前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >利用strcpy攻击服务器

利用strcpy攻击服务器

作者头像
gaigai
发布2021-03-24 11:15:06
1.8K0
发布2021-03-24 11:15:06
举报
文章被收录于专栏:Windows开发Windows开发

char* strcpy(char * destination, const char * source)

strcpy函数将source所指向的字符串拷贝到destination,拷贝内容是从source所指向的地址开始,直到遇到\0为止。这就意味着,拷贝的内容有可能超过destination的空间。如果destination是通过new在堆中分配内存,将导致堆破坏。如果destination是局部变量,将导致栈破坏。不管是堆破坏还是栈破坏,最终大概率将导致程序异常崩溃,这种情况有可能会在程序运行一段时间后才出现崩溃,所以排查相当困难。强烈建议使用微软提供的安全版本strcpy_s,指定destination的空间长度。sprintf也存在同样的问题。

由于strcpy会导致栈破坏,如果source是来源于用户输入的数据,用户就可以构造特殊的数据让服务端执行,进行恶意攻击,攻击的原理是:程序在调用函数时,call指令会将下一条指令先存入栈,然后执行函数,函数执行完后,ret指令会取出之前call指令存放的下一条指令,继续执行,于是通过栈破坏,替换下一条指令为自己构造的恶意代码(比如调起cmd,执行文件删除)。

接下来,我将演示如何通过strcpy的漏洞代码,改变程序的执行流程。先看一段简单的服务端代码。

代码语言:javascript
复制
void ProcessData(const char data[])
{
    char buf[4];
    strcpy(buf, data);    
}

int main()
{    
    const char* data = GetDataFromUserInput();
    ProcessData(data);
    return 0;
}

此代码片段,演示程序通过GetDataFromUserInput()函数从用户输入获得数据(可以是通过网络从前端发送过来),然后处理数据ProcessData(),该函数通过strcpy拷贝data到局部变量buf。如前面所说,strcpy调用前未对data长度进行校验,可能会导致栈破坏。

程序调用ProcessData函数返回后,要继续执行这行代码return 0; 所以在进入ProcessData()函数前需要先将return 0; 的指令存在栈上(这是由汇编指令call所做的)。进入ProcessData()后,buf是局部变量占4个字节也是在栈上,通过计算return 0的指令所在的栈上地址与buf的地址之间的偏移后,在data对应的位置填入攻击函数的地址,等strcpy执行完,下一条指令return 0;就会变成攻击函数的地址,完成拦截。

return 0的指令所在的栈上地址与buf的地址之间的偏移,怎么计算呢?对汇编代码熟悉的牛人,一眼就能计算出来。接下来,我演示下如何通过汇编代码,计算他们之间的偏移值。本人使用Visual Studio 2013调试。

这是main函数的汇编代码,我在调用ProcessData()这行代码设置断点,如下图所示。

此时,esp寄存器(指向栈顶地址)通过监视器知道是0x0034fa30

mov eax, dword ptr [data] 将data地址类型const char* 转成dword ptr,存在寄存器eax

push eax 将eax存在栈上,也就是将data地址存在栈上(函数调用前都需要将参数入栈,data是ProcessData的参数,所以得入栈),此时栈顶0x0034fa30的值是data的地址,esp变成0x0034fa2c(栈地址是从高到低,所以esp要减4)

call ProcessData 调用ProcessData,可以按F11调试进入ProcessData,call下一条指令地址是00E51725 add esp, 4

按F11进入ProcessData(),如下是ProcessData()的汇编代码。

此时通过监视器看到esp地址是0x0034fa28,比上面push eax指令执行后esp值0x0034fa2c又少了4个字节,就是因为call指令将返回指令00E51725 add esp, 4的地址00E51725存入栈上。通过内存查看器可以证实。

从上面调试可知道,函数调用返回地址存在栈0x0034fa28上。

继续调试,断点设置在call dword ptr ds:[0E54100h]这行(也就是strcpy(buf,data)这行代码),按F5执行。鼠标移到buf变量上,知道buf地址是0x0034fa20。

由此可知函数调用返回地址在栈上的位置与buf变量的位置偏移值是8(0x0034fa28 - 0x0034fa20)。于是就可以构造用户数据,完整代码如下。

代码语言:javascript
复制
#include <iostream>
#include<windows.h>
using namespace std;

void Attack()
{
    while (true)
    {
        cout << "You have been attacked" << endl;
        Sleep(1000);
    }
}

void ProcessData(const char data[])
{
    char buf[4];
    strcpy(buf, data);    
}

const char* GetDataFromUserInput()
{
    static char data[13];
    int attackAddress = (int)&Attack;
    memset(data, 'a', sizeof(data));
    memcpy(data + 8, &attackAddress, 4);
    data[12] = 0;
    return data;
}

int main()
{    
    const char* data = GetDataFromUserInput();
    ProcessData(data);
    return 0;
}

GetDataFromUserInput()里面构造一个13字节的数据,内存初始化为字母a,最后一个字节设置为0(要让strcpy拷贝这13个字节,只能最后一个字节为0)。然后在偏移值8位置保存攻击函数的地址&Attack。

本演示是在Visual Studio 2013,Release配置下,关闭“启用内部函数”设置(如果不关闭,strcpy函数的汇编指令会直接内联到ProcessData()内,为了简化汇编指令,特意关闭该设置),运行结果如下图所示。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-03-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Windows开发 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库一体机 TData
数据库一体机 TData 是融合了高性能计算、热插拔闪存、Infiniband 网络、RDMA 远程直接存取数据的数据库解决方案,为用户提供高可用、易扩展、高性能的数据库服务,适用于 OLAP、 OLTP 以及混合负载等各种应用场景下的极限性能需求,支持 Oracle、SQL Server、MySQL 和 PostgreSQL 等各种主流数据库。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档