栈溢出基础

栈溢出


stack frame pointer:上一个栈帧(父函数)的栈底的值。

函数调用栈是指程序运行时一段连续的区域,用来保存函数运行时的状态信息,包括函数参数与局部变量等。

发生函数调用时,调用函数(caller)的状态被保存在栈内,被调用函数(callee)的状态被压入调用栈的栈顶。函数调用结束时,栈顶的函数(callee)状态被弹出,栈顶恢复到调用函数(caller)的状态。

函数调用栈在内存中从高地址到低地址生长,所以栈顶对应的内存地址在压栈时变小,退栈时变大。

栈帧中子函数所用的形参保存在父函数栈帧中arguments。

esp指向当前所调用函数所属的栈帧。

将被调用函数的参数压入栈内时是倒序压入。

栈顶永远指向当前正在执行的指令所属的函数对应的栈帧。

子函数完成指定功能后要释放掉所调用的局部变量,只需要将esp推到ebp,就可以释放掉;然后ebp所指向的地址中保存着父函数栈底的地址会传送至ebp寄存器内,ebp就会回到父函数栈底的位置;esp自动减去一个字长并指向return address;

字长:32位字长就是32bit,64位字长就是64bit。

pop,push的工作单位为一字长。

x86架构用eax存放返回值。

汇编指令中call指令自带保存返回地址的操作。

leave=mov(将esp移到ebp位置)+pop(ebp返回到父函数的栈底位置),若esp已经指向ebp,则可以直接pop。

gdb升级:peda gef pwndbg

python3 脚本:运行此脚本

cat 文件名 :捕捉此文件

ida :shift+fn+f12 :将程序转换为字符串形式

寻找main函数

1.首先执行该文件

2.其次 shift+fn+f12将程序中可转为ASCLL码的内容转换为字符串,找到该字符串

3.双击进入后

4.左下角位置的DATA中存放了 引用这段数据的代码位置,双击进入

5.找到了此数据在程序中的位置,这是程序员自己写的,大概率是我们所要找的位置。f5反编译一下就可以找到main函数

下载pwntools(python2和python2):pip 2 install pwntools(pip 3 install pwntools)

导入python3: python3

攻击:1. from pwn import *(导入pwntools所有模块)

建议先用本地连接攻打获取shell然后在转换为远程连接

2.打开远程或本地连接

(1) io(自定义名字) = process("./本地程序") 打开本地连接

(2) io =remote ("IP",本地端口) 打开远程连接 IP要以字符串的的形式输入,本地端口应提前打开

此时io变成进程管道

3.接受内容

(1)io.recvline() (显示收到的内容(一行))

(2)io.recv () (所有)

4.编写payload

5.发送payload

(1)io.send(b"字符串") 加b是为了将字符串以一字节形式发送,

(2)io.send(p64(64位的数字)) ()里应为字节流 p64()将数据打包为64位宽度的字节流数据,p32()即为32位

(3)io.sendline () 一直读取,直到遇到换行符或字符串结束符。而sendline会自动在输入的数据末尾加上换行符 等效于io.send(b" \n")

6.io.interactive() 进入交互模式

checksec : 查看有哪些保护措施

gdb 调试 :b 后跟要打断点的位置 (可以b *地址,也可以b 一个函数,比如b main)

r命令 :运行程序

n命令逐个执行语句

s命令 进入函数

stack 24 :查看24项的stack

ret2text

1.file 文件 查看多少位的ELF文件,再用IDA打开

nc IP 端口 :访问这个端口

2.用python3 recv一下

除了刚刚收到的字符串,这里还多出了一串字符串。末尾的\r为特殊的文本控制字符,\r会清空前面的内容,也就是所多出来的内容。此段数据发了过来,但是由于\r的存在使得此数据无法显示出来。

3.用echo函数解码此数据 解码: echo 内容 | base64 -d , -d指decode , | 为管道符

篡改栈帧上的返回地址为程序中已有的后门函数

phone_book(找假的flag)

1.file 文件 查看多少位的ELF文件,再用IDA打开

2.(1)第一种方法 查看程序执行流,因为假的flag(fleg)只有可能是出题人写的。首先f5反编译为c语言找到main函数,其次在其中找到非库函数即出题人自己编写的函数,在此题目中record即为所找函数

双击进入此函数,即可找到fleg

(2)第二中方法 shift+fn+f12 ,若fleg是以完整的方式存放即可使用此方法

pwn题目的基本步骤

ret2text

1.首先checksec 文件名 查看文件的保护措施

2.用IDA打开文件 ,f5反编译为c语言,寻找存在漏洞的函数

3.进入此函数,发现gets函数存在漏洞

4.对文件进行动态调试 gdb 文件名,gdb内容较多,建议用全屏然后缩小字体

5.打断点 b main 在main函数中打断点(也可以b *地址)

run(简写r)

REGISTERS为寄存器,DISASM即所执行指令周围的指令进行反汇编的结果

STACK 栈,BACKTRACE 函数调用栈的关系

6.next(简写为n),直到遇到漏洞函数

7.s 进入此函数

n 步过,执行此函数

8.stack 24 看长度为24项stack栈里的内容

通过输入字符串覆盖掉eax与ebp之间的区域,使其执行完vulnerable后无法return到main函数,而到get_shell函数。quit停止动态调试

9.找到后门函数

system一个字符串与在shell中执行此字符串是一个作用,就可以控制此对方服务器

10.eap与ebp之间有16个字节,ebp也需要4个字节覆盖掉,(如果是64位的架构rbp则需要8个字节来覆盖)要想将所想返回的地址覆盖程序中原有的地址就要输入20个字节的恶意数据加上所需要的地址(返回地址)。

找到get_shell的返回地址

编写脚本准备攻击

io.interactive()即进入交互模式,此时已经获得shell,获取了本机的控制权

再将本地连接转换为远程连接

ctrl+d 退出python交互环境

ret2text题目一般程序中有后门函数即有systerm

ret2shellcode题目篡改栈帧上的返回地址为攻击着手动传入的shellcode所在的缓冲区地址,由于the NX bits 保护措施的开启,栈缓冲区不可执行,故当下的常用手段变为向bss缓冲区写入shellcode或向堆缓冲区写入shellcode并使用mprotect赋予其可执行权限

ASLR保护措施(地址随机化)

ASLR关闭时多次查看栈的地址,地址不变,没有被随机化

ASLR打开时多次查看栈的地址,地址发生改变

PIE保护措施 打开后bss,data,text也会地址随机化

canary保护措施

在形成一个新的栈帧的时候,会在previous的低地址出形成一个canary,里面是一个随机值,因此如果要进行栈溢出,就一定会遇到canary并覆盖它,销毁栈帧的时候会检测canary是否发生了变化,如果发生了变化,程序会直接崩溃退出,并弹出stack check file,即栈检查失败,程序强制退出。

获取shellcode:

pwntools中有此工具,在python3中

输入shellcraft.sh()即可获取关于shell的一个shellcode,这样输出的并不美观可以输入print(shellcraft.sh())即可将换行符隐藏 为汇编代码

pwntools中 有工具(asm)可以将汇编代码转换为机器码如下

默认把二进制串当成可显示字符转化为ASCLL码,如果不可显示即原样输出

此命令默认输出的都是攻击32位的shellcode,如果是攻击64位需print(shellcraft.amd64.sh())。由于默认的攻击环境为32位,所以在脚本中应添加 context.arch = "amd64"

pwndbg中vmmap显示虚拟内存的空间分布

ret2shellcode(将shellcode写入bss段中)

1.IDA打开

找到可以函数gets

输入的数据存入局部变量s中,s的前0x64u个字节复制到buf2中,推测出buf2为未初始化的全局变量,其存放在bss段,所以可以将shellcode写入bss段。可以将shellcode写入s,然后将buf2的地址当作return 的地址写入攻击脚本中。

2.gdb动态调试

需要112个字节的恶意数据与目标地址

3.编写脚本

payload = asm(shellcraft.sh().ljust(112,b'A')) 作用为向得到的shellcode后加A直到字节长度为112个字节,asm是将汇编代码转换位机器码

本地连接打通后转换为远程连接

ret2shellcode : 106.54.129.202 10003

进入交互模式后,cat flag.txt 获取其flag

ret2shellcode(将shellcode写入栈中)

首先sudo su 变为超级用户,然后echo 0 > /proc/sys/kernel/randomize_va_space 将ASLR保护措施关闭

gcc -fno-stack-protector -z execstack -no-pie -g -o ret2stack ret2stack.c 其写入脚本之中

        -fno-stack-protector 关闭canary保护措施

        -z execstack 打开栈的可执行权限

        -no-pie 关闭PIE保护措施

        -g 将调制信息带上,可以看到C语言代码,前提是 ret2stack.c 存在

        -o 输出目标文件的名称

写脚本的时候表头应写上 #!/bin/sh

写完之后给脚本可执行权限

执行完后就得到一个关闭有关栈保护措施的ret2stack

虚拟机中ctrl+c是强行终止所在执行的进程,ctrl+shift+c是复制粘贴

对ret2stack进行gdb调试

需要112个字节覆盖掉空间以及8个字节的数据覆盖rbp的内容,末尾再加上所要求返回到的返回地址

因为要将shellcode写入栈中,所以返回地址应为栈的地址 即 0x7fffffffe060

进入python3编写脚本

攻击失败,原因为gdb里看到的地址很可能是错误的

在ret2stack.c原代码中使用print函数输出栈的地址 为0x7fffffffe0e0 与gdb动态调试得出的不同

重新编写脚本 ret2stack.c

执行此脚本时无法执行,原因是没有消除缓冲区,print函数输出的数据会先到缓冲区里,由于缓冲区没有满所以不会输出,执行时就会卡在io.recv()

重新整理ret2stack.c

结果发现gdb中与程序的print 函数输出 的rsp地址是不同的。原因是gdb在调试此程序时建立了一个新的沙盒空间,gdb中默认是关闭了ALSR的(即使物理机中是关闭了ASLR的),与宿主机的ALSR是无关的,而程序中的。gdb调试时地址偏移量是不会错的,但是地址是不一定一模一样的。环境的不同也可能会影响pwn的过程,比如有的题目远程连接可以打通,本地连接却可以打通。

由于此程序是自己编写的,没有考虑额外的因素所以导致出现了问题。

第一个函数的栈帧是main函数的,在main函数之前是没有栈帧的

  • 11
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值