Aliexpress LTE / 4G Stick hacking - Part 2
In my previous post, we started to play a little bit with a cheap LTE stick from Aliexpress.
We identified the APK responsible for serving the limited Web-UI and keen eyes might have spotted something unusual:
So this APK claims to be signed by Google (well, ‘Android’) which seems odd. Well, not really:
$ adb shell getprop ro.build.description
msm8916_32_512-user 4.4.4 KTU84P eng.qwang.20220611 test-keys
Did you notice something? Yes: test-keys.
What are test-keys?
Android OTA packages are signed using a ‘platform key’ which should usually be kept secret.
If you try to update a package, Android will check if the update has been signed with the same key and - if not - reject the update. For convenience, AOSP comes with a set of test-keys which are (semi automatically) used to sign OTA packages during development. Developers are supposed to provide their own keys for releases, but seems like the manufacturer of this device couldn’t be bothered to do so.
Well, that’s handy for us because - if my theory is correct - we can just grab the AOSP test keys and install a patched update. All without requiring any special privileges.
Fetching the test keys
First, we need to clone one of the AOSP repos and convert the platform test keys to something that can be used by jarsigner
:
$ git clone https://android.googlesource.com/platform/build
$ cd build/target/product/security/
$ openssl pkcs8 -inform DER -nocrypt -in platform.pk8 -out platform.pem
$ openssl pkcs12 -export -in platform.x509.pem -inkey platform.pem -out platform.p12 -password pass:android -name testkey
$ keytool -importkeystore -deststorepass android -destkeystore platform.keystore -srckeystore platform.p12 -srcstoretype PKCS12 -srcstorepass android
$ mv platform.keystore /tmp/LTE
Modifying the APK
We are now the proud owner of some test keys. Lets see if we can use them to sign an update.
First, we need to install APKTool which we will use to decompile and repackaging.
Unpacking the APK
This is as simple as running:
$ java -jar apktool.jar d Jetty2m.apk -o JETTY
Then we use Gimp to modify ./assets/jetty/img/header.jpg
and change the APK version number in apktool.yml
:
$ git diff
diff --git a/JETTY/apktool.yml b/JETTY/apktool.yml
index 83e4507..b5d4226 100644
--- a/JETTY/apktool.yml
+++ b/JETTY/apktool.yml
@@ -95,4 +95,4 @@ usesFramework:
version: 2.7.0
versionInfo:
- versionCode: '1'
- versionName: '1.0'
+ versionCode: '2'
+ versionName: '2.0'
Repackage and sign
Repackaging the APK is done via:
$ java -jar apktool.jar b -o unsigned.apk JETTY
But before we can install our ‘update’, we should zipalign and (of course!) sign it:
$ zipalign -v 4 unsigned.apk aligned.apk
$ jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore ./platform.keystore aligned.apk testkey
Installing the update
$ adb install -r aligned.apk
Performing Push Install
aligned.apk: 1 file pushed, 0 skipped. 1962.0 MB/s (684517 bytes in 0.000s)
pkg: /data/local/tmp/aligned.apk
Success
Well, that already looks pretty good. But does it work?
Let’s find out by adb reboot
ing the device and checking:
Yay! Not only did Android accept our homegrown update, it also happily executed it.
This means that it will also be possible to modify the java bytecode of the package and hence execute our own code, something we will do in the next article of this serie.