最新消息:

关于扫描器XSS插件的思考

学习探索 pang0lin 75浏览 0评论

最近写一款WEB漏洞扫描器,整个过程还是挺顺利的。到最后的调试阶段,就开始和别的扫描器对比性能。遇到了一个比较特别的反射型XSS漏洞

本质上这是一个普通的POST类型的反射型XSS,大概是这样的

http://xxx.com/login.jspx?returnUrl=1"<script>alert(1)</script>

POST:
username=1&password=1

然后里面的returnUrl这里是存在反射型XSS漏洞的。

为了复现漏洞,我在firefox的hackbar里面构造了这个请求,但是得到的结果是这样的

这里可以看出,传入的参数在页面源代码中是经过了urlencode的,难道是说扫描器误报了?

答案当然是否定的。

后来翻阅了一些资料得知,浏览器对传入的URL会进行一次自动的urlencode操作,也就是把”变成%22。那如果是不让浏览器自动编码,就可以触发漏洞呢?

在burp里面构造同样的请求,然后把被编码的特殊字符解码回来。

可以看出如果是在burp里面直接发包中不编码字符串,确实存在了XSS漏洞

但是,如果浏览器对这种链接会自动编码,这样的漏洞怎么才能真的有用?用户又不会用burp来看你发的链接。

经过测试之后发现,firefox和chrome会对传入的url参数中的值进行编码,但是IE不会对浏览器进行编码,也就是说,漏洞成立,必须是基于用户使用的是IE或者IE内核的浏览器。

虽然漏洞具有局限性,但是作为一款扫描器,也应该是能够扫描到这种漏洞的。本人使用的扫描器基于python的requests库进行发包,在测试的过程中发现,requests同样会对部分特殊字符进行自动编码

有一个有意思的事情是这样的,对待上面的漏洞我的扫描器并没有扫描到,但是有一个几乎同样的漏洞大概就是这样的

http://xxxx.com?page=1'onclick=alert(1)//

我之前做测试的时候,就看到过我扫到了一个DOM-XSS,然后是利用单引号闭合了前面的单引号,然后引入了on事件导致XSS。这里同样是不能使用%27代替单引号,所以直接在forefox浏览器和chrome浏览器中都是不能复现的。

但是requests库没有对我传入的单引号进行编码(同IE浏览器),导致识别到这是一个反射型XSS

那为什么requests会对双引号进行编码,而不对单引号进行编码呢?

我去翻看了requests库的源代码,还好开源的。在utils.py文件中,有一段代码是这样的

def requote_uri(uri):
    """Re-quote the given URI.

    This function passes the given URI through an unquote/quote cycle to
    ensure that it is fully and consistently quoted.
    """
    safe_with_percent = "!#$%&'()*+,/:;=?@[]~"
    safe_without_percent = "!#$&'()*+,/:;=?@[]"
    try:
        # Unquote only the unreserved characters
        # Then quote only illegal characters (do not quote reserved,
        # unreserved, or '%')
        return quote(unquote_unreserved(uri), safe=safe_with_percent)
    except InvalidURL:
        # We couldn't unquote the given URI, so let's try quoting it, but
        # there may be unquoted '%'s in the URI. We need to make sure they're
        # properly quoted so they do not cause issues elsewhere.
        return quote(uri, safe=safe_without_percent)

这个函数大致就是在定义怎么对传入的url进行编码的,里面定义了一个变量safe_with_percent用来保存不需要编码的安全字符,可以看出单引号是被requests认为是安全的,然而双引号不是。

为了能够让我们的扫描器能够扫到这样的漏洞,有一个简单的办法是直接修改utils.py文件,

safe_with_percent = "!#$%&'()*+,/:;=?@[]~\""

这样之后,以后我们python的requests库,就不会再对url中的单引号进行编码了。

后来同事告诉我,还有一种更简单的方法是可以通过重写requests库的send方法,强行把已经被编码的url再转码回来。这样做的好处是,我只想在扫描器里面对requests库不编码特殊字符,但是其他时候,我还是希望它能正常工作。

import requests
import urllib

class NoQuotedCommasSession(requests.Session):
    def send(self, *a, **kw):
        a[0].url = a[0].url.replace(urllib.quote("\""), "\"").replace(urllib.quote("<"), "<").replace(urllib.quote(">"), ">")
        return requests.Session.send(self, *a, **kw)
s  = NoQuotedCommasSession()
s.get("http://xxxx.com?page='\"<aaaaaa>")

这样之后就可以按照我们的需求,像IE一样对URL进行访问了。

转载请注明:我是穿山甲,小弟穿山乙 » 关于扫描器XSS插件的思考

发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址