也可移步Hor1zon公众号
https://mp.weixin.qq.com/s/aXr3E1THtLmYbAFnYnuCPA
D3_car_flag1
题目环境太垃圾了,安卓环境一直断😅
其实很简单,一开始有点懵,想加个监看进去看看,日过车的都知道scrcpy是个好工具😋
https://github.com/Genymobile/scrcpy
可是这个环境真的太卡了,上了scrcpy之后那是一点就断;背景这几个字暗示了要找到车的GPS数据,但是这个导航怎么点都点不开,还老是断服务,后边发现根本没装车载导航(地图)服务;
所以还是接着命令行操作,先来看一下应用列表 哎 您猜怎么着?
一眼就看到了一个非常可疑的APP
package:com.d3car.factory
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 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
| generic_x86_64:/ $ pm list packages package:com.android.cts.priv.ctsshim package:com.android.car.messenger package:com.android.providers.telephony package:com.google.android.car.kitchensink package:com.android.providers.calendar package:com.android.providers.media package:com.android.wallpapercropper package:com.android.car.media package:com.android.car.radio package:com.android.car.trust package:com.android.documentsui package:com.android.externalstorage package:com.android.htmlviewer package:com.android.companiondevicemanager package:com.android.quicksearchbox package:com.android.mms.service package:com.android.providers.downloads package:com.android.car.overview package:android.car.cluster.loggingrenderer package:com.android.defcontainer package:com.android.car.mapsplaceholder package:com.android.providers.downloads.ui package:com.android.pacprocessor package:com.android.certinstaller package:com.android.carrierconfig package:android package:com.android.contacts package:com.android.camera2 package:com.android.car.systemupdater package:com.android.car package:com.android.egg package:com.android.mtp package:com.android.nfc package:com.android.backupconfirm package:com.android.provision package:com.android.statementservice package:com.android.calendar package:com.android.systemui.theme.dark package:com.android.car.hvac package:com.android.providers.settings package:com.android.sharedstoragebackup package:com.android.printspooler package:com.android.dreams.basic package:com.android.car.dialer package:com.android.webview package:com.android.inputdevices package:com.android.support.car.lenspicker package:com.android.bips package:com.android.musicfx package:com.android.cellbroadcastreceiver package:android.ext.shared package:com.android.onetimeinitializer package:com.android.server.telecom package:com.android.keychain package:com.android.printservice.recommendation package:com.android.gallery3d package:android.ext.services package:com.android.calllogbackup package:com.android.packageinstaller package:com.android.carrierdefaultapp package:com.svox.pico package:com.android.car.media.localmediaplayer package:com.android.proxyhandler package:com.android.inputmethod.latin package:org.chromium.webview_shell package:com.d3car.factory package:android.car.usb.handler package:com.android.managedprovisioning package:com.android.dreams.phototable package:com.android.smspush package:android.car.cluster.sample package:com.android.wallpaper.livepicker package:com.android.storagemanager package:jp.co.omronsoft.openwnn package:com.android.bookmarkprovider package:com.android.settings package:com.android.calculator2 package:com.android.cts.ctsshim package:com.android.vpndialogs package:com.android.email package:com.android.music package:com.android.phone package:com.android.shell package:com.android.wallpaperbackup package:com.android.providers.blockednumber package:com.android.providers.userdictionary package:com.android.emergency package:com.android.location.fused package:com.android.deskclock package:com.android.systemui package:com.android.bluetoothmidiservice package:com.android.bluetooth package:com.android.providers.contacts package:com.android.captiveportallogin generic_x86_64:/ $ generic_x86_64:/ $ generic_x86_64:/ $ generic_x86_64:/ $ pm path com.d3car.factory package:/system/priv-app/D3Factory/D3Factory.apk generic_x86_64:/ $
PS G:\> adb pull /system/priv-app/D3Factory/D3Factory.apk /system/priv-app/D3Factory/D3Factory.apk: 1 file pulled, 0 skipped. 0.1 MB/s (38128 bytes in 0.354s)
|
简单逆向就可以找到flag了)
1 2 3 4 5
| <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:gravity="center" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:textSize="@dimen/common_textsize_24" android:id="@+id/flag1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dp" android:text="d3ctf{yes_you_f1nd_b4ckdo0r}"/> <Button android:id="@+id/tcpdump" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="open/close tcpdump"/> </LinearLayout>
|
也可以用另一种方法,直接拉起应用的Activity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| generic_x86_64:/ $ dumpsys package com.d3car.factory | grep -i activity Activity Resolver Table: 4d5331e com.d3car.factory/.FactoryActivity filter 1beb95a b8e17ff com.d3car.factory/.PwdAuthActivity filter ee66505 b8e17ff com.d3car.factory/.PwdAuthActivity filter ee66505 android.permission.USER_ACTIVITY: granted=true android.permission.MANAGE_ACTIVITY_STACKS: granted=true android.permission.USER_ACTIVITY: granted=true android.permission.MANAGE_ACTIVITY_STACKS: granted=true generic_x86_64:/ $ generic_x86_64:/ $ generic_x86_64:/ $ generic_x86_64:/ $ am start -n com.d3car.factory/.FactoryActivity Starting: Intent { cmp=com.d3car.factory/.FactoryActivity } generic_x86_64:/ $ generic_x86_64:/ $ generic_x86_64:/ $
|
D3_car_flag2
1 2
| PS G:\> adb pull /system/priv-app/ #我甚至把所有的app都拖了下来) PS G:\> adb pull /system/priv-app/D3Factory/oat/x86_64
|
这里一开始是先去把odex转成dex
利用了baksmali-2.5.2.jar和smali-2.5.2.jar,转成的dex发现只还原了方法名,里面的核心的代码根本看不到,再试试把vdex转成dex,windows环境及其不友好,最后在ubuntu虚拟机完成了还原
所需要的工具为:https://github.com/anestisb/vdexExtractor
🤗项目下载下来后直接./make.sh gcc编译就行,然后会在bin目录下生成vdexExtractor文件😚
执行命令:./vdexExtractor -i xxx.vdex -o ./
最后jadx打开该dex,即可看到核心代码
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
| package com.d3car.factory;
import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast;
public class PwdAuthActivity extends Activity { private Context mContext; private Button mEnterBtn; private TextView mKeyText; private EditText mPwdText;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(2130837504); this.mPwdText = (EditText) findViewById(2131165185); this.mEnterBtn = (Button) findViewById(2131165186); this.mKeyText = (TextView) findViewById(2131165184); this.mContext = getApplicationContext(); Log.d("D3CTF", "onCreate: "); this.mEnterBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { PwdAuthActivity.this.verifyPWD(PwdAuthActivity.this.mPwdText.getText().toString(), PwdAuthActivity.this.mKeyText.getText().toString()); } }); }
public void verifyPWD(String pwd, String key) { if (pwd.length() == 0) { Toast.makeText(this, getString(2131099707), 0).show(); } else if (verifyPassWord(pwd, key)) { Log.d("D3CTF", "verifyPWD: the password is right!"); startActivity(new Intent(this, FactoryActivity.class)); } else { Toast.makeText(this, getString(2131099706), 0).show(); } }
public static boolean verifyPassWord(String password, String key) { if (key == null || key.isEmpty()) { return "20240419".equals(password); } return "uVQPRRYTrpvqvCv6".equals(encryptPwdByKey(password, key)); }
public static String encryptPwdByKey(String pwd, String key) { char[] pwd_arr = pwd.toCharArray(); char[] key_arr = key.toCharArray(); char[] result = new char[pwd.length()]; for (int i = 0; i < pwd.length(); i++) { result[i] = (char) (pwd_arr[i] ^ key_arr[i % pwd.length()]); } return new String(result); } }
|
验证代码的核心在这里,其实逆向逻辑还是很简单,就是一个异或,但是这里的数据真是诱导了我,看这里的逻辑是传入了key和密码。因为即使要逆向,这两个数据你得有一个才行,一开始我以为这个20240419是key,然后逆向出密码,发现不对,这就不得不开始看一下代码的整体逻辑
这个TextView?再来看看登录页面
key就是屏幕上的字符串😂,然后直接梭脚本就行
1 2 3 4 5 6 7 8 9
| data="uVQPRRYTrpvqvCv6" key="D2036445ADCGF12W7" pwd="" for i in range(len(data)): pwd+=chr(ord(data[i])^ord(key[i])) print(pwd)
|
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
| package com.d3car.factory;
import android.app.Activity; import android.os.Bundle; import android.os.SystemProperties; import android.widget.CheckBox; import android.widget.CompoundButton; import java.io.IOException;
private CheckBox mTcpDump;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(2130837506); this.mTcpDump = (CheckBox) findViewById(2131165189); if (SystemProperties.getInt("sys.tcpdump", 0) == 1) { this.mTcpDump.setChecked(true); } else { this.mTcpDump.setChecked(false); } this.mTcpDump.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { SystemProperties.set("sys.tcpdump", "1"); try { Runtime.getRuntime().exec("/system/xbin/tcpdump -i any -s 0 -w /sdcard/tcpdumplog.pcap -W 1"); } catch (IOException e) { e.printStackTrace(); } } else { SystemProperties.set("sys.tcpdump", "0"); try { Runtime.getRuntime().exec("pkill tcpdump"); } catch (IOException e2) { e2.printStackTrace(); } } } }); } }
|
在adb直接使用tcpdump显示被ban了,可以看到程序后门是一个tcpdump服务
用自带的APP后门去抓包,可以看到存在mqtt服务再循环往复的发送同样的包。
抓到MQTT服务的主题&账号&密码(断的太快了 没机会传扫描工具到IVI里面扫😭扫一下应该就能扫到其他ECU了
1 2 3 4 5 6 7
| Client ID Length: 11 Client ID: Gojo_Satoru User Name Length: 11 User Name: abmaM_kcalb Password Length: 14 Password: Ya5_1_n4C_tahW
|
以及两条MQTT的报文,这里的mqtt是在做can的转发,在环境中实现uds的功能
1 2 3 4 5
| Topic: can/514/write Message: 022701ffffffffff #看到2701 血脉觉醒 是UDS服务 这里给了did为514的ecu的pincode
Topic: can/514/write Message: 0527022dcf28ffff
|
环境中应该不存在模拟的CAN总线(向出题人求证了这一点),ivi这里应该是通过mqtt与其他ECU通信,所以可以先用22服务去读其他ecu信息,然后要过掉27服务,进入QNX拿flag,也向出题人求证了这一点,flag果然在QNX里面。这里难点在于确定qnx的did,然后就通过mqtt执行can/ecu id/write
来执行诊断命令;还有就是要把环境代理到本地来发mqtt广播包;
现在没有环境也没法再具体分析操作,看了官方和W&M师傅的wp,感觉总体思路上和我的想法差不多,可以用fscan扫到一些seed2key.dll,也就是27服务密钥算法,逆向得到key,而且qnx还存在31服务,后边的过程参考W&M师傅的wp,写的很细🫡
https://blog.wm-team.cn/index.php/archives/75/#D3+car+2
D3_car_flag3
无地图服务的背景提示联想到flag应该和GPS有关
前面查看应用包发现有一个com.android.location.fused
的APP,这里我的思路有点偏了)我跑过去研究这个APP,考虑从这个app中拿到gps定位,但我再也没连上过靶机😭也无法验证是否可行。
和前面一样,把odex转成dex,可以看到车机是由GPS服务的,只是需要一个APP去调用GPS权限即可拿到定位信息,下一步想法就是搞一个地图/定位APP adb install上去来获取经纬度信息。
从车机安全性考虑,一般都会采用私有证书签名,在/system/etc/security
找到了车机的证书信息,通过伪造签名证书就可以让APP安装到车机上面了。
看了W&M师傅的wp真的给跪了,通过相机调用GPS信息再来拿到经纬度信息的想法真的太绝了Orzzzzzz
我倒是也打开过车机设置APP但他真的太卡了🥲基本上点两下就会断线,我就得再次启动安卓服务,然后他再次断线😭
由于环境无了,这里引用凌武出题人师傅的截图,装好定位APP就可以拿到经纬度了。
因为目前国内的车载地图服务商除了特斯拉基本都是高德,所以直接去高德搜索经纬度
然后再保利·江语海东南门这里看到出题人的用户评价,进个人主页就可以拿到flag了。