您所在的位置: 首页>>开发>>.Net>>vc++.net>>

缓冲区溢出还是问题吗?C++/CLI安全编码(2)

http://developer.51cto.com  2007-01-22 17:49  谢启东编译  天极开发  我要评论(0)
  • 摘要:在本文中,将主要讲解在以最小代价把现有老系统移植到使用CLR的新环境中来时,所要面临的问题,目的是为了确定这些程序是否仍然易受折磨C/C++程序多年的缓冲区溢出的影响。
  • 标签:缓冲区  溢出  C++  CLI  安全  编码

倘若输入了更多的字符,以致密码字符数组存储空间无法容纳,一个攻击者就可以溢出此缓冲区,并以shellcode(可为任意的代码)地址覆盖掉返回地址。出于演示的目的,在此假定shellcode已被注入,且定位于0x00408130,为执行此代码,攻击者只需把下列字符串作为密码输入:

Enter 8 character password:
123456789012345678900|@

这个输入的字符串被复制到密码字符数组,溢出了此缓冲区并覆盖相应的内存包括返回地址。字符串中的三个字符0|@覆盖了返回地址的前三个字节,而返回地址的最后一个字节被一个由gets()函数产生的null结尾字符所覆盖。注意,如果这个null不在最后一个字节上,那么不可能复制整个字符串,因为gets()函数会把这个null字符解释为字符串的结尾。那为什么要以上这三个字符呢?因为,这些字符的十六进制形式提供了内存中表示地址所需的值,"0"的ASCII十六进制码为0x30,"|"为0x81,而"@"为0x40。如果把这三个字符以顺序{ '0', '|', '@' }连接起来,就可将shellcode(0x00408130)地址的小尾字节序表示形式写入到内存中。最后一个null字节 由字符串的null字符提供。(见代码段2。)

代码段2:

002DF3D4 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 1234567890123456
002DF3E4 37 38 39 30 30 81 40 00 01 00 00 00 79 3a 4e 00 78900.@.....y:N.
002DF3F4 a8 2b 2f 00 38 f4 2d 00 da c4 fc 79 78 f4 2d 00 .+/.8.-....yx.-.
002DF404 48 f4 2d 00 60 13 40 00 01 00 00 00 50 53 54 00 H.-.`.@.....PST.

当checkpassword()函数返回时,控制权就传到shellcode而不是main()函数中的原始返回地址上。

为了简化这个攻击过程,在此,关闭了缓冲区安全检查选项/GS。如果这个选项没有关闭,编译器将会在声明在堆栈上的任何数组(缓冲区)之后插入一个"密探"--实际上为一个Cookie,见图1。

 
图1:基于"密探"的缓冲区溢出保护

如果要使用那些不受控制的字符串复制操作,如gets()或strcpy(),来覆盖掉由"密探"保护的返回地址(EIP)、基指针(EBP)、或堆栈上的其他值,一个攻击者将首先要覆盖掉这个"密探"。如果"密探"被修改了,当函数返回时,将会产生一个错误,导致攻击失败--除非是为了进行"拒绝服务攻击"。通过暴力枚举猜测这个值,或其他方法,还是有可能挫败这个"密探"的,但是,进行一次成功攻击的难度增加了。

打开/GS选项不会让程序对缓冲区溢出漏洞彻底免疫,堆栈中的缓冲区溢出仍会使程序崩溃,攻击者利用基于堆栈的溢出来执行任意代码的可能性,即使在打开/GS的情况下仍然存在。更重要的是,/GS选项不会检测堆中或数据段中的缓冲区溢出。

为举例说明,例2使用Win32 GUI重写了前面那个示例程序,这个程序提供一个带有一些简单选项的菜单栏--File菜单下有两个菜单项:"Login"和"Exit"。Login会用一个对话框来提示用户输入密码,一旦输入了密码,在用户点击"OK"按钮之后,将把输入的密码与之前记录的密码相比较。

例2:

1. #include "stdafx.h"
2. #include "TestItDan.h"
3. #include <stdlib.h>
4. #include <stdio.h>
5. #include <windows.h>
6. #define MAX_LOADSTRING 100
7. struct user {
8.  wchar_t *name;
9.  size_t len;
10. int uid;
11. };
13. HINSTANCE hInst;
14. TCHAR szTitle[MAX_LOADSTRING];
15. TCHAR szWindowClass[MAX_LOADSTRING];
16. TCHAR lpszUserName[16] = L"guest";
17. TCHAR lpszPassword[16] = L"0123456789abcde";
18. struct user *userP = (struct user *)0xcdcdcdcdcdcdcdcd;
19. size_t userNameLen = 16;
20. size_t userPasswordLen = 0xffffffff;
25. int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow) {
26.  UNREFERENCED_PARAMETER(hPrevInstance);
27.  UNREFERENCED_PARAMETER(lpCmdLine);
28.  MSG msg;
29.  HACCEL hAccelTable;
30.  LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
31.  LoadString(hInstance, IDC_TESTITDAN, szWindowClass, MAX_LOADSTRING);
32.  MyRegisterClass(hInstance);
33.  userP = (struct user *)malloc(sizeof(user));
34.  if (!InitInstance (hInstance, nCmdShow)) {
35. return FALSE;
36.  }
37.  hAccelTable =LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TESTITDAN));
38.  while (GetMessage(&msg, NULL, 0, 0)) {
39. if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
40.  TranslateMessage(&msg);
41.  DispatchMessage(&msg);
42. }
43.  }
44.  return (int) msg.wParam;
45. }
109. INT_PTR CALLBACK GetPassword(HWND hDlg, UINT message, WPARAM wParam,

LPARAM lParam) {
110.  TCHAR lpszGuestPassword[16] = L"NCC-1701";
111.  UNREFERENCED_PARAMETER(lParam);
112.  switch (message) {
113. case WM_INITDIALOG:
114.  return (INT_PTR)TRUE;
115. case WM_COMMAND:
116.  if (LOWORD(wParam) == IDOK) {
117. EndDialog(hDlg, LOWORD(wParam));
118. SendDlgItemMessage(hDlg,
119. IDC_EDIT1,
120. EM_GETLINE,
121. (WPARAM) 0, // line 0
122. (LPARAM) lpszPassword
123. );
124. userP->len = userNameLen;
125. if (wcscmp(lpszPassword, lpszGuestPassword) == 0) {
126.  return true;
127. }
128. else {
129.  MessageBox(hDlg,
130. (LPCWSTR)L"Invalid Password",
131. (LPCWSTR)L"Login Failed",
132. MB_OK
133.  );
134. }
135. return (INT_PTR)TRUE;
136.  }
137.  break;
138. }
139. return (INT_PTR)FALSE;
140.  }


共3页: 上一页 [1] 2 [3] 下一页
【内容导航】
如何有效提升企业安全审计应用水平
Web安全云时代
NAC安全访问控制
微软Forefront企业安全解决方案
VPN安全技术与应用
 
 验证码: (点击刷新验证码)   匿名发表
  • Visual C++ 完全自学宝典

  • 作者:强锋科技,朱洪波
  • Visual C++ 6.0是微软公司为程序人员提供的Visual Studio 6.0工具套件中的重要组成部分。本书由浅入深地介绍使用Visual C++ 6.0..
Copyright©2005-2008 51CTO.COM 版权所有