Neurohazard
暮雲煙月,皓首窮經;森羅萬象,如是我聞。

Burp Suite: Turbo Intruder 基本使用

wpadmin~January 29, 2019 /InfoSec

Contents

Burp Suite: Turbo Intruder 基本使用

author: BLKStone

感谢 CF_HB 提供的帮助

从个人角度看值得关注的优势

1 通过调参实现高 RPS

2 支持发送畸形 HTTP 请求

基本说明

Turbo Intruder 是一个 Burp Suite 的一个插件,似乎也是由 James Kettle 牵头主导的一个项目。这个插件设计的主要目标是希望能够发送 海量 的 HTTP 请求,同时分析其响应。这个插件使用的网络栈是为了加快发包速度而单独进行优化过的,在某些极端情况下可以达到 30, 000 RPS。(当然最终的 RPS 值也跟具体 web 应用本身和其服务端配置高度相关)

特性说明

快速 – Turbo Intruder 使用从头开始手动编码的 HTTP 网络栈,在构建过程中一直都在考虑发包速度。 因此,在许多目标上,它甚至可以超过的异步 Go 实现的脚本。

可扩展 – Turbo Intruder 可以实现平滑的内存使用,实现可靠的多日攻击。 它也可以通过命令行在 Headless 环境中运行。

灵活 – 攻击的配置是通过 Python 来处理的,这可以帮助实现一些复杂的需求,比如需要配置一个多个 HTTP 交互步骤的攻击序列;并且也支持一些发送一些常规 API 无法实现的 畸形 HTTP 请求

方便 – 该插件已实现了一种 diff 算法可以自动忽略一些 “无价值的” 的 HTTP 响应。

1548772113827

P.S.: James Kettle 在 PortSwigger 的主要工作是负责优化 Burp Suite 的 Scanner 组件的扫描能力,以及一些新型 Web 应用漏洞的安全研究。

原理简介

1548771439680

1 发送多个 HTTP 请求时不关闭 TCP 连接 (TCP 复用),可以省去 中间的 TCP 连接建立时三次握手的时间。

2 Pipleline 模式,连续无间隔发送多个请求,再无间隔读取,省去 SERVER_WAITLATENCY

注意,使用 Pipeline 模式时可能会出现请求和响应 错位 的情况。

engine 是基于 Java Thread 的,并且未使用 HTTP / 2。

常用例子

在原始 HTTP 请求中用 %s 标出要替换的内容。

# Find more example scripts at https://github.com/PortSwigger/turbo-intruder/tree/master/examples
def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                           concurrentConnections=5,
                           requestsPerConnection=100,
                           pipeline=False
                           )
    engine.start()

    # 将 404 页面标注为 boring
    for i in range(3, 8):
        engine.queue(target.req, randstr(i), learn=1)
        engine.queue(target.req, target.baseInput, learn=2)

    for word in open('/usr/share/dict/words'):
        engine.queue(target.req, word.rstrip())

    # list of all words observed in traffic
    for word in wordlists.observedWords:
        engine.queue(target.req, word)


def handleResponse(req, interesting):
    if interesting:
        table.add(req)

速度调整(Speed Tuning)

如果 HTTP 请求发送速度对于攻击很重要,那么您可能希望按顺序调整如下三个参数 pipeline, requestsPerConnectionconcurrentConnections。目标应该是找到最大化RPS(每秒请求数)的三个参数值,同时尽可能保持 Retries 计数器接近 0 。

这里的三个参数的最佳值是高度依赖具体服务器状态的,但到目前为止我 (James Kettle) 已达到最大速度是 30,000 RPS 。

调速案例

Turbo Intruder: Abusing HTTP Misfeatures to Accelerate Attacks by James Kettle / 10:32

条件竞争

默认的脚本并不适合做针对条件竞争类型漏洞的 exploit 。

如果你需要让 HTTP 请求尽可能在接近同一时刻的窗口内到达服务端,建议先将请求内容放入队列,之后再进行engine.start()

另外要保证 concurrentConnections 的值与一开始放入队列的请求数一致。

优惠券案例

Turbo Intruder: Abusing HTTP Misfeatures to Accelerate Attacks by James Kettle / 14:51

参考示例

https://github.com/PortSwigger/turbo-intruder/blob/master/resources/examples/race.py

def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                           concurrentConnections=30,
                           requestsPerConnection=100,
                           pipeline=False
                           )
    # queue up attacks before launching engine.start
    for i in range(30):
        engine.queue(target.req, target.baseInput)

    engine.start(timeout=5)
    engine.complete(timeout=60)


def handleResponse(req, interesting):
    table.add(req)

Turbo Intruder 内置字典

Turbo Intruder 有两个内置字典,一个是用于 长时间的目录暴力破解攻击 (long-running bruteforce attacks) , 另一个是存储所有 目标范围 内流量响应中包含的单词 (all words observed in in-scope proxy traffic in-scope proxy traffic)。

observed word

示例

def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                           concurrentConnections=5,
                           requestsPerConnection=100,
                           pipeline=False
                           )

    engine.start()

    # regular wordlist
    for line in open('D:\\share\\demo_list.txt'):
        engine.queue(target.req, line.rstrip())

    # list of all words observed in traffic
    for word in wordlists.observedWords:
        engine.queue(target.req, word)

def handleResponse(req, interesting):
    table.add(req)

long-running bruteforce attacks

无尽枚举

可以用于毫无前置信息的强行枚举目录,不过耗时巨大。

def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                           concurrentConnections=5,
                           requestsPerConnection=100,
                           pipeline=False
                           )

    engine.start()

    # infinitely-running bruteforce (a, b ... aaa, aab etc)
    seed = 0
    while True:
        batch = []
        # 这里的 5000 似乎不是数量
        seed = wordlists.bruteforce.generate(seed, 5000, batch)
        for word in batch:
            engine.queue(target.req, word)


def handleResponse(req, interesting):
    table.add(req)

命令行模式 (Command line usage)

命令行模式不支持自动发现 interesting 的 HTTP 响应。


# 基本用法 java -jar turbo.jar <scriptFile> <baseRequestFile> <endpoint> <baseInput> # 具体示例 java -jar turbo.jar resources/examples/basic.py resources/examples/request.txt https://example.net:443 foo java -jar turbo-intruder-all.jar default.py req.txt http://wp.blkstone.me:80 ""

baseInput 一般可以置空。

网络栈/引擎切换

Earlier versions of Turbo Intruder also had asynchronous and HTTP2 engines built on Apache HttpComponents but they were vastly less reliable than the threaded engine and didn’t actually go any faster on most machines, so it has been removed.

Turbo Intruder 引擎

def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                           concurrentConnections=1,
                           requestsPerConnection=1,
                           pipeline=False,
                           maxRetriesPerRequest=0,
                           engine=Engine.THREADED
                           )
    engine.start()

Burp 默认网络栈

def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                           concurrentConnections=1,
                           requestsPerConnection=1,
                           pipeline=False,
                           maxRetriesPerRequest=0,
                           engine=Engine.BURP
                           )
    engine.start()

常见的过滤方式

显示全部

# 显示全部
def handleResponse(req, interesting):
    table.add(req)

显示 interesting

Coding a custom response check here isn’t always necessary – if you queue a requests specify the ‘learn’ parameter then Turbo Intruder will learn those responses as boring, and then set the ‘interesting’ argument based on whether each new response looks like a boring one. This strategy is used by the default script. For further information on this filtering strategy, check out my presentation on Backslash Powered Scanner

# 显示 interesting
# 用 learn 参数指定,让 turbo intruder 学习 boring 的响应 

def handleResponse(req, interesting):
    if interesting:
        table.add(req)

仅不显示 404 Not Found

def handleResponse(req, interesting):
    if '404 Not Found' not in req.response:
        table.add(req)

仅显示 200 OK

# 仅显示 200 OK
def handleResponse(req, interesting):
    if '200 OK' in req.response:
        table.add(req)

目录嵌套

支持枚举多级目录。

def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint)
    engine.start()
    for word in open('/usr/share/dict/words'):
        engine.queue(target.req, word.rstrip())


def handleResponse(req, interesting):
    if '404 Not Found' not in req.response:
        table.add(req)
        for word in open('/usr/share/dict/words'):
            req.engine.queue(req.template, req.word+'/'+word.rstrip())

debug 脚本

If the ‘failed’ counter in the stats panel starts rapidly increasing, that’s a good sign that something is amiss. It could be a problem with your script, the target website, or Turbo Intruder's network stack. If you’re interested in helping make the tool better, I’ve made a debug script to help you identify and potentially report the source of the problem.

将自定义的内容直接放入请求队列中。

# Use this to debug issues with Turbo Intruder connecting to sites
# If this script as-is fails, try changing Engine.THREADED to Engine.BURP
# If that makes it work, file a report on http://github.com/PortSwigger/turbo-intruder/issues
# Please include the target request/domain, and your OS and Java version from Help->Diagnostics
def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                           concurrentConnections=1,
                           requestsPerConnection=1,
                           pipeline=False,
                           maxRetriesPerRequest=0,
                           engine=Engine.THREADED
                           )
    engine.start()

    engine.queue(target.req)
    engine.queue(target.req)
    engine.queue(target.req)


def handleResponse(req, interesting):
    table.add(req)

Cluster Bomb

举个例子

POST /login/ HTTP/1.1
Host: wp.blkstone.me
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://wp.blkstone.me/7062fcc4-login/?loggedout=true
Content-Type: application/x-www-form-urlencoded
Content-Length: 104
Connection: close
Cookie:wordpress_test_cookie=WP+Cookie+check; _gid=GA1.2.1749827947.1548738591
Upgrade-Insecure-Requests: 1

%s&wp-submit=Log+In&redirect_to=http%3A%2F%2Fwp.blkstone.me%2Fwp-admin%2F&testcookie=1

cluster bomb

def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                           concurrentConnections=5,
                           requestsPerConnection=100,
                           pipeline=False
                           )

    engine.start()

    # cluster bomber
    for password in open('D:\\share\\top500passwords.txt'):
        for username in open('D:\\share\\users.txt'):
            # log=admin&pwd=123456
            payload = 'log=' + username.rstrip() + '&pwd=' + password.rstrip()
            engine.queue(target.req, payload.rstrip())

    # list of all words observed in traffic
    for word in wordlists.observedWords:
        engine.queue(target.req, word)

def handleResponse(req, interesting):
    table.add(req)

缺陷

不支持 upstream proxy

不支持 SSL 客户端证书 (SSL Client Certificate)

但是可以通过切换网络引擎到 Engine.BURP 来解决。

def queueRequests(target, wordlists):
    engine = RequestEngine(engine=Engine.BURP)
    engine.start()

其他问题

1 cmdline 模式如何 output 结果

参考资料

依据相关性从高到低排列

Turbo Intruder README.md

https://github.com/PortSwigger/turbo-intruder/blob/master/readme.md

Turbo Intruder: Embracing the billion-request attack

https://portswigger.net/blog/turbo-intruder-embracing-the-billion-request-attack

Turbo Intruder: Abusing HTTP Misfeatures to Accelerate Attacks by James Kettle

James Kettle – Backslash Powered Scanning: Implementing Human Intuition

(一些有关扫描器设计的思考)

distributeDamage

https://github.com/PortSwigger/distribute-damage

backslash-powered-scanner

https://github.com/PortSwigger/backslash-powered-scanner

LevelUp 0x03 2019 | Bugcrowd

Leave a Reply

Your email address will not be published. Required fields are marked *