无效HTTP请求绕过Lighttpd重写规则

阅读量    35660 |   稿费 180

分享到: QQ空间 新浪微博 微信 QQ facebook twitter

 

开始测试

作为测试的一部分,客户端提供了对根目录的列目录功能。在用Burp Intruder模块发起完全扫描之前,我通过repeater模块,在几个选择的页面中仔细查找,发现了secret.html,我感觉这个页面有些奇怪,于是发了一个请求并得到了如下的秘密内容:

这样就能查看秘密内容?也太easy了吧,但是我没有烦恼,继续探索。

我在浏览器中输入那个url地址,结果却是“对不起,你无法查看内容”,如图

这跟我想的不一样,我想这可能跟session有关,但是看Burp代理中的请求,貌似一样啊。

虽然Firefox中有一些额外的headers,但那也是正常的啊。

burp代理如图:

我琢磨着如果不用Firefox,使用curl能否看到内容?我直接把burp repeater中的请求复制过来,粘贴到命令行中:

奇怪的是,url粘贴的时候竟然出现了错误,少了一个/,但是我可以手工修改过来,请求后结果如图:

结果还是不允许查看,这跟我预想的也不一样。于是我直接从burp中获取curl命令并且运行,结果如图:

没有返回东西,而且url地址也不对,还是少了一个‘/’,这就有点头疼了。

此时,我应该意识到哪里有问题,但是没有,我还是直接加上‘/’,继续尝试请求,结果如图:

结果还是一样,这就奇了怪了。Burp能够访问到秘密的内容,Firefoxcurl却不能。

我们再试试Netcat,我先建立一个连接,然后从burp repeater中复制urlnc中执行,如图:

没有返回内容,连接是开着的,但是服务器没有响应。也许我哪里输错了,于是我将请求放到一个文件中,然后通过文件的方式发起请求:

连接还是被挂起,没有响应。现在,我有点蒙,整不明白。梳理一下情况:

Burp能够访问秘密内容

Curl使用burp提供的url无法访问秘密内容

Burp中提供的curl命令也无法访问秘密内容

Netcat的任何尝试也都是挂起状态

请求中肯定有不同的地方而我没有发现。我们往下一层走,用wireshark抓包看看。

首先是burp 请求:

然后是burp生成的curl命令:

有几个不同的地方,这个请求带有curl user agent和接受的header

WAFs和其他简单的防御系统都会对user agent进行检查,所以有可能就是这么简单。我们去掉额外的headers再尝试一遍:

盯着这些请求仔细看,看似没有区别,但我还是发现了其中的差异,

burp请求的是secret.html,而curl请求的是/secret.html。这个额外的‘/’肯定就是差异所在,

这也解释了为什么从burp复制的urlburp生成的curl命令都少了一个‘/’。

Burp能够发起请求并读到内容,因为文件名在请求中已经指定,而curl则要求url包含文件名。

由于我无法使用curl复现这个请求,所以使用Netcat试试,看看能否搞明白为什么失败。我们看看wireshark中的Netcat连接,如图:

对比查看两个请求,都是请求的secret.html,而不是/secret.html,但是肯定有细微的差别。

我们来看看十六进制视图是怎样的:

Burp十六进制视图

Netcat十六进制视图:

盯着看了一会儿,终于发现了不一致的地方,burp使用的是DOS形式的行尾结束符(rn),而Netcat使用的是Unix结束符(n)

因为之前我把请求放在文件中,使用vim的话,行尾结束符就会被很容易的修改,打开文件,输入如下内容:

然后保存。如果你不擅长使用vim,你也可以使用dos2Unix包中的unix2dos应用。

转换之后我们再来试一下:

耶,成功了,可以查看到内容。现在我可以通过Netcat复现请求,我们来看看究竟是不是斜线‘/’的问题。加上‘/’之后再试试看:

我们得到的是无法查看。请求secret.html可以访问,请求/secret.html被拒绝。

这种请求无法通过浏览器或者其他工具,因为它们将整个url视为参数,只有那些把主机和文件看做两个独立实体的才能解析这种请求。

虽然一开始我很蒙,搞不明白其中的细微差别,不过现在我可以复现这个问题了。

我觉得我应该找个时间跟开发者聊一聊,看他们知不知道这个问题。

 

继续深挖

跟做应用测试一样,客户端也要检查服务器配置,因此他们提供了Lighttpd的配置,当我发现下面这一样后,问题随之解决。

看起来非常简单,任何请求以/secret.html开头的页面将会在内部被重定向到/not_permitted.html页面。

但是当我请求secret.html,而不是/secret.html,这个规则就不适用了,我的请求并没有被重定向,所以我能访问到秘密内容。

 明白这点后,我想看看是否能够通过curl或者浏览器来查看秘密内容。第一次尝试如下url

我尝试了curl和很多浏览器,但他们都一样,在发请求之前进行了简化,所以最后还是请求的/secret.html

我尝试了多重../组合,都失败了。最终下面这条请求成功了:

我发现‘.’号会简化,但是多余的‘/’不会。所以下面的url是有效的并且能够访问到秘密内容,因为请求的是//secret.html,这跟它们的正则不匹配。

在众多浏览器中确认过这个url有效之后,我就可以把它作为证据写到报告里作为漏洞利用的例子。

虽然花了一些时间,但总比直接给他们展示一张burprepeater截图说:“嘿,我看到了你们的秘密内容,但不知道是怎么看到的”。

希望你看完我是符合调试这个漏洞对你有所帮助。这展示了计算机的确定性,任何事情都有原因。

有时候只是需要花点时间来弄明白它的规则,当你知道游戏规则后,你就可以在游戏中轻而易举的获胜,正所谓知己知彼,百战不殆。

 

测试其他web服务器

我决定对ApacheNginxIIS也进行测试,但是都返回“400 Bad request”响应。

Apache

查看错误日志文件,也多了一条记录:

Nginx

Nginx中没有错误日志。

IIS

我没有权限访问IIS日志文件来查看是否有错误日志。

 

防御

不要在根目录存放秘密文件。如果存放在根目录意外,它依然可以被其他页面调用,但是无法直接通过url访问;

代码层防御,增加过滤函数,添加必要的‘/’,移除所有额外的‘/’;

 应用如下规则,提示403禁止访问页面:

Server.errorfile-prefix选项可以设置为返回一个自定义的403错误页面。

 如果你想修复重写规则,最简单的办法就是通过正则匹配移除‘/:

这条规则会拦截所有访问包含secret.html的请求。如果类似这种文件在这个网站中是唯一的,那么这条规则十分有效。

如果其他人在网站上有一个view_secret.html文件,那么这条规则就会给其他人带来一堆问题,他们看不到自己的页面并且苦恼的琢磨着为什么。

下面这个规则更好,无论secret.html前面跟着多少个‘/’,都重定向到禁止页面。

我觉得这也不是最好的解决方案,因为可能会有其他字符插入到文件名中来绕过规则。

 最后一条建议依赖于secret.html的目的。

如果它是一个模板文件,被其他文件引用,那么可以在文件中添加一些逻辑,只有通过正确访问才显示内容,否则不显示内容,

比如对引用它的文件做相同的认证和授权检查。

 

审核人:yiwang   编辑:边边

分享到: QQ空间 新浪微博 微信 QQ facebook twitter
|推荐阅读
|发表评论
|评论列表
加载更多