1

喵喵机折腾记

 2 years ago
source link: https://www.ihcblog.com/miaomiaoji/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

也发点存货吧。这个是去年7月份做的一些工作,现在应该有些已经失效了。

去年暑假发现了喵喵机这个东西,作为一个折腾小能手,搞了点喵喵机相关的逆向和开发。 所有东西见: https://github.com/ihciah/miaomiaoji-tool

喵喵机是个蓝牙热敏打印机,可以直接利用它的 App 走蓝牙连接并打印。之前在微博看到了 DIYGOD 折腾了一个远程推送打印,也想搞一个类似的东西,可是我并不想一直手动戳着手机。考虑到手头有一个树莓派3,带蓝牙功能,于是决定拆了喵喵机的 App ,拿到通信协议,然后在树莓派上起控制脚本。

dce4ccef2e6f24f1a076d00d4c3a6a7893629d69.jpg

App 逆向

这部分本来懒得拆的,只想拿到蓝牙日志猜一猜的,找了个安卓手机搞,果然没猜出来==

那就拆 Apk 吧。下了最新的 Apk 和好几个旧版本,发现都有 360 加固,就很烦。后来折腾了一波虚拟机脱壳,就是在系统加载 dex 的时候把 dex dump 出来。蛮通用的做法,毕竟现有加固就和多年前的 PC 应用加壳一样,加载时动态解密代码放内存,只要找到 OEP 然后 dump 即可。在安卓里,加载 dex 时 dump 就可以拿到加固的内容。

当然,除了 dex ,这款 App 还有一点点的 Native 代码,拖 IDA 里可以拿到一个 key。这个稍后再讲。

我们先 Focus 蓝牙通信部分。在看了这么多垃圾代码(自带天然人工混淆)后,逆出了通信协议:

(1 byte) 2
(1 byte) 控制命令
(1 byte) 当前 payload 包序列号
(2 byte) payload 长度
(n byte) payload
(4 byte) payload 的 CRC32 校验码
(1 byte) 3

当 payload 过长时,拆成长度不大于 2016 的多个包,依次发送。

其中, CRC32 校验码的初始值为 crcKey = 0x35769521。控制命令包括 PRT_PRINT_DATA 等,数字常量,1.0.2 版本 Apk 中有 26 个, 2.0.3 版本中增加到 47 个,向下兼容。

机器返回的消息同样遵循上述协议,当最后一个包的 command 字段为 \x00 的时候表示信息发送完毕。

这时候我们只需要使用 Python 等语言复现一遍协议即可。

这里我实现了一个图片打印接口,然后在微信公众号后台接收图片,发送至树莓派自动进行打印。

微信端 喵喵机端(microUSB纯粹充电用)

7db77cfd18129c35d136434819eceed5ebb66e96.png35da7e0c447f1f9afb6147e7f54d214cf9e491ee.jpg

另附几个折腾样例:

不同深度的打印测试页 失败样例

8c98eba8092bc83eb8f1b428812b52c6d503e88a.jpg4e599738d0881e7b96e7712c8bd214ea95f90728.jpg

服务端通信

POST /api/ap/Login HTTP/1.1
ts: 1502784192
sign: b71a3f80dab036e3110532590972961e
Accept-Encoding: gzip, deflate
Connection: close
Accept: **/*//*
userId: 1758717881
language: zh_CN
User-Agent: paperang_mm_android
Content-Type: application/x-www-form-urlencoded
Content-Length: 442
Host: ifs.mm.paperang.cn
msg=xxxxxxx
  • tstime.time() 取整
  • sign 为字符串 userId=xxx&msg=xxx&ts=xxx&signKey=ab69a9d9-94a5-4111-9554-00af2917732f 的小写 MD5
  • msg 在签名字符串中为一串json:
    {"ip":"","language":"CN","remark":"{\"brand\":\"samsung\",\"device\":\"SMA3000\",\" os\":\"and\",\"release\":\"5.0.2\",\"baseObjId\":0}","userName":"[email protected]","userPassWord":"md5_of_password","type":1,"
  • 消息正文中的 msg 为原始 msg (即上文提到的 json 串,下记作msg_original )经加密后组成的 json 串(需 urllib.quote ,但 ios 版app抓包后发现似乎不quote也行?)
  • 原始消息:
    {"swType":"mmj_p1_fw"}
    奇怪的AES加密:
    QpJ42KMTg1f9msKsG5Xz3JY5nGL0UVQWZtAcFRG5dA8=
    组成json串:
    {"parameter":"QpJ42KMTg1f9msKsG5Xz3JY5nGL0UVQWZtAcFRG5dA8\\u003d\\n","baseObjId":0}
    转码:
    %7B%22parameter%22%3A%22QpJ42KMTg1f9msKsG5Xz3JY5nGL0UVQWZtAcFRG5dA8%5Cu003d%5Cn%22%2C%22baseObjId%22%3A0%7D
  • AES 加密算法采用 AES_ECB ,逆向 libalf_h_sdkcore.so 可以得到key: f3e15c3a845d48dc ( classes.dex 文件中也包含该密钥),输出时使
    b64encode ,特殊的是还需要将所有 + 替换为 -

响应包为 {"data":"xxxxx"}json 串,其中data 的值也遵循上面提到的奇怪的AES ,进行逆操作即可得到未加密的 json 响应。

from Crypto.Cipher import AES
import base64
def decrypt(msg):
msg = base64.b64decode(msg.replace("-", "+"))
c = AES.new("f3e15c3a845d48dc", AES.MODE_ECB)
return c.decrypt(msg)

手机 App 加载图片等资源通过阿里云 OSS SDK 加载,很奇怪的是 Burp 中未出现。应该是没有走系统 HTTP 代理,于是还是上 wireshark 。抓包得到这些请求都
是使用了 BUCKETID
mb-mm 内的文件,该 BUCKET 为私有 BUCKET ,需要 OSSAccessKeyIdSignature
按理说这个签名应该在服务器端做,但是尝试在 iOS上下载字体,从服务器上却没有返回任何签名,那么可以断定签名是在 App 内部做的。查看 App 的相关代码
和阿里云 OSS 的 Android SDK ,可以通过 OSSPlainTextAKSKCredentialProvider 设置 AccessKeyIdAccessKeySecret ,于是得到:

AccessKeyId: LTAIrPvoTOwid4QD
AccessKeySecret: 5xxJHjKmgMEFaqXhb3VZ2QrkcFRWde

之前抓包并解密后得到最新固件名: mmj_p1_fw_v127.bin ,打算尝试从OSS下载;现在直接下载到所有历史版本的APK和固件了2333333。

也就是说,如果我们生成了符合签名的固件并替换上去,可以让所有喵喵机在更新固件之后变砖=。= 或者加进去一些后门代码== 并且,该 OSS 内还有所有用户远程打印的图片,如果你仔细探索,会发现一些奇♂怪的图(捂脸)。

另外,在测试过程中也发现了一些注入漏洞。如:

POST /AjaxSub/GetSubscriptionCategory
typeId=2-1

我们可以直接得到表名:

Database: mm_subscription_db
t_examineimagecache - 4829
t_material - 30459
t_materialcollectionconfig - 550402
t_materialgroup - 717
t_materialgroupconfig - 23593
t_materialoperationrecords - 3866621
t_message - 0
t_subcontentoperationrecords - 214243
t_subscription - 507
t_subscriptioncategory - 10
t_subscriptioncheck - 901
t_subscriptioncontent - 5642
t_subscriptionmaterial - 115
t_subscriptionrecord - 505050
t_subscriptionuserconfig - 396411
t_subscriptionusergroup - 6

一番尝试后并没有分析出固件格式或者是入口点,但是在观察hex数据时发现 YC1021 字样,搜索发现这个是蓝牙芯片名称。
第二天拆了机器,找到了芯片制造商 Nuvoton ,芯片型号 NUC123LD4BN0 ,使用的处理芯片是 STM32F071CBU6Cortex M0 架构。
IDA按照ARM6M 格式载入,发现似乎还能看,搜索立即数0x180 ,该数字十进制表示为384 ,即每行的像素数。

SRAM_BASE = 0x20000000

固件修改后可以通过两种方式上传,一种是 Nuvoton 所支持的 ISP ,被固件本身实现为蓝牙上传后调用接口更新;另一种是 USB 上传。考虑到改错的话蓝牙方式更新固件后可能会GG,所以先确保USB上传固件方式可以工作。
于是找到官网,然而又打出GG,需要编程器刷入。。。

本打算修改固件,让机器接受灰度图,然后能将吐出去的纸吃回去,多次打印来实现有深浅区别的打印。然而凉了呢。有 dalao 愿意改的话求戳。

另: 某小哥一年前曾因逆向喵喵机戳过我,现在…emmm去了这家公司。。感觉也是很神奇。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK