Websec level 30
前言
昨天在易霖博搞的網路安全與執法競賽看到的一道web題,實際上就是用兩個原題湊起來的。。
不過後面的一關沒見過這裡簡單記錄一下
第一關
打開是個登錄介面,和BJDCTF的簡單注入一模一樣,連密碼都一樣。。
第二關
登錄後得到
即
<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
include 'flag.php'; //defines $flag
class B {
function __destruct() {//當一個對象銷毀時被調用或者腳本結束時調用
global $flag;
echo $flag;
}
}
if (isset($_POST['payload'])) {
ob_start();//打開輸出緩衝區,所有的輸出資訊不在直接發送到瀏覽器,而是保存在輸出緩衝區裡面,可選得回調函數用於處理輸出結果資訊。
$a = unserialize($_POST['payload']);
if ($a === False) {
ob_end_clean();//清空(擦除)緩衝區並關閉輸出緩衝
}
throw new Exception('Something tragic happened');//拋出一個錯誤
}
?>
還是原題 Websec level 30
payload:
a:2:{i:0;O:1:"B":0:{}i:0;i:1;}
詳細可以參考:
[//kangwoosun.github.io/webhacking/2020/03/28/Websec/]
[//www.evonide.com/breaking-phps-garbage-collection-and-unserialize/#comments]
[//www.evonide.com/fuzzing-unserialize/]
以下是個人的淺薄理解
如果傳入一個序列化的數組,並且這個數組中存在兩個或多個key相等的變數,那麼反序列化的時侯將刪除首先輸入的變數。因此,如果將類 B 對象作為value冗餘,則將調用析構函數,而不會導致反序列化錯誤,即先解析 O:1:”B”:0:{} 生成一個對象,然後在向後解析又遇到 i:0 於是將前一個 i:0 的值改為1,就相當於消滅了之前生成的對象於是觸發__destruct函數,之後也是冗餘的關係使得反序列化的結果返回的是 array(0=>1) ,不為False,於是不會進入到ob_end_clean(),最後輸出flag
這題如果直接傳入
O:1:"B":0:{}
是不會輸出flag,因為雖然這樣反序列化得到的a是一個對象不等於False,但是之後會通過throw new 拋出一個錯誤,它這裡的拋出錯誤就類似於下了一個斷點一樣,使得腳本程式的運行停止在了這裡,並沒有結束,所以反序列化後的B對象仍然存在,不會觸發__destruct