浅析php反序列化字符串逃逸
前言:
php反序列化字符串逃逸之前沒有詳細的學習過,所以遇到題目看的有點懵,這次好好學習一下。
反序列化的特點
首先要了解一下反序列化的一些特點:
超出的部分并不會被反序列化成功,如下圖:
這說明反序列化的過程是有一定識別范圍的,在這個范圍之外的字符都會被忽略,不影響反序列化的正常進行。而且可以看到反序列化字符串都是以";}結束的,那如果把";}添入到需要反序列化的字符串中(除了結尾處),就能讓反序列化提前閉合結束,后面的內容就相應的丟棄了。
2. 長度不對應的時候會報錯
在反序列化的時候php會根據s所指定的字符長度去讀取后邊的字符。如果指定的長度錯誤則反序列化就會失敗
3. 可以反序列化類中不存在的元素
<?php $str='O:1:"A":3:{s:4:"name";s:3:"shy";s:4:"pass";s:6:"123456";s:5:"pass2";s:6:"123456";}'; var_dump(unserialize($str));
這些特點一定要清楚,否則在做題時可能就因為這些基礎知識而做出不來。
字符串逃逸
0x0:特點
這類CTF題目的本質是因為改變序列化字符串的長度,從而導致反序列化漏洞。
具體的話大致都是因為php序列化后的字符串經過了替換或者修改,導致字符串長度發生變化。而且總是先進行序列化,再進行替換修改操作。
0x01:過濾后字符變多
實驗代碼:
#參考字節脈搏實驗室 <?php function lemon($string){$lemon = '/p/i';return preg_replace($lemon,'ww',$string); } $username = $_GET['a']; $age = '20'; $user = array($username,$age); var_dump(serialize($user)); echo "<br>";$r = lemon(serialize($user)); var_dump($r); var_dump(unserialize($r)); ?>正常輸入的話
因為我們輸入的是apple,含有兩個p,所以會被替換成四個w,但是發現長度并沒有變化,因此根據反序列化的特點,指定的長度錯誤則反序列化就會失敗。
但是正是因為存在這個過濾,我們便可以去修改age的值,首先來看一下,原來序列化后";i:1;s:2:"20";}長度為16,我們已經知道了當輸入一個p會替換成ww,所以如果輸入16個p,那么會生成32個的w,所以如果我們輸入16個p再加上構造的相同位數的";i:1;s:2:"30";},恰好是32位,即
32 pppppppppppppppp";i:1;s:2:"30";} 經過替換后 32 wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww所以非常明顯了,在過濾后的序列化時會被32個w全部填充,從而使構造的代碼 ";i:1;s:2:"30";} 成功逃逸,修改了age的值,而原來的那";i:1;s:2:"20";}則被忽略了因為反序列化字符串都是以";}結束的,我們傳入的";i:1;s:2:"30";}已經在前面成功閉合了
0x02:過濾后字符變少
搭建一個簡單的實驗環境代碼如下:
#參考Mr. Anonymous師傅的代碼學習 <?php function str_rep($string){return preg_replace( '/lemon|shy/','', $string); }$test['name'] = $_GET['name']; $test['sign'] = $_GET['sign']; $test['number'] = '2020'; $temp = str_rep(serialize($test)); printf($temp); $fake = unserialize($temp); echo '<br>'; print("name:".$fake['name'].'<br>'); print("sign:".$fake['sign'].'<br>'); print("number:".$fake['number'].'<br>'); ?>如果正常輸入的話,回顯出的結果如下:
已經知道number的值是固定的2020
如果想要修改這個值,就要在sign中加入";s:6:"number";s:4:"2000";},其長度為27,仔細觀察便可以發現是利用反序列化的第一個特點底層代碼是以;作為字段的分隔,以}作為結尾,想要將之前的number擋在序列化之外,從而可以反序列化自己構造的,但直接輸入發現是不行的,并沒有將我們輸入的給反序列化了
在實驗代碼中有替換功能,當遇到lemon 或 shy會自動替換為空,也這里用shy做為name的輸入,故意輸入敏感字符,替換為空之后來實現字符逃逸,三個字符變成零個字符,吃掉了三個字符,輸入8個shy,也就是騰出了24個字符的空間,利用這個空間來進行構造,由于";s:4:"sign";s:54:"hello成了name的內容,所以還要在后面加個";s:4:"sign";s:4:"eval作為sign序列化的內容。
這個構造其實也很簡單,因為經過測試發現,";s:4:"sign";s:這個長度其實是不變的,變的是我們在參數sign輸入的參數,這里假設輸入9個shy,那么吃掉了27個字符,對應的就需要添加27個字符,目前";s:4:"sign";s:這個長度為15,所以還差12個,因為整個payload肯定是不超過100個字符的,所以加上后面的長度,也就是";s:4:"sign";s:xx:",這個長度為19,因此我們要輸入的字符只需8個即可
payload:
http://127.0.0.1/1.php ?name=shyshyshyshyshyshyshyshyshy &sign=hello123";s:4:"sign";s:4:"eval";s:6:"number";s:4:"2000";}
這樣便可以將number的值給更改了,原理的話就是這樣,做題時還要多動手進行測試。
總結
以上是生活随笔為你收集整理的浅析php反序列化字符串逃逸的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第四届“强网杯”全国网络安全挑战赛_部分
- 下一篇: CISCN2020初赛_Web