#user-password #script #lua #scriptable #cracker #networking #run-time

已删除 badtouch

可脚本化网络认证破解工具

0.7.3 2021年1月14日
0.7.1 2019年11月9日
0.7.0 2019年4月24日
0.6.1 2018年8月2日
0.3.0 2018年3月19日

#4#cracker

每月下载量 31 次

GPL-3.0 许可证

120KB
3K SLoC

badtouch Crates.io

badtouch 是一个可脚本化的网络认证破解工具。虽然常见的服务暴力破解空间已经 非常 饱和饱和,但在测试Web应用程序的凭据时,你可能仍然需要编写自己的Python脚本。

badtouch 的范围是专门破解自定义服务。这是通过编写加载到Lua运行时的脚本实现的。这些脚本代表一个单一的服务,并提供一个返回true或false的 verify(user, password) 函数。并发、进度指示和报告由 badtouch 运行时神奇地提供。

asciicast

安装

如果你在基于 archlinux 的系统上,使用

pacman -S badtouch

如果你在 Mac OSX 上,使用

brew install badtouch

要从源码构建,请确保已安装 rustlibssl-dev 并运行

cargo install

使用以下命令验证您的设置是否完成

badtouch --help

Debian

  1. 安装必要的构建工具
sudo apt-get update && sudo apt-get dist-upgrade
sudo apt-get install build-essential libssl-dev pkg-config
  1. 安装 rust
curl -sf -L https://static.rust-lang.org/rustup.sh | sh
source $HOME/.cargo/env
  1. 安装 badtouch
cd /path/to/badtouch
cargo install

脚本

一个简单的脚本可能看起来像这样

descr = "example.com"

function verify(user, password)
    session = http_mksession()

    -- get csrf token
    req = http_request(session, 'GET', 'https://example.com/login', {})
    resp = http_send(req)
    if last_err() then return end

    -- parse token from html
    html = resp['text']
    csrf = html_select(html, 'input[name="csrf"]')
    token = csrf["attrs"]["value"]

    -- send login
    req = http_request(session, 'POST', 'https://example.com/login', {
        form={
            user=user,
            password=password,
            csrf=token
        }
    })
    resp = http_send(req)
    if last_err() then return end

    -- search response for successful login
    html = resp['text']
    return html:find('Login successful') != nil
end

请参阅参考和 示例 了解所有可用函数。请注意,您可以使用 print(x)badtouch oneshot 来调试您的脚本。

参考

base64_decode

解码base64字符串。

base64_decode("ww==")

base64_encode

使用base64编码二进制数组。

base64_encode("\x00\xff")

clear_err

清除所有记录的错误以防止重新排队。

if last_err() then
    clear_err()
    return false
else
    return true
end

execve

执行外部程序。返回退出代码。

execve("myprog", {"arg1", "arg2", "--arg", "3"})

hex

对字节数组进行十六进制编码。

hex("\x6F\x68\x61\x69\x0A\x00")

hmac_md5

使用md5计算hmac。返回二进制数组。

hmac_md5("secret", "my authenticated message")

hmac_sha1

使用sha1计算hmac。返回二进制数组。

hmac_sha1("secret", "my authenticated message")

hmac_sha2_256

使用sha2_256计算hmac。返回二进制数组。

hmac_sha2_256("secret", "my authenticated message")

hmac_sha2_512

使用sha2_512计算hmac。返回二进制数组。

hmac_sha2_512("secret", "my authenticated message")

hmac_sha3_256

使用sha3_256计算hmac。返回二进制数组。

hmac_sha3_256("secret", "my authenticated message")

hmac_sha3_512

使用sha3_512计算hmac。返回二进制数组。

hmac_sha3_512("secret", "my authenticated message")

html_select

解析HTML文档并返回与CSS选择器匹配的第一个元素。返回值是一个表格,其中text是内部文本,attrs是元素属性表。

csrf = html_select(html, 'input[name="csrf"]')
token = csrf["attrs"]["value"]

html_select_list

html_select相同,但返回所有匹配项而不是第一个。

html_select_list(html, 'input[name="csrf"]')

http_basic_auth

发送带有基本认证的GET请求。如果没有设置WWW-Authenticate头,并且状态码不是401,则返回true

http_basic_auth("https://httpbin.org/basic-auth/foo/buzz", user, password)

http_mksession

创建会话对象。这与python-requests中的requests.Session类似,并跟踪cookie。

session = http_mksession()

http_request

准备HTTP请求。第一个参数是会话引用,并且从该会话中复制cookie到请求中。请求发送后,响应中的cookie会复制回会话。

下一个参数是methodurl和附加选项。请注意,即使没有设置选项,您仍然需要指定一个空的表格{}。以下选项可用

  • query - 应设置在URL上的查询参数映射
  • headers - 应设置的头映射
  • basic_auth - 使用{"用户, "密码"}配置基本认证头
  • user_agent - 用字符串覆盖默认用户代理
  • json - 应进行json编码的请求体
  • form - 应进行表单编码的请求体
  • body - 原始请求体作为字符串
req = http_request(session, 'POST', 'https://httpbin.org/post', {
    json={
        user=user,
        password=password,
    }
})
resp = http_send(req)
if last_err() then return end
if resp["status"] ~= 200 then return "invalid status code" end

http_send

使用http_request发送已构建的请求。返回一个具有以下键的表格

  • status - HTTP状态码
  • headers - 头表
  • text - 响应体作为字符串
req = http_request(session, 'POST', 'https://httpbin.org/post', {
    json={
        user=user,
        password=password,
    }
})
resp = http_send(req)
if last_err() then return end
if resp["status"] ~= 200 then return "invalid status code" end

json_decode

从json字符串解码lua值。

json_decode("{\"data\":{\"password\":\"fizz\",\"user\":\"bar\"},\"list\":[1,3,3,7]}")

json_encode

将 Lua 值编码为 JSON 字符串。请注意,空表被编码为空对象 {},而不是空列表 []

x = json_encode({
    hello="world",
    almost_one=0.9999,
    list={1,3,3,7},
    data={
        user=user,
        password=password,
        empty=nil
    }
})

last_err

如果没有记录错误,则返回 nil,否则返回字符串。

if last_err() then return end

ldap_bind

连接到 LDAP 服务器并尝试使用给定的用户进行身份验证。

ldap_bind("ldaps://ldap.example.com/",
    "cn=\"" .. ldap_escape(user) .. "\",ou=users,dc=example,dc=com", password)

ldap_escape

在相对区分名称中转义属性值。

ldap_escape(user)

ldap_search_bind

连接到 LDAP 服务器,登录到搜索用户,搜索目标用户,然后尝试使用搜索返回的第一个 DN 进行身份验证。

ldap_search_bind("ldaps://ldap.example.com/",
    -- the user we use to find the correct DN
    "cn=search_user,ou=users,dc=example,dc=com", "searchpw",
    -- base DN we search in
    "dc=example,dc=com",
    -- the user we test
    user, password)

md5

使用 md5 对字节数组进行散列并返回字节数据。

hex(md5("\x00\xff"))

mysql_connect

连接到 MySQL 数据库并尝试使用提供的凭据进行身份验证。成功时返回 MySQL 连接。

sock = mysql_connect("127.0.0.1", 3306, user, password)

mysql_query

在 MySQL 连接上运行查询。第三个参数用于预处理语句。

rows = mysql_query(sock, 'SELECT VERSION(), :foo as foo', {
    foo='magic'
})

print

打印变量的值。请注意,这将绕过常规写入器并可能干扰进度条。仅用于调试。

print({
    data={
        user=user,
        password=password
    }
})

rand

返回具有最小和最大约束的随机 u32。返回值可以大于或等于最小边界,并且始终小于最大边界。此函数尚未经过密码学安全性的审查。

rand(0, 256)

randombytes

生成指定数量的随机字节数。

randombytes(16)

sha1

使用 sha1 对字节数组进行散列并返回字节数据。

hex(sha1("\x00\xff"))

sha2_256

使用 sha2_256 对字节数组进行散列并返回字节数据。

hex(sha2_256("\x00\xff"))

sha2_512

使用 sha2_512 对字节数组进行散列并返回字节数据。

hex(sha2_512("\x00\xff"))

sha3_256

使用 sha3_256 对字节数组进行散列并返回字节数据。

hex(sha3_256("\x00\xff"))

sha3_512

使用 sha3_512 对字节数组进行散列并返回字节数据。

hex(sha3_512("\x00\xff"))

sleep

暂停线程指定的秒数。这主要用于调试并发。

sleep(3)

sock_connect

创建 TCP 连接。

sock = sock_connect("127.0.0.1", 1337)

sock_send

向套接字发送数据。

sock_send(sock, "hello world")

sock_recv

从套接字接收最多 4096 字节。

x = sock_recv(sock)

sock_sendline

向套接字发送字符串。自动将换行符追加到字符串中。

sock_sendline(sock, line)

sock_recvline

从套接字接收一行。该行包含换行符。

x = sock_recvline(sock)

sock_recvall

从套接字接收所有数据,直到 EOF。

x = sock_recvall(sock)

sock_recvline_contains

从服务器接收行,直到一行包含针,然后返回该行。

x = sock_recvline_contains(sock, needle)

sock_recvline_regex

从服务器接收行,直到一行匹配正则表达式,然后返回该行。

x = sock_recvline_regex(sock, "^250 ")

sock_recvn

从套接字接收恰好 n 字节。

x = sock_recvn(sock, 4)

sock_recvuntil

在找到针之前接收数据,然后返回包含针的所有数据。

x = sock_recvuntil(sock, needle)

sock_sendafter

在找到针之前接收数据,然后将数据写入套接字。

sock_sendafter(sock, needle, data)

sock_newline

覆盖默认的 \n 换行符。

sock_newline(sock, "\r\n")

配置

您可以在 ~/.config/badtouch.toml 中放置配置文件以设置一些默认值。

全局用户代理

[runtime]
user_agent = "w3m/0.5.3+git20180125"

RLIMIT_NOFILE

[runtime]
# requires CAP_SYS_RESOURCE
# sudo setcap 'CAP_SYS_RESOURCE=+ep' /usr/bin/badtouch
rlimit_nofile = 64000

包装Python脚本

badtouch 运行时仍然非常简单,因此您可能偶尔需要将 shell 传递给您的常规 Python 脚本。您的包装器可能看起来像这样

descr = "example.com"

function verify(user, password)
    ret = execve("./docs/test.py", {user, password})
    if last_err() then return end

    if ret == 2 then
        return "script signaled an exception"
    end

    return ret == 0
end

您的 Python 脚本可能看起来像这样

import sys

try:
    if sys.argv[1] == "foo" and sys.argv[2] == "bar":
        # correct credentials
        sys.exit(0)
    else:
        # incorrect credentials
        sys.exit(1)
except:
    # signal an exception
    # this requeues the attempt instead of discarding it
    sys.exit(2)

许可证

GPLv3+

依赖项

~27–43MB
~719K SLoC