FP3 : MITM update engine

Intro

If we want to get the update without a stock rom, we should know how the update engine get the URL of the OTA update. I’ll show how to MITM (man in the middle) the update engine.

Stock rooted rom

First, we need a stock rooted rom.

  1. Install stock rom with the flashable zip
  2. Flash TWRP
  3. Flash magisk
  4. Erase userdata
    In bootloader : fastboot -w

Proxy and system certificate

  1. Launch burp on your computer and listen on your LAN
  2. Boot without any SIM card, skip as much as possible steps, just enter a PIN.
  3. Enable developper mode, adb and disable automatic system update
  4. Install magisk manager with adb
    adb install magisk/MagiskManager-v7.5.1.apk
  5. Disable google apk, so they won’t try to update
adb shell pm disable-user --user 0 com.google.android.configupdater
adb shell pm disable-user --user 0 com.google.android.gms
adb shell pm disable-user --user 0 com.google.android.gmsintegration
adb shell pm disable-user --user 0 com.google.android.gms.policy_sidecar_aps
adb shell pm disable-user --user 0 com.google.android.gsf
  1. Setup your wifi
  2. Download the CA cert with chrome
    http://{server_ip}:{port}
  3. Rename and move the cert
adb shell mv /sdcard/Download/cacert.der /sdcard/cacert.cer
  1. Add the cert as user cert
    Settings > Search : cert > install from storage
    name : cacert
  2. Install the magisk module “Move Certificates”
    Magisk Manager > Download > Move Certificates > Install
  3. Set your wifi proxy to manual, with your server ip and listenning port
  4. Disable the wifi
  5. Re-enable the google apk
adb shell pm enable com.google.android.configupdater
adb shell pm enable com.google.android.gms
adb shell pm enable com.google.android.gmsintegration
adb shell pm enable com.google.android.gms.policy_sidecar_aps
adb shell pm enable com.google.android.gsf
  1. Do a TWRP backup of data.

Then you’re done.

5 Likes

OK, I have the request giving the OTA URL.

Host : https://android.googleapis.com

Request:

POST /checkin HTTP/1.1
Content-type: application/x-protobuffer
Content-encoding: gzip
Accept-Encoding: gzip, deflate
Cookie: NID=197=cKN [...] 3WWABxwtqM
User-Agent: Dalvik/2.1.0 (Linux; U; Android 9; FP3 Build/8901.2.A.0105.20191217)
Host: android.googleapis.com
Connection: close
Content-Length: 14155

[Gzipped data]

Response :

HTTP/1.1 200 OK
Content-Type: application/x-protobuffer; charset=UTF-8
Date: Thu, 30 Jan 2020 19:53:07 GMT
Expires: Thu, 30 Jan 2020 19:53:07 GMT
Cache-Control: private, max-age=0
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Server: GSE
Alt-Svc: quic=":443"; ma=2592000; v="46,43",h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000
Connection: close
Content-Length: 150342

[ ... ] 
update_urlnhttps://android.googleapis.com/packages/ota-api/fairphone_fp3_fp3/996d9c3cd83bf55bcbf4674a7074885e2d66e0f8.zip*#
[ ... ]
5 Likes

Well, I managed to have the url without the phone. But I used the same cookie and the exact same gzip POST data. (and I didn’t look deeply in what is in it)

Edit : the cookie is … useless :slight_smile:

Edit2 : I am trying to get an OTA URL for a different build. But it doesn’t work for the moment. I have to wait to have the stock 0110 (or another version). If someone want to try and have a different version, please send me the gzipped post data :slight_smile:

Edit3 : I’ll upload the script if it works for the next update. Script uploaded. We just have to try if it works with the next update

1 Like

What exactly is sent in the body (gzipped data)?

This alone doesn’t work:
curl -X POST -H "Content-type: application/x-protobuffer" -A "Dalvik/2.1.0 (Linux; U; Android 9; FP3 Build/8901.2.A.0105.20191217)" https://android.googleapis.com/checkin

Well, if someone want to dig it, here is the script :

Works from A0105 to A0110 (and hopfully the next ones)

2 Likes

I’ve uploaded it on github. I tried to do a sed with the build, incremental and date before gzip it. But it didn’t give the OTA URL.

edit : The build version in the user agent isn’t check

Is the blob the checkin process sends by any change the crazy structure described in this blog?

I am actually not sure, but if it is, then you’d have to reverse engineer and recreate one of the best protected parts of proprietary interfaces google put into their closed gapps. in order to have your phone pretend to google that it’s a different phone.

Actually, the same request always give the OTA URL. If it works with the next update we don’t really care what’s inside (we’ll do diff from A0105) :smile:

edit : And I think the “important” part at the end is encrypted with the public key mentioned before. If I use my own public key, I’ll be able to see what’s inside. I just don’t really care if the same request always works (we don’t need full update thanks to your payload_dumper ! :slight_smile: )

what I would like is older images, pre November - just for completeness sake

Yep, then it 'll be hard to do unless we dig a bit more.
Actually, I just wanted to have the future URL without flashing the stock ROM again ^^

well, one hope is that someone will post it here in the forum in acceptable time :wink:

one option that might work is to have LOS or whatever you like in slot A, and flash the latest stock into slot B, then boot up slot B once just to find out the update URL, then reboot into A and download on the PC.

issues might be that slot B might not actually boot unless you erase userdata first - I had that problem in the past when trying a stock downgrade, it wouldn’t boot unless i forced a factory reset first.

I just hope my script (actually, the request) will work for the future update ^^

well, as I see it, there’s 4 plausible futures:

  1. the script will stop working after some time because some cookies/session IDs encrypted in it run out
  2. the script will continue working but only ever give you the same next version, not a delta update across 2 or more firmware versions
  3. the script will give an updated URL allowing to “jump over” the next firmware to the latest
  4. the same as 3, but only once or twice, then get stuck as in 2 requiring to run the updates one-after-the-other (and boot the new system to get the next updates URL)

we saw 2 “jump over the fox” updates so far, but at least one of them involved an update that was pulled back after a single week

only time will tell :wink:

actually, you could try to downgrade to A.0101 and see if you get a skipover URL :wink:

I see a 5th option : After 2-3 releases, it does FULL updates :slight_smile:

As you said, time will tell :smile:

Maybe i’ll try with the A0101 next week (and replace the public key too)

There’s also: Presenting QCSuper: a tool for capturing your 2G/3G/4G air traffic on Qualcomm-based phones. Requires root.

1 Like

It would seem, that the request is using googles play API.
It would be interesting to know if it finds updates, without having a google account on the phone.

Here is a python-implementation of the play-api:

It would likely require some modifications to work for requesting the OTA-URL.

I didn’t have any google account for the tests I did, and it has found the update

Then it might use some kind of token predefined in the firmware.
But it definitely seems to use the checkin-api of the play-services.

OK, it works with A0111.

Getting OTA URL from BUILD 8901.2.A.0105.20191217/12171325 (2019-12-05)
Fairphone 3 A.0111 update*r
https://android.googleapis.com/packages/ota-api/fairphone_fp3_fp3/05f054a6029b23dcd171ded487dedb929ae99dc1.zip
3 Likes

The method you described in your top post works?