Aliexpress LTE / 4G Stick hacking
I recently decided that i “need” an LTE USB stick to tinker around with, so i visited Aliexpress and bought one of the many available cheap devices.
Weeks later, i was the proud owner of this thing:
First impressions
After plugging the device in, it appears as an ‘Android’ device, which is - interesting.
$ lsusb |grep Android
Bus 001 Device 017: ID 05c6:9024 Qualcomm, Inc. Android
$ dmesg | grep usb
[20388.606115] usb 1-2.4: new high-speed USB device number 16 using xhci_hcd
[20388.684301] usb 1-2.4: New USB device found, idVendor=05c6, idProduct=9091, bcdDevice=ff.ff
[20388.684309] usb 1-2.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[20388.684311] usb 1-2.4: Product: Android
[20388.684313] usb 1-2.4: Manufacturer: Android
[20388.684314] usb 1-2.4: SerialNumber: 1234567890ABCDEF
[20425.758881] usb 1-2.4: USB disconnect, device number 16
[20425.935886] usb 1-2.4: new high-speed USB device number 17 using xhci_hcd
[20426.013250] usb 1-2.4: New USB device found, idVendor=05c6, idProduct=9024, bcdDevice=ff.ff
[20426.013264] usb 1-2.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[20426.013270] usb 1-2.4: Product: Android
[20426.013274] usb 1-2.4: Manufacturer: Android
[20426.013277] usb 1-2.4: SerialNumber: 1234567890ABCDEF
[20426.017802] rndis_host 1-2.4:1.0 usb0: register 'rndis_host' at usb-0000:00:14.0-2.4, RNDIS device, 02:0c:08:57:35:38
[20426.029337] rndis_host 1-2.4:1.0 enp0s20f0u2u4: renamed from usb0
As we can see in the dmesg output, the device also provides a ‘virtual’ ethernet interface, so let’s see if it likes us:
$ psa-dhcpc -ifname enp0s20f0u2u4 -default_route=false
psa-dhcpc[enp0s20f0u2u4] 2022/12/18 17:47:04 unconfiguring interface
psa-dhcpc[enp0s20f0u2u4] 2022/12/18 17:47:04 Sending DHCPDISCOVER broadcast
psa-dhcpc[enp0s20f0u2u4] 2022/12/18 17:47:04 ==> waiting for valid reply until 2022-12-18T17:57:04+01:00
psa-dhcpc[enp0s20f0u2u4] 2022/12/18 17:47:06 Accepting offer for IP 192.168.42.53 from server 192.168.42.129
psa-dhcpc[enp0s20f0u2u4] 2022/12/18 17:47:06 ==> waiting for valid reply until 2022-12-18T17:48:06+01:00
psa-dhcpc[enp0s20f0u2u4] 2022/12/18 17:47:07 Running ARPING for 192.168.42.53
psa-dhcpc[enp0s20f0u2u4] 2022/12/18 17:47:07 Configuring interface to use IP 192.168.42.53/ffffff00 via <nil>
psa-dhcpc[enp0s20f0u2u4] 2022/12/18 17:47:07 -> Lease is valid for 1h0m0s
psa-dhcpc[enp0s20f0u2u4] 2022/12/18 17:47:07 -> Renew will happen after 30m0s, must rebind after 52m30s
## Add a route to the IP printed on the back of the device (because we skipped the default route)
$ ip route add 192.168.43.1 dev enp0s20f0u2u4
Cool, so we got an IP and can… access the webinterface?
The webinterface continues to be underwhelming:
We can change the SSID and WIFI password (and the IMEI?!), but there is not option to turn the WIFI off (i don’t want to operate device as a hotspot) and nor can we change the announced DHCP range:
Thats a bummer.
ADB
Since the device identifies itself as an ‘Android’ device, let’s just try adb
:
$ adb shell
shell@msm8916_32_512:/ $ id
uid=2000(shell) gid=2000(shell) groups=1004(input),1007(log),1011(adb),1015(sdcard_rw),1028(sdcard_r),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats) context=kernel
shell@msm8916_32_512:/ $ cat /proc/version
Linux version 3.10.28 (qwang@qwang) (gcc version 4.7 (GCC) ) #1 SMP PREEMPT Sun Jun 12 15:39:30 CST 2022
shell@msm8916_32_512:/ $ ls /data
opendir failed, Permission denied
1|shell@msm8916_32_512:/ $ getprop |grep fingerprint
[ro.build.fingerprint]: [qcom/msm8916_32_512/msm8916_32_512:4.4.4/KTU84P/eng.qwang.20220611:user/test-keys]
Ok, so this thing does indeed run Android (4.4.4 (aka KitKat) with Linux 3.10) which makes me want to disable the WIFI hotspot even more.
Unfortunately, we are not root, but maybe we can just ask nicely?
$ adb root
restarting adbd as root
$ adb shell
shell@msm8916_32_512:/ $ id
uid=2000(shell) gid=2000(shell) groups=1004(input),1007(log),1011(adb),1015(sdcard_rw),1028(sdcard_r),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats) context=kernel
Unfortunately not :-(
However: We know that the device implements a custom webserver, so maybe it has some hidden functions we can explore?
Checking out the webserver
Who listens on port 80 ?
We know that we can access the device via ‘192.168.43.1’ on Port 80 - what else is there?
$ nmap -v -sS 192.168.43.1
...
Nmap scan report for 192.168.43.1
Host is up (0.0060s latency).
Not shown: 997 closed ports
PORT STATE SERVICE
53/tcp open domain
80/tcp open http
8080/tcp open http-proxy
Not too many surprises here: The device anwers / forwards DNS queries on Port 53 - and Port 8080 shows us the same webinterface as we see on Port 80 - so the real webserver is likely not running on port 80 - and digging around in /system/etc
quickly confirms this:
cat /system/etc/httpproxy.conf
# lighttpd.conf
server.modules = (
"mod_access",
"mod_accesslog",
# "mod_indexfile",
"mod_proxy",
# "mod_magnet",
)
server.document-root = "/data/www/"
$HTTP["host"] =="192.168.43.1"{
$HTTP["url"] !~ "^(xion.ico|.*/static/.*)$" {
proxy.server = ( "" => (( "host" => "192.168.43.1", "port" => 8080 )))
}
}
Ok, i’ve seen worse. Unfortunately, we don’t have root access on the stick, so figuring out who listens on port 8080 needs some guessing.
…and what’s up with Port 8080?
Its always good to be polite, so let’s just ask the webserver on Port 8080:
$ telnet 192.168.43.1 8080
Trying 192.168.43.1...
Connected to 192.168.43.1.
Escape character is '^]'.
G
HTTP/1.1 400 Bad Request
Connection: close
Server: Jetty(8.y.z-SNAPSHOT)
Error: 400
Ok, the thing is built using Jetty - and likely an APK, so lets check whats installed:
$ adb shell pm -l
package:com.qualcomm.fastdormancy
package:com.qualcomm.timeservice
package:com.android.launcher
package:com.android.defcontainer
package:android
package:com.android.settings
package:com.android.externalstorage
package:com.qualcomm.wfd.service
package:com.android.phone
package:com.jetty2m.hello
package:com.android.proxyhandler
package:com.android.systemui
package:com.qualcomm.interfacepermissions
package:com.android.keychain
package:com.qualcomm.gsmtuneaway
package:com.android.inputdevices
package:com.qualcomm.qcom_qmi
package:com.android.packageinstaller
package:com.android.providers.telephony
package:com.dsi.ant.server
package:org.codeaurora.ims
package:com.svox.pico
package:com.qualcomm.qti.networksetting
package:com.qualcomm.shutdownlistner
package:com.android.providers.userdictionary
package:com.android.documentsui
package:com.android.wallpapercropper
package:com.android.sharedstoragebackup
package:com.android.location.fused
package:com.android.backupconfirm
package:com.android.providers.settings
package:com.android.vpndialogs
package:com.android.keyguard
package:com.android.provision
package:com.android.pacprocessor
package:com.disaplay.test.test
package:com.qualcomm.qcrilmsgtunnel
package:com.android.shell
package:com.android.certinstaller
Bingo: com.jetty2m.hello
sounds like what we are looking for.
Now, let’s fetch the APK:
$ adb shell ls /system/app/*etty*
/system/app/Jetty2m.apk
/system/app/Jetty2m.odex
$ adb pull /system/app/Jetty2m.apk
And here it is: Jetty2m.apk
What’s next?
So far we learned that the stick runs an (old) version of Android and that the
Web-UI is (very likely) served by Jetty2m.apk
. While we probably could just
root the stick using one of the various kernel root exploits, it might be more
fun to just look into what we can do with the mysterious Web-UI.
And that’s exaclty what we will do in the next article of this series!