BurpSuite作为代理,复用目标站点的js代码处理指定的内容

BurpSuite作为代理,复用目标站点的js代码处理指定的内容

本文转自thinkoaa 并作补充

0x01 前言

之前写了一个burp插件,直接使用目标站点的加密js来解决用intruder模块爆破时的payload加密问题

地址:https://www.freebuf.com/sectool/242363.html

除了上面的情况外,有时还会遇到把burp当作代理,调用网站的js代码处理来自浏览器、sqlmap等工具的内容情况。

比如目标网站的参数调用了js加密算法,不管是手动访问也好,还是sqlmap注入也好,需要调用指定算法处理参数,用python或java重写算法的话呢,时间成本太高,有些算法还挺复杂……但,如果能够直接复用目标网站的js代码的话就太方便了。

因此,简单写了一个burp suite插件,专门解决上述问题:下载地址:JSFlash

使用步骤是 可以参考我之前另一个插件的文章 参考地址

  1. 1.把目标站点的相关js代码放到本地js文件中,调试可用;
  2. 2.把JSFlash插件导入到Burp Suite中,在插件中加载指定的js文件并填写对应的参数;
  3. 3.抓包发repeater做测试,如果效果符合预期,则该插件会根据指定的规则,调用js代码,处理指定的内容。

效果图:

image

0x02 使用方法

1.从目标站点复制修改或者手动写好js代码,调试正确

image

image

因为插件是通过java调用js,因此window、document等对象及方法,还有一些很新的js特性可能在浏览器中执行正确,但插件调用时会报错,因此插件会把可能产生的错误信息弹出显示,方便根据实际逻辑修改,根据我的经历来看,不管多复杂,只要耐心点,没有改不了的情况,如图:

image

image

再举一个例:

image

image

2.导入插件,设置参数

image

2.1 设置url,一定要用burp的Copy URL菜单复制,不要手动填写,以免出错:

image

image

2.2 设置处理指定内容的规则

GET方式:

image

image

php代码如图:

image

处理结果:

image

POST方式:

image

image

php代码如图:

image

结果如图:

image

一次调用多个方法,处理多个指定内容:

数据包:

image

规则:

image

php代码:

image

结果:

image

0x03 总结

这个插件用到的时候,需要具体情况具体分析,不过思路是这么个思路,目的就是复用js代码,提高工作效率。

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攻击工具中使用它。有关更多信息,请参阅此处

Shu-黍

Shu-黍

imageimage

“所聚越多,所负也越重。你我呀,都只是自己天地间的一栗罢了”

我得说一句,这可能是明日方舟第一次限定把陪跑风头几乎完全压住的一次

虽然我并不认为黍太超出预期,一是看莱茵看多了习惯这样的配色,而是梯田与闽南语这样的象征我从小就在接触(有生之年能听到客家话嘛?)……

但是确实还是超出预期了(这都什么发言啊,已经混乱了),然而我还要两三个小时才下班QAQ

最后感谢鹰角送的新年贺词,诶,是什么来着?

灰产-如何对APK修改后重签

灰产-如何对APK修改后重签

image

写在前面

前段时间没有事做的时候,组织上仿佛看穿了我很咸,突然让我去研究下灰产包,让我分析用了什么技术&做出了什么改动。

image

总而言之

虽然入职就听说了公司应用之前有被灰产“薅羊毛”的问题,但真让我弄我也没专门弄过啊,而且这部分之前是交给风控组去做的,这么久了整不来靠我嘛?而且我也想吐槽这灰产包你们又是怎么弄来的,还有两份不同技术实现的……

image

签名篡改

如果想对apk内部内容进行修改,从而达到实现某些功能或规避某些审查的目的,就一定要对签名进行重签,这一点上只需要和正版签名比对一下便能发现。如何检测使用了这些篡改应用的用户等不在这次的任务范围内,篡改功能点内容也不展开讨论,此处仅讨论绕过审查重签的技术。

image

MT APP签名检查及绕过

对灰产包简单的逆向后,我在第一个包很快地就发现了一个KillApplication.java

image

很显然,做篡改的兄弟还不够细,或者根本没懂相应的原理性知识,留下了如此明显的痕迹,并且在URL参数直接暴露了篡改方式:

ApkSignatureKillerEx

image

算是让我直接回忆起之前用过的MT管理器,好像酷安就能下到,不过我已经很久没用过了,不知道MT现在是自带这种签名方式还是作为外部插件使用的。

而MT APP签名检查及绕过在Android逆向-获取APP签名 一文中有详细表述,在此不做赘述(懒)

NP APP签名检查及绕过

那我们再来看下一个,啊,还不用我找,MobSF都给我翻出来了:

image

你是?

image

顺着FuckSign.java2863678687@qq.com 这两个信息(痕迹也是太明显了),我找到了另一种篡改方式:

NP-Manager

image

直接获取下来也很容易就复现了篡改与绕过:

image

写在后面

首先啊,风控安全真是和什么都斗争不断,除开apk包篡改,也还有模拟GPS定位、虚拟用户接码手机号等等,还好不是我直接负责:

image

然后,之前文章提到过外网可能是MobSF官方开的一个在线检测的平台,直接暴露了非常多的检测应用报告,无独有偶,我在做这次灰产分析的时候,在搜索引擎寻找FuckSign.java,发现了国内一个仿MobSF的在线检测平台,从搜索引擎记录来看,市场上很多其他应用也不堪灰产侵扰:

image

我在发现这个检测平台的时候,它给检测项部分“需要开通VIP”解锁,该说是刻意而为导致规避了部分问题还是啥呢……总之,我在几周后重新访问的时候,他已经是崩溃状态,嘛,不好评价:

image

最后,要做灰产黑产,就要从原理性把痕迹去除或转化,不能留太明显的技术痕迹,虽然可以说这些最后找到的都是开源项目,是卖刀者不是作恶人,但淹死的多是会水的,这里分享一篇文章:灰产,赚点快钱?

image

参考引用

ApkSignatureKillerEx

Android逆向-获取APP签名

NP-Manager

Firebase Installations API 密钥硬编码

灰产,赚点快钱?

Firebase Installations API 密钥硬编码

Firebase Installations API 密钥硬编码

image

起因

新公司让我对应用移动端产品也渗透一下,自然地想到移动端APK相关的自动化检测工具,于是Docker起了一个MobSF跑了下检测,算是做个铺垫。

当然还不如自己手动测来的漏洞直接,自动化扫描得出的结果不一定都具有直接性和威胁性,但MobSF还支持动态检测,实测下来确实能自动化访问activity事件,但每次调用Frida去执行注入测试的时候就会出大大小小的问题:

  1. 目前Mac M1/M2芯片由于ARM架构的问题,还无法完全解决Genymotion跑不了ARM包的问题(Genymotion给的MAC客户端实现用的是X86架构,完全不是官方说的因为是ARM芯片就可以直接支持ARM包了,实践出真知),M1/M2可使用的系统目前只有Android11,无法打translation包
  2. 很多移动应用做了SSL-Pinning等方式防抓包,需要用各种Posed去解,这些操作可能会与MobSF动态检测的模块冲突与覆盖(如MobSF动态检测会自动植入证书)

虽然对个人的工作不会带来太大的影响(又不是没有扫描器就不会渗透了),但我还是想流畅地使用一回动态检测啊,看看能达到什么层度,有这个执念在,我萌生了一个想法:

互联网上有没有别人搭建好的完整检测平台呢?

image

资产发现

还真被我找到一个,而且像是官方搭建的站点,此处相关域名隐去,不予展开。

作为一个安全人员,自然会考虑提交检测的包会上传存储在哪及检测内容是否会暴露的问题,于是我先下意识地访问了recent scans:

image

这是啥?!为什么我能看到今天所有提交检测的应用,并且可以看到完整的检测报告?!而且更哈人的是,举例应用竟然是未对外发布的内部研发版本(官网版本2.0.011 < 研发版本2.0.015),且没有做加固之类的!

image

这不禁让我想到了两个问题:

  1. MobSF这个线上检测平台肯定是没做好权限划分的,或者从设计来说MobSF可能就没实现这点,因为一般都是在本地部署的检测平台;纵使在后台做了定期清理数据的策略,在短期内这些检测内容还是会留存下来
  2. 所有被检测的应用可以被任意的人员查看,如果有安全问题很有可能线上版本也存在类似问题,而且数据泄漏就是泄漏了,在一段时间内一个访问凭证都将是有效的,即使你知道它已经泄露,会因为你不知道多少功能调用用到了这个凭证而不敢直接替换

那么这个应用里有什么呢?

image

API Key泄露

直接上图,这些码应该够了吧:

image

除了显而易见的google_maps_key 外,apk内还硬编码了firebase_database_urlgoogle_api_keygoogle_app_idgoogle_storage_bucket 等敏感参数(有些是我直接获取源包找的),firebase_database_url 直接访问果然无权限,但是剩下的几个参数是怎么调用的?能获得什么信息呢?

首先猜测和存储空间有关,但不对,Google Cloud并不是用这样的参数类型请求访问的;那既然存在firebase_database_url,会不会和Firebase有关?一番文档翻找下,我大致了解了Firebase是啥,还有一部分的API调用,并知道了相关的API Key是在什么位置被生成又用于何处的:

image

之后要做的事情就简单了,构造一个请求,就可以获取到与Firebase服务器交互许可的凭证了:

image

之后的操作就不做了,扩大影响面应该很容易,所以为什么要演奏春日……啊不对,为什么要把应用程序的报告暴露在公开检测平台!

image

参考引用

Deploy an application - Desktop User Guide

How to install Xposed/EdXposed/LSPosed + Magisk with Genymotion Desktop?

管理 Firebase 安装

排查初始化选项问题

QQ群名称改动的一些小问题

QQ群名称改动的一些小问题

image

写在前面

别问我为啥最近更博客更这么勤,首先我得承认,确实新公司在我试用期的时候没有安排很多复杂的活给我干,虽然这样,但也不代表我每天能产出或者转载这么多文章,毕竟都是技术文章,都要自己看过理解再push上来的,每天有这么多时间吗?

前段时间没有,这段时间有了= =

因为临近年关,加上推进DLP和其他安全服务都阻塞在了钱上,导致最近我甚至能在Copy之于,写几篇这样的原创文章,分享下杂七杂八的技术来了。

但说实话,不论是转载来的文章还是自己原创的文章,都是比较久前接触到的知识了,也就是即使我是现在写出来的,接触我所描述的技术也是在大半年前甚至一年多前了(比如下文),每次写博客就是这样把旧东西重新捡拾的过程,有点像中学时期的错题本,常看常新,再看再新……

所以这不算是在工位上摸鱼哦,是增长技术积累,嗯,一定是这样。

image

问题二则

其一:讨论组的实现与群聊不同

读者要说了:你这是废话

之前在QQ创建讨论组和创建群的方式就不一样,实现上不一致是很自然的事情,但是在作者写这篇文章的时候,QQ已经把“创建讨论组”这一功能下线了,所有的讨论组理论上也都自动转群了。

image

那么这个时候,讨论组转成的群和直接创建的群有什么差异吗?毕竟现在看起来一摸一样,转换后的群是重构了实现还是直接被套了个群外壳?

任意群成员可修改群名

在讨论组内,大家的权限划分是较为统一的,或者可以理解为没有做好权限划分,在转群后群成员仍被赋予了较高的权限,如:在只有一个群主的讨论组转群里,即便其他群成员不是管理员也可以随意修改群名(甚至可以扩展到其他信息):

image

image

image

image

而对于直接创建的群来说,群名称是无法被任意群成员提交修改的:

image

image

其二:QQ客户端群名称修改注入

对于第一个问题,大家肯定会说这有啥,连个越权都算不上,利用不起来,顶多整蛊无辜群主,钓鱼诈骗都难利用起来,无意义,忽略了!(很像是SRC漏洞审核员会脱口而出的话呢)

image

那么,如果我顺着这个思路,触发一下客户端的注入,阁下又该如何应对?

image

image

首先可以看出QQ的客户端(包括TIM)在PC和移动端对群名称修改的实现不同:对于同一个POC,移动端将闭合字符后续的代码段全部解析,PC端收到POC的影响进行了三次群名称修改且名称不同,第一次修改可能也将闭合字符后续的代码段解析。

具体实现和步骤无,只是记录下自己发现的小问题,这个点能触发什么利用也在此不做讨论。

image

Shadowsocks/Vmess到底怎么选?安全性如何?

Shadowsocks/Vmess到底怎么选?安全性如何?

image

起因

入冬后,准确来说是在秋季,就感觉原来的小机场偶尔会出现大批节点无法连接的情况,今年1月底到期,在考虑几年了是否该更换跑路,不过好在相对便宜,故障一会就好,还能接受。

然而在将要到期的前几天的时间点上,它刚好又出现了中断,且持续了近1个小时,这对打工人来说不太能接受了,于是便舍弃了原来的小机场,投奔朋友推荐的更大一家。

image

但这里有两个问题,一个是用什么代理软件,第二个是用什么代理协议,这两个问题是逐步浮现的。

代理软件

由于个人职业与所处行业原因,接触墙外比较早(小时候到外服体验新版本游戏),也在之前就尝试自己搭过VPS,详见Try-for-V2Ray,后来由于Vultr质量真的不堪入目、WS+TLS需要的域名证书也是一笔费用且麻烦(才不是懒),项目算是咕掉了,但其中学习到的知识与相关技术还没全忘,用到的各种代理软件也还是多的。

Clash

你要我从中选择,移动端PC端我都会毫不犹豫的选择Clash,谁能拒绝可爱猫猫?但是,可爱猫猫在2023年11月寄掉了!与之相关的Core、Pro、X等都闻风而逝(只猫,影逝二度),仅留下永远停止更新的本地客户端。

image

虽然现在才1月底,最后一次release在3个月前,但时间越长,对于一个曾开源项目来说就越危险,必须要有可行的安全性选择(我也曾考虑过不这么麻烦,直接用之前的不就好了,然后我在互联网上“看着不错还蛮正经”的网站上获取的ClashX远程服务端口就被修改过了)。

V2rayU

撰写此文时,我新入职的公司使用的是MAC M2办公,在第一家公司就使用MAC的我并无什么不适应,但是ClashX在我入职前就化作灰烬,我在换机场前就已经在使用V2rayU,这是个专走Vmess协议的Proxy,虽然repo已有两年未更新了,但是release其实作者一直在偷偷更新。

image

然而,当我切换到新的机场订阅时,却发现机场节点的一句提醒:

因V2ray重大漏洞问题,暂时下架全部V2节点。请使用ssr/ss连接方式进行使用

image

代理协议

所以这是怎么回事?

我依稀记得我玩个人VPS那些年还在传VMESS协议更加安全,V2ray可以用更多的传输配置才对啊?这个重大漏洞是什么,CVE编号多少?(啊,这就是职业病)

V2ray重大漏洞

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

漏洞的描述简单来说就是:

v2ray的TLS流量可被简单特征码匹配精准识别,vmess协议设计和实现缺陷可导致服务器遭到主动探测特征识别

这两方面的问题不论哪个都会使得用V2ray作为Proxy、VMESS作协议进行传输的墙外访问方式被轻松识别到,虽然不同于传统安全漏洞,但确实是严重问题。

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

截止本文撰写,V2ray-Core的最新release已经到5.12.1,可是这个问题应该早已经被修复了,为什么现在订阅还有这样的提示,不让使用VMESS协议?

image

如何选择

绕一大圈,让我们回到文章的主标题:

Shadowsocks/Vmess到底怎么选?安全性如何?

先说结论:它们最新版本的实现都是安全的,也都是不安全的

image

为什么这么说?

对于这两种协议甚至更多种的传输协议,想要去了解它的具体实现及传输形式并不难,以Shadowsocks为例,在Shadowsocks协议解析一文中有清晰明了的叙述,Vmess你也应该都能找到类似的内容。

Shadowsocks/Vmess都会采用一定的加密算法,将传输内容进行加密,在浅谈一下Shadowsocks和VMess的安全性一文的评论中,enfein有提到“shadowsocks 协议现阶段还是安全的,但 VMess 在一些领域做得更好,例如使用依赖于时间的密钥生成办法”,这也佐证了我最初认为Vmess协议的安全性设计比Shadowsocks好的看法,那就能说明Vmess安全性更好吗?

image

主要漏洞

我们回忆一下前文提到的“V2ray重大漏洞”,虽然没有被直接破解出传输内容明文,但能精确地探测标识proxy服务器,与在黑暗森林中点火且大喊无异。

那么Shadowsocks有这样的问题吗?

浅谈一下Shadowsocks和VMess的安全性的原文中,作者例举了两个Shadowsocks的相关漏洞:

Shadowsocks AEAD 加密方式设计存在严重漏洞,无法保证通信内容的可靠性

shadowsocks redirect attack exploit

前者也会使proxy服务器因为流量特征被标识而封禁,后者则更致命地可导致传输内容密文被解析。

image

最佳实践

既然大家都是卧龙凤雏,有什么不那么烂的方式吗?

首先要明确的是,最新版本的协议都已经将已知漏洞修复,可以认为两者安全性相近,也都有可能被流量分析与主动探测(即使你采取了防范与伪装)。

针对Shadowsocks,防御GFW主动探测的实用指南一文中指出了Shadowsocks理应达到的最佳实践;相应的,Vmess支持和TLS组合,也可以实现动态端口等,这些在我搭建VPS的时候就已经是个人可以不算复杂的实现了。并且在【还Shadowsocks一个清白】Shadowsocks是如何被检测和封锁的,兼谈ss配置策略一文中,也有提到可以采用国内转国外双重代理的方式,规划ip白名单,规避一些探测(但文章内容主观性较强,观点接纳需分别):

image

此外,在搭建与使用的过程中,不能过分信任某些教程,并不是说它们的方法有问题,而是很多一键部署的脚本为了运行的稳定性与一致性,是写死了引用版本的,那么就很有可能还在利用存在漏洞的协议版本;同时也需要注意客户端的选择,个人现在使用的是Clash Verge Rev(回来吧我的牢猫!),Clash Verge的原repo也因为2023年11月的风波停止更新,Rev是抛弃了原Clash Core(repo removed)采用mihomo重新构建并仍在更新的版本。

image

那为什么不使用V2ray相关的客户端?

一方面是新的机场不支持Vmess(前情提要),一方面是V2ray Core做出的客户端确实没有猫猫可爱(猫猫也支持Vmess等多种协议),再一方面是有些V2ray的客户端的最新release用的Core版本仍处于风险版本(V2rayU:所以爱是会消失的对吗?)

image

机场顾虑

最后一个问题,既然Shadowsocks和Vmess都可以,为什么有些机场不提供Vmess节点了?

这个问题在关于科学上网的流行说法一文中可见一斑:

  • 大部分机场都是中转线路,使用 V2RAY 显得太重,消耗服务器资源大
  • V2RAY在防标识的场景下相比已经搭好的Shadowsocks没有明显优势

所以对于机场线路,公网隧道、专线,没有一定要再采用哪种协议的需求,更多地在考虑带宽等费用与访问流畅度。此外,机场躲避封锁的方式,在文章中也有谈及,同时文章中也有谈到订阅转换的技术,在一些机场也有提供(在逐渐收敛)。

个人小注

对于浏览访问来说,机场提供的服务已经完全够用,除了不能登录服务器进行配置这部分不便,这也是我为什么暂时放弃了自己搭建VPS的想法;

但对于未来的渗透测试来说,虽然简单的OOB可以Dnslog/Ceye,但如果要弹shell,或者境外测试,就还是需要国内云与国外云的服务,这些机场就完全无法支持了。

image

参考引用

Try-for-V2Ray

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

Shadowsocks协议解析

浅谈一下Shadowsocks和VMess的安全性

Shadowsocks AEAD 加密方式设计存在严重漏洞,无法保证通信内容的可靠性

shadowsocks redirect attack exploit

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

【还Shadowsocks一个清白】Shadowsocks是如何被检测和封锁的,兼谈ss配置策略

关于科学上网的流行说法