Hydra 蛮力和 JSON

信息安全 密码 蛮力 九头蛇
2021-08-20 18:00:13

我遇到了 Hydra 和 JSON 有效负载的问题。

登录请求(被 Fiddler 拦截)如下:

POST http://architectureservice.test.com/api/v1/login HTTP/1.1
Host: architectureservice.test.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json;charset=utf-8
Referer: http://architectureclient.test.com/
Content-Length: 51
Origin: http://architectureclient.test.com
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache

{"username":"tester","password":"test"}

响应,在密码错误的情况下实际上是空的,因为它是一个单页应用程序。服务器将改为返回 404(未找到)或 405 错误代码。如果凭据正确,它将继续返回 200 页。

如您所见,请求从客户端流向服务。服务上其实是没有表单的,它接受客户端填写的参数(这都是在我的本地机器上,改编了HOSTS文件)。当凭据正确时,将创建一个cookie(这是第一个cookie,登录前没有会话cookie或其他东西)。

现在,凭据以 JSON 格式传递。我的 Hydra 命令如下所示:

hydra -L "users.txt" -P "passwords.txt" -s 80 architectureservice.test.com http-post-form "/api/v1/login:{'username'\:'^USER^','password'\:'^PASS^'}:NOT FOUND"

但是,这将返回所有密码都是有效的。是否可以将 Hydra 与 JSON 格式和单页应用程序一起使用?


更新 感谢 Iserni 的回答,我能够构建以下命令:

hydra -v -V -L "users.txt" -P "passwords.txt" -s 80 architectureservice.test.com http-post-form "/api/v1/login:{\"username\"\:\"^USER^\",\"password\"\:\"^PASS^\"}:changeFirstName:H=Accept: application/json, text/plain, */*:H=Accept-Language: en-US,en;q=0.5:H=Accept-Encoding: gzip, deflate:H=Referer: http\://architectureclient.test.com/:H=Origin: http\://architectureclient.test.com:H=Connection: keep-alive"

注意:请注意,不必在 Header 值中转义冒号。事实上,这会破坏命令,所以你不能在那里转义冒号。

我用 Wireshark 截获了这个请求,除了 JSON 有效负载外,它看起来与用 Firefox 发出的请求完全相同。Hydra 创建了一个“x-www-form-urlencoded”主体。如果我尝试使用 Firefox 请求(被 fiddler 拦截)以这种方式对其进行编码,则会出现“未找到”错误。所以我确实需要能够创建一个 JSON 内容类型。这对 Hydra 可行吗?

为了澄清事情,这里是 Wireshark 捕获的屏幕截图: Wireshark 截图 除了 Content-Type 标头和正文有效负载(来自 Firefox,它是 JSON)之外,一切都与从 Firefox 发出请求时完全相同。


更新:解决方案

hydra -v -V -L "users.txt" -P "passwords.txt" -s 80 architectureservice.tester.com http-post-form "/api/v1/login:{\"username\"\:\"^USER^\",\"password\"\:\"^PASS^\"}:S=firstName:H=Accept: application/json, text/plain, */*:H=Accept-Language: en-US,en;q=0.5:H=Accept-Encoding: gzip, deflate:H=Referer: http\://architectureclient.tester.com/:H=Origin: http\://architectureclient.tester.com:H=Connection: keep-alive"

S=: I used this because in case of a failure, we get an empty response. The S= can be used to tell Hydra what comes back in case of a valid response. (We send back the firstName in case of a success)
H=: I noticed that Hydra understands that in a header, there will always be a colon. So you do not need to escape colons in headers. In other places, you do.

如果您按以下方式调整 Hydra 的源代码(对于 Hydra 7.6),上述命令有效: 在 hydra-http-form.c 的第 327 行附近:

  if (strcmp(type, "POST") == 0) {
    sprintf(buffer,
            "POST %.600s HTTP/1.0\r\nHost: %s\r\nUser-Agent: Mozilla/5.0 (Hydra)\r\nContent-Type: application/json\r\nContent-Length: %d\r\n%s%s\r\n%s",
            url, webtarget, (int) strlen(upd3variables), header, cuserheader, upd3variables);
    if (hydra_send(s, buffer, strlen(buffer), 0) < 0) {
      return 1;

如您所见,我采用了最丑陋的解决方案(将硬编码的标头值从“x-www-form-urlencoded”切换为“json”。Iserni(见下面的答案)提出了一种更好的方法,但我遇到了一些语法错误并决定只是硬编码 json 值。此外,Content-Type 在 hydra-http-form.c 文件中的多个位置被硬编码,请根据您的情况在必要时进行更改。

现在,您可以使用 Hydra 暴力破解 json Web 应用程序。

1个回答

如果 JSON 没有问题(见底部),问题可能是 Hydra 现在发送的标头与 AJAX 登录表单的标头不同。

标头问题的主要来源(当然除了 User-Agent)通常是

  • Content-Type标题_
  • Accept标题_
  • Origin标题_
  • X-Requested-With标题_
  • 推荐人和 CSRF 检查。
  • 饼干,

许多框架,无论是作为调试辅助还是“安全”,都会检查 XRW 标头和/或 CSRF 对策,如果内容类型和接受参数不适合作为 JSON 请求,一些路由器将提供重定向(HTTP/1.1 200 OK页面) ,您的登录名应该是,

Cookie 似乎不是您的问题。

您首先需要检查所有必要的标头,您可以通过使用 cURL 并检查单个登录(始终相同)来完成。

(运行的另一个有价值的检查是拦截框架对单个 Hydra 请求的响应。假设 200 页 Hydra 错误为正确登录而不是“输入中的错误某某……”)。

找到相关标题及其值后,您必须将它们包含在 Hydra 序列中。允许输入错误,例如

"/api/v1/login:{\"username\"\:\"^USER^\",\"password\"\:\"^PASS^\"}:NOT FOUND:H=Origin\: http\://architectureclient.test.com:H=Accept\: application/json, text/plain, */*:H=Content-Type\: application/json;charset=utf-8"

请注意,您使用的序列似乎与您的 HTTP 请求的 JSON 风格不同您使用单引号,但一些解码器(尤其是 PHP 的json_decode())会犹豫。POST相反,您引用的拦截使用引号。

<?php
    $json=<<<JSON
{'user':'joe'}
JSON;
    // Does not work (PHP 5.6.x)
    print_r(json_decode($json, true));
?>

关于内容类型的更新

我已经检查了 Hydra 的源代码。显然,方法为POST. (Hydra 8.0 代码,文件hydra-http-form.c):

  if (strcmp(type, "POST") == 0) {
    sprintf(buffer,
            "POST %.600s HTTP/1.0\r\nHost: %s\r\nUser-Agent: Mozilla/5.0 (Hydra)\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: %d\r\n%s%s\r\n%s",
            url, webtarget, (int) strlen(upd3variables), header, cuserheader, upd3variables);
    if (hydra_send(s, buffer, strlen(buffer), 0) < 0) {
      return 1;
    }
  } else {
    ...

解决方案。嗯。一个非常丑陋肮脏的黑客:

sed -e 's/Content-Type: application\/x-www-form-urlencoded/X-Would-Type: application\/x-www-form-urlencoded/' < hydra > hydra2

...这将产生一个新的二进制文件,它不会发送一个Content-Type标题而是X-Would-Type一个。两个字符串长度相等,并且二进制文件没有被签名或 MD5summed,它应该可以工作。现在您可以添加Content-Type自己的标题,这应该会通过。

不过,我不完全确定如何使用 Hydra发送多个标头。命令似乎是冒号分隔的,并且由于标题包含冒号......

更好的解决方案

编辑代码,使其读取(在我的源代码中的第 298 行附近):

  if (strcmp(type, "POST") == 0) {
    sprintf(buffer,
            "POST http://%s:%d%.600s HTTP/1.0\r\nHost: %s\r\nUser-Agent: Mozilla/5.0 (Hydra)\r\n%sContent-Length: %d\r\n%s%s\r\n%s",
            webtarget, webport, url, webtarget,

    ((NULL == strstr("Content-Type", cuserheader))
     ? "Content-Type: application/x-www-form-urlencoded\r\n"
     : "")

    (int) strlen(upd3variables), header, cuserheader, upd3variables);
    if (hydra_send(s, buffer, strlen(buffer), 0) < 0) {
      return 1;
    }
  } else {

...因此,如果您提供Content-Type自己的 a,它不会自己添加一个。