科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网安全频道破坏力依然不可小视 缓冲区溢出攻防

破坏力依然不可小视 缓冲区溢出攻防

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

 很久以来,在人们心目中,“黑客”和病毒作者的身上总是笼罩着一层神秘的光环,他们被各种媒体描述成技术高手甚至技术天才,以至于有些人为了证明自己的“天才”身份而走上歧途,甚至违法犯罪。记得不久前就看到过这样一个案例:一位计算机专业研究生入侵了一家商业网站并删除了所有数据。当他在狱中接受记者的采访时,他非常自豪地说这样做只是为了证明自己和获得那种成就感。

来源:论坛整理 2008年11月5日

关键字: 安全技术 入侵 攻击防范

  • 评论
  • 分享微博
  • 分享邮件
 很久以来,在人们心目中,“黑客”和病毒作者的身上总是笼罩着一层神秘的光环,他们被各种媒体描述成技术高手甚至技术天才,以至于有些人为了证明自己的“天才”身份而走上歧途,甚至违法犯罪。记得不久前就看到过这样一个案例:一位计算机专业研究生入侵了一家商业网站并删除了所有数据。当他在狱中接受记者的采访时,他非常自豪地说这样做只是为了证明自己和获得那种成就感。

  本文讨论的缓冲区溢出攻击实际上是一项非常“古老”的技术,但它的破坏力依然不可小视——相信大家都还没有忘记之前的“冲击波”。文中的代码实例几乎就是一个真实的病毒了,其中的一些技术你可能没有见过,但我可以很负责任的说它没有使用任何高深的技术,我没有进ring0,没有写设备驱动,甚至连汇编代码也只用了非常简单的11句。我希望此文能让大家重新认识一下“黑客”和病毒作者,把他们从神坛上“拉”下来。我更要提醒大家把那位“研究生”作为前车之鉴,不要滥用这项技术,否则必将玩火自焚。下面就进入正题。

  什么是缓冲区溢出

  你一定用strcpy拷贝过字符串吧?那,如果拷贝时目的字符串的缓冲区的长度小于源字符串的长度,会发生什么呢?对,源字符串中多余的字符会覆盖掉进程的其它数据。这种现象就叫缓冲区溢出。根据被覆盖数据的位置的不同,缓冲区溢出分为静态存储区溢出、栈溢出和堆溢出三种。而发生溢出后,进程可能的表现也有三种:一是运行正常,这时,被覆盖的是无用数据,并且没有发生访问违例;二是运行出错,包括输出错误和非法操作等;第三种就是受到攻击,程序开始执行有害代码,此时,哪些数据被覆盖和用什么数据来覆盖都是攻击者精心设计的。

  一般情况下,静态存储区和堆上的缓冲区溢出漏洞不大可能被攻击者利用。而栈上的漏洞则具有极大的危险性,所以我们的讲解也以栈上的缓冲区溢出为例。

  攻击原理

  要进行攻击,先得找到靶子。所以我就准备了一个叫做“victim”的程序作为被攻击对象,它在逻辑上等价于下面的代码:

void GetComputerName(SOCKET sck, LPSTR szComputer)
{
  char szBuf[512];
  recv(sck, szBuf, sizeof(szBuf), 0);
  LPSTR szFileName = szBuf;
  while((*szFileName) == '''')
   szFileName++;
  while((*szFileName) != '''' && (*szFileName) != '''')
  {
   *szComputer = *szFileName;
   szComputer++;
   szFileName++;
  }
  *szComputer = '''';
}
void ShowComputerName(SOCKET sck)
{
  char szComputer[16];
  GetComputerName(sck, szComputer);
  // mov ecx,dword ptr [esp+4]
  // sub esp,10h; ———②
  // lea eax,[esp]
  // push eax
  // push ecx
  // call GetComputerName (401000h)
  printf(szComputer);
  // lea edx,[esp]
  // push edx
  // call printf (401103h)
}
  // add esp,14h
  // ret 4; ———③
int __cdecl main(int argc, char* argv[])
{
  WSADATA wsa;
  WSAStartup(MAKEWORD(2,2), &wsa);
  struct sockaddr_in saServer;
  saServer.sin_family = AF_INET;
  saServer.sin_port = 0xA05B; //htons(23456)
  saServer.sin_addr.s_addr=ADDR_ANY;
  SOCKET sckListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  bind(sckListen, (sockaddr *)&saServer, sizeof(saServer));
  listen(sckListen, 2);
  SOCKET sckClient = accept(sckListen, NULL, NULL);// ———①
  ShowComputerName(sckClient);
  closesocket(sckClient);
  closesocket(sckListen);
  WSACleanup();
  return 0;
}

   victim程序的本意是从网络上接收一个UNC(Universal Naming Convention)形式的文件名,然后从中分离出机器名并打印在屏幕上。由于正常情况下,机器名最多只有16个字节,所以ShowComputerName函数也只给szComputer分配了16个字节长的缓冲区,并且GetComputerName也没有对缓冲区的长度做任何检查。这样,ShowComputerName中就出现了一个缓冲区溢出漏洞。

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章