目录
写在开头
近期又开始回头开始学pwn了,看了b站国资社畜大佬的视频,在大佬讲解的基础上做个总结,加入了我的一些思考。学pwn主要是要了解内存布局和程序的执行过程,感觉学习路线确实比较陡峭,今后我也会不定期更新这个系列。
本文主要以对一个程序的调试过程为例,介绍gdb调试器的常见命令,并直观的展示所谓“溢出”覆盖的效果以及大小端序的问题。涉及的知识点包括:pwn题目环境的部署、gdb调试的常见命令、大小端序的影响、简单解pwn题目脚本的编写。特别说明,由于篇幅有限,本文不会过多介绍汇编指令以及程序运行时函数调用栈的变化过程。这些内容可能会在后面的博客中再做介绍,本文的重点是使用gdb对程序进行调试。本文需要的工具主要有gdb和pwntools,读者如果想跟着复现,只要有gdb和pwntools即可,安装过程详见:
pwn入门(1):kali配置相关环境(pwntools+gdb+peda)_gdb插件 peda-优快云博客
备注:文末有我总结的gdb常见指令,有需要的读者可以直接看文末。
一、pwn题目环境的部署
这一部分属于调试过程的前置,想在本地部署一个pwn环境,用socat开启一个本地端口运行pwn题目(下文会细说)。当然读者如果仅仅了解gdb的话也可以不用考虑这么多,直接用p = process(./文件)即可。建议使用ubuntu或kali这样的系统部署环境、调试程序。
首先我们要构建一个存在“溢出”漏洞的二进制文件。这里我们就用国资社畜大佬给出的question.c文件即可,其内容如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
char sh[]="/bin/sh";
int init_func(){
setvbuf(stdin,0,2,0);
setvbuf(stdout,0,2,0);
setvbuf(stderr,0,2,0);
return 0;
}
int func(char *cmd){
system(sh);
return 0;
}
int main(){
init_func();
volatile int (*fp)();
fp=0;
int a;
puts("input:");
gets(&a); //gets没有对输入字符的长度做限制,存在溢出
if(fp){
fp();
}
return 0;
}
然后用gcc把这个文件编译一下,生成存在漏洞的二进制文件,注意编译的过程要关闭pie保护,命令如下:
gcc question.c -no-pie -o question1

此处简要说明一下PIE保护(不是本文重点)。
1.PIE保护是编译时默认开启的。如果想关闭pie保护,需要手动添加参数-no-pie
2.PIE (position-independent executable) 是一种生成地址无关可执行程序的技术。是一种保护机制,如果程序开启了PIE保护的话,那么在每次加载程序时都会改变加载的基地址。当然这种机制不利于我们本地调试程序,所以在这里就关闭了。
接下来为了增强仪式感,我们可以在当前目录新建一个文件flag,拿到这个flag相当于解题成功。

然后用socat开启8888端口部署这个题目question1,当然你也可以使用任何未被占用的其他端口:
socat tcp-l:8888,fork exec:./question1,reuseaddr

然后另起一个终端(ctrl+shift+t),试一试能不能用nc连接这个题目,如下图连接成功:

随便输入一段字符串看看效果,好像没啥问题:

二、解题思路(不是重点)
如果从解题的角度思考,我们只能拿到一个二进制文件,是看不到源代码的。当然可以放到ida中分析,也可以用反汇编工具查看伪源代码,然后再慢慢分析。不过由于本文的重点是用gdb调试程序,因此这里就直接从上面的源代码简要分析触发漏洞的位置:
1.溢出点:代码中存在危险函数gets()。gets函数用于获取用户的输入,且不会对输入的字符数量做限制,因此有可能会溢出覆盖其他内存。
2.后门函数:存在后门函数func,这个函数可以获取shell,我们要想办法让这个函数执行。
3.函数指针fp,原始的

本文通过实例讲解了如何使用GDB调试器对存在溢出漏洞的程序进行调试,涉及pwn环境部署、gdb命令应用、溢出覆盖、大小端序影响及Python脚本编写,旨在帮助理解内存布局和程序执行过程。
最低0.47元/天 解锁文章
2200

被折叠的 条评论
为什么被折叠?



