[工控安全][原创]某工控软件由wcslen()函数引起的内存访问越界漏洞(一)
mailto: wangkai0351@gmail.com
【未经同意禁止转载】
某工控软件由wcslen()函数引起的内存访问越界漏洞(一)
wcslen()函数原型
参考微软网站https://docs.microsoft.com/zh-cn/cpp/c-runtime-library/reference/strlen-wcslen-mbslen-mbslen-l-mbstrlen-mbstrlen-l?view=vs-2019
wcslen()
函数C runtime library中用于计算款字符串长度的函数,定义在<string.h> 或 <wchar.h>。
其在VS2019的标准库中的原型如下
size_t wcslen(
const wchar_t *str
);
参数
输入参数:
str:以为 null 结尾的字符串。
输出参数:
返回str中的字符数,不包括为 null 终端。
微软已经提示:
安全说明这些函数会引发由缓冲区溢出问题带来的潜在威胁。 缓冲区溢出问题是常见的系统攻击方法,使权限的提升不能确保。 有关详细信息,请参阅 避免缓冲区溢出。
某软件dll中的wcslen()函数
某软件的dll中包含的wcslen()函数经过IDA Pro v7.0(Version 7.0.170914 macOS x86_64 (32-bit address size))反编译后得到的伪代码如下
size_t __cdecl wcslen(const wchar_t *a1)
{
const wchar_t *v1; // eax
wchar_t v2; // cx
v1 = a1;
do
{
v2 = *v1;
++v1;
}
while ( v2 );
return v1 - a1 - 1;
}
wcslen()函数缓冲区访问越界
参考以上微软网站,我们编写一个wcslen()
函数正常调用示例程序
#include <stdlib.h>
int main()
{
wchar_t* wstr1 = L"Count.";
wprintf(L"Length of '%s' : %d\n", wstr1, wcslen(wstr1) );
}
根据https://book.2cto.com/201312/38514.html网站所说,wcslen()
函数产生缓冲区溢出是由计算机底层对字符串编码的弱点带来的。
1)如果字符数组不是正确地以空字符结尾的,strlen()
函数可能会返回一个错误的超大的数值,使用它时,就可能会导致漏洞。
2)如果传入一个非以空字符结尾的字符串,strlen()
函数可以越过动态分配的数组的边界读取,并导致程序停止运行。
第二点最有可能带来信息安全隐患,触发漏洞的条件是构造一块以非空字符结尾的连续字符串空间。
我们把反汇编的wcslen()
代入到示例程序中,并构造shellcode,如下
#include <stdlib.h>
size_t wcslen_(const wchar_t *a1)
{
const wchar_t *v1; // eax
wchar_t v2; // cx
v1 = a1;
do
{
v2 = *v1;
printf("v2 = %d\n", v2);
++v1;
}
while ( v2 );
return v1 - a1 - 1;
}
int main()
{
char* str1 = "Count.";
wchar_t* wstr1 = L"Count.";
wchar_t wstr2[6];
wstr2[0] = L'C';
wstr2[1] = L'o';
wstr2[2] = L'u';
wstr2[3] = L'n';
wstr2[4] = L't';
wstr2[5] = L'.';
wchar_t *wstr3_p = (&wstr2[5]+1);
*wstr3_p = L'.';
wprintf(L"Length of '%s' : %d\n", wstr1, wcslen_(wstr2) );
}
运行结果如下(Macos+Apple LLVM version 10.0.1 (clang-1001.0.46.4))
v2 = 67
v2 = 111
v2 = 117
v2 = 110
v2 = 116
v2 = 46
v2 = 46
v2 = 642464122
v2 = -504575440
v2 = 32766
v2 = 1788097493
v2 = 32767
v2 = 0
Length of 'C' : 12
[1] 84188 abort ./a.out
可以看出已经越界读取了。
如果我们进一步构造再长一点的字符串空间
wchar_t *wstr3_p = (&wstr2[5]+1);
wstr3_p[0] = L'.';
wstr3_p[1] = L'.';
wstr3_p[2] = L'.';
wstr3_p[300] = L'.';
运行结果如下
[1] 84740 segmentation fault ./a.out
已经发生了段错误。
某软件dll中调用wcslen()的函数
某工控软件的dll中,_cxxxx()
函数调用了wcslen()
,经过IDA Pro v7.0反编译得到
int __cdecl _cxxxx(wchar_t *a1)
{
int result; // eax
size_t v2; // eax
__int16 v3; // ax
signed int v4; // [esp+10h] [ebp-20h]
size_t v5; // [esp+14h] [ebp-1Ch]
v4 = 0;
if ( a1 != 0 )
{
v5 = wcslen(a1); //调用wsclen()函数处
result = v4;
}
else
{
/*
错误处理
*/
result = -1;
}
return result;
}
下面就是寻找哪个函数或者动作调用了这个_cxxxx()
函数,关键是我们如何自行构造_cxxxx()
函数的输入参数。
posted on 2019-06-13 15:21 大单GreatDane 阅读(672) 评论(0) 编辑 收藏 举报