无意间找到受密码保护的工程模式,该模式需在”更新”按钮左侧轻按5次,再在右侧轻按两次即可出现:
但是,尝试所有公开的默认密码(1200、2400、3802、当前时间等)均不正确。
于是决定自己下载固件,并尝试逆向。
固件更新
固件可从update.hyundai.com获取。固件必须下载并安装导航更新程序,然后选择车型。更新程序会下载所有文件并准备SD卡或USB驱动器。给公司的现代测试汽车下载了23GB的数据,其中包括导航更新和固件。USB驱动器的根文件夹中有2018_20_Tucson_EU.ver文件,其中列出了更新中的所有文件:
每个文件都有其目录、名称、CRC32(带符号的32位整数)和大小。很快发现有一个有意思的文件:2018_20_Tucson_EUDAUDIOPLUS_Meurtlflupdatesystemupdate_package.zip,这是一个加密压缩包:
尝试使用greenluigi1文章中发现的密码(ahqltmTkrhk2018@@)解压缩,但并未成功。
破解压缩密码
决定尝试使用与greenluigi1文章中相同的破解工具bkcrack进行破解密码。bkcrack实现了EliBiham和PaulC.Kocher发现的已知明文攻击。该攻击需要至少12个字节的明文。加密压缩包包含两个压缩文件。那么什么是已知明文的最佳候选呢?当然是ZIP文件头!为以下形式:
update_package.zip中的两个压缩文件都是在未压缩的情况下存储的(已经压缩的文件没有必要再压缩)。可以用以下命令来验证这一点:
bkcrack -L update_package.zip
bkcrack 1.5.0 - 2022-07-07
Archive: update_package.zip
Index Encryption Compression CRC32 Uncompressed Packed size Name
---------- ----------- -------- ------------ ------------ ----------------
0 ZipCrypto Store fbe57f09 227492981 227492993 update.zip
1 ZipCrypto Store b4be54fe 1203 1215 otacerts.zip
现在只需猜测update.zip或otacerts.zip文件头的12个字节,就可以实施攻击。前10个字节没有太多选择。前4个字节是固定的(504b0304)。版本字节在大多数情况下是1400或0a00。假设嵌套压缩包未加密,通用位标志应为0000。压缩方法为0000(存储)或0800(deflate)。因此,前10个字节有以下几种变体:
我们还需要两个字节,候选字节要么是文件修改时间,要么是文件修改日期。时间的存储单位是秒除以2的精度,因此有24*60*30=43200种可能性。假设文件修改发生在过去5年,那么日期字段就有5*365=1825种可能性。显然,对日期字段进行暴力破解更有效。但是在我的笔记本电脑上运行一次这种攻击需要30分钟,因此暴力破解是不可行的。是时候再做一次大胆的猜测了。update.zip和otacerts.zip的文件修改日期都是”2022年4月21日”。假设otacerts.zip中第一个文件条目的修改日期也是”2022年4月21日”。这个日期在MS-DOS格式中编码为9554。现在有12个字节的纯文本,但它们并不连续,因为跳过了文件修改时间。好在bkcrack支持使用-x选项指定偏移量。使用plain1.bin进行的第一次攻击失败了。不过,通过plain2.bin,成功恢复了密钥:
$ bkcrack -C update_package.zip -c otacerts.zip -p plain2.bin -x 12 9554
bkcrack 1.5.0 - 2022-07-07
[15:03:29] Z reduction using 3 bytes of known plaintext
100.0 % (3 / 3)
[15:03:29] Attack on 1677473 Z values at index 6
Keys: 850725d9 64202f01 143f9452
2.8 % (47031 / 1677473)
[15:04:05] Keys
850725d9 64202f01 143f9452
解压压缩文件:
$ bkcrack -C update_package.zip -c update.zip -k 850725d9 64202f01 143f9452 -d update.zip
$ bkcrack -C update_package.zip -c otacerts.zip -k 850725d9 64202f01 143f9452 -d otacerts.zip
otacerts.zip压缩包中包含一个于2022年4月21日修改的X509证书:
update.zip包含的内容:
逆向固件
显然,测试车运行的是安卓系统,system.ext4是根文件系统。尝试挂载并查看里面的内容:
$ mkdir /tmp/car
$ sudo mount -t ext4 -o loop system.ext4 /tmp/car
$ ls -la /tmp/car
total 140
drwxr-xr-x 14 root root 4096 Jan 1 1970 .
drwxrwxrwt 25 root root 65536 Aug 11 15:40 ..
drwxr-xr-x 2 root root 4096 Apr 21 10:50 app
drwxr-xr-x 2 root 2000 4096 Apr 21 10:46 bin
-rw-r--r-- 1 root root 6020 Apr 21 10:26 build.prop
drwxr-xr-x 11 root root 4096 Apr 21 10:50 etc
drwxr-xr-x 2 root root 4096 Apr 21 10:35 fonts
drwxr-xr-x 2 root root 4096 Apr 21 10:50 framework
-rw-r--r-- 1 root root 1912 Apr 21 10:35 key_3000000.psr
-rw-r--r-- 1 root root 1913 Apr 21 10:35 key_921600.psr
drwxr-xr-x 8 root root 8192 Apr 21 10:46 lib
drwx------ 2 root root 4096 Jan 1 1970 lost+found
drwxr-xr-x 4 root root 4096 Apr 21 10:35 media
drwxr-xr-x 7 root root 4096 Apr 21 10:38 usr
drwxr-xr-x 4 root 2000 4096 Apr 21 10:35 vendor
drwxr-xr-x 2 root root 4096 Apr 21 10:35 wifi
drwxr-xr-x 2 root 2000 4096 Apr 21 10:45 xbin
几乎所有应用程序都在/app文件夹中。每个应用程序都有.apk和.odex,例如
$ ls -l /tmp/car/app/HKMC_EngineerMode.*
-rw-r--r-- 1 root root 2124079 Apr 21 10:50 /tmp/car/app/HKMC_EngineerMode.apk
-rw-r--r-- 1 root root 1630136 Apr 21 10:50 /tmp/car/app/HKMC_EngineerMode.odex
尝试使用baksmali将odex文件转换为smali,用jadx将smali反编译为Java。先看看工程模式的应用程序,然后再看看软件更新。
java -jar baksmali-2.5.2.jar deodex -a 17 -d /tmp/car/framework -o engmode /tmp/car/app/HKMC_EngineerMode.odex
java -jar baksmali-2.5.2.jar deodex -a 17 -d /tmp/car/framework -o swupdate /tmp/car/app/HKMC_SwUpdate.odex
工程模式密码
工程模式密码通过com.hkmc.system.app.engineering.ime.InputPasswordExt的getKeyString()方法获取。该方法获取当前年份的最后一位数字,然后进行资源查找:
这些是相应的资源字符串:
今年的密码是2702。我在测试车上试了一下,成功了:
软件更新密码
虽然可以用bkcrack提取固件更新的密钥,但我还是很想知道update_package.zip的密码。通过简单的grep搜索”update_package.zip”,我找到了com.hkmc.system.app.swupdate.ImageFileCopy的getPassword()方法:
静态密码”+Ekfrl51Qkshsk#@zpdhkdWkd~-f”不起作用。密码是由以下系统属性连接而成的:
SHA512Checking()方法计算给定字符串的SHA512摘要,并将结果返回为大写十六进制字符串。这样做两次并获取一个子串:
SHA512Checking(SHA512Checking(tmp1)).substring(10, 38) = "15DAA85C8D44B3979CD152A387F6"
密码是15DAA85C8D44B3979CD152A387F6
后续
可以确定可使用后门创建一个固件更新,并可获得一个root shell。但有可能会导致测试车出现不可预测的问题,所以暂时不敢尝试。
原文始发于微信公众号(安全脉脉):现代 Tucson破解