Skip to content

Host Device Management

Ann4Security edited this page Oct 19, 2020 · 12 revisions

The azsphere_connect.sh script is used to setup a SLIP tunnel over the USB -> Serial connection (Service UART on the Seeed MT3620 Mini Dev Board and create the sl0 interface:

ubuntu ~> sudo azsphere_connect.sh
Azure Sphere device connected
ubuntu ~> ifconfig sl0
sl0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 296
        inet 192.168.35.1  netmask 255.255.255.255  destination 192.168.35.2
        slip  txqueuelen 10  (Serial Line IP)
        RX packets 16  bytes 2077 (2.0 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 17  bytes 1504 (1.5 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Host IP: 192.168.35.1 Device IP: 192.168.35.2

The device has only one listening TCP/IP service, an HTTPS server:

ubuntu ~> sudo nmap -A -p- 192.168.35.2
Starting Nmap 7.80 ( https://nmap.org ) at 2020-09-08 17:22 UTC
Nmap scan report for 192.168.35.2
Host is up (0.012s latency).
Not shown: 65534 closed ports
PORT    STATE SERVICE VERSION
443/tcp open  https
|_http-title: Site doesn't have a title (application/octet-stream).
| ssl-cert: Subject: commonName=192.168.35.2/organizationName=Microsoft Corporation/stateOrProvinceName=Washington/countryName=US
| Subject Alternative Name: DNS:*.devices.sphere.azure.local, DNS:192.168.35.2, IP Address:192.168.35.2
| Not valid before: 2018-08-22T16:51:43
|_Not valid after:  2038-08-17T16:51:43

Service Reverse Engineering

The HTTPS service is implemented in the gatewayd executable. This executable can be extracted from one of the *.bin files from the recovery Firmware. It is a C++ binary with a custom HTTP stack. We did not fully reverse engineer this binary, but did extract the endpoints that can be accessed by locating a global dispatch table:

Endpoints

  • /abi_versions
    • GET
> curl -k https://192.168.35.2/abi_versions
{"SecureWorldRuntime":1,"OSRuntime":1,"ApplicationRuntime":5}
  • /restart
    • POST
> curl -k -d '' https://192.168.35.2/restart
{"restartingSystem":true}
  • /status
    • GET
> curl -k https://192.168.35.2/status
{"uptime":6812}
  • /log
    • GET
      • binary goo… log messages
  • /images
    • GET
      • Lists all components that are installed… including those that are built in
> curl -k https://192.168.35.2/images
{
            "is_ota_update_in_progress": false,
            "has_staged_updates": false,
            "restart_required": false,
            "components": [
                    {
                            "uid": "ec96028b-080b-4ff5-9ef1-b40264a8c652",
                            "image_type": 7,
                            "is_update_staged": false,
                            "does_image_type_require_restart": true,
                            "images": [
                                    {
                                            "uid": "bec97446-60fd-40f7-abd8-ef396c36e88e",
                                            "length_in_bytes": 2491164,
                                            "uncompressed_length_in_bytes": 2491164,
                                            "replica_type": 0
                                    }
                            ],
                            "name": "NW Kernel"
                    },
    ...
  • /telemetry
  • /wifi/scan
    • GET
      • lists wifi networks it sees
> curl -k https://192.168.35.2/wifi/scan
{"values":[{"bssid":"xx:xx:xx:xx:xx:xx","freq":2462,"signal_level":-67,"ssid":"xxxx","securityState":"psk"},...]}
  • /wifi/config/networks
    • GET
    • POST
    • PATCH
    • DELETE
  • /wifi/interface
    • GET
    > curl -k https://192.168.35.2/wifi/interface
    {"ssid":"","configState":"unknown","connectionState":"disconnected","securityState":"unknown","mode":"","key_mgmt":"UNKNOWN","wpa_state":"DISCONNECTED","address":"ec:9c:32:f2:24:7a","id":0,"configName":""}
  • PATCH
    • Updates config
  • /wifi/diagnostics/networks
    • GET
> curl -k https://192.168.35.2/wifi/diagnostics/networks
{"values":[{"timestamp":"2000-01-01t00:45:21+0000","networkId":9,"ssid":"ABCD","error":"NetworkNotFound",...}
  • /update/stage
    • PUT
      • Used to upload images and other binary config blobs
  • /update/install
    • POST
      • Device will parse whatever was uploaded in /update/stage and install/apply the image.
  • /app/status
    • GET
    • PATCH
  • /app/image
    • DELETE
  • /app/quota
    • GET
  • /net/interfaces
    • GET
    > curl -k https://192.168.35.2/net/interfaces
    {"interfaces":[{"interfaceName":"lo","interfaceUp":true,"connectedToNetwork":false,"ipAcquired":false,"connectedToInternet":false},{"interfaceName":"sl0","interfaceUp":true,"connectedToNetwork":false,"ipAcquired":false,"connectedToInternet":false},{"interfaceName":"wlan0","interfaceUp":true,"connectedToNetwork":false,"ipAcquired":false,"connectedToInternet":false}]}
  • /net/status
    • GET
    > curl -k https://192.168.35.2/net/status
    {"deviceAuthenticationIsReady":false,"networkTimeSync":"incomplete"}
  • /device/manufacturing_state
    • GET
    > curl -k https://192.168.35.2/device/manufacturing_state
    {"manufacturingState":"Blank"}
  • PUT
  • /device/security_state
    • GET
    > curl -k https://192.168.35.2/device/security_state
    {"securityState":"SECURE","deviceIdentityPublicKey":"7BEE580B2EB6391D272AB42BF62FDDCC4E0AAB7475C0B1AFFB0D5CE24F2AACBA1E424224D6B571005518AEFD89A900D9A33EB2E8795598CF63826E348CBCDAA2"}
  • /certstore/certs
    • GET
    • POST
    • DELETE
  • /certstore/space
    • GET
    > curl -k https://192.168.35.2/certstore/space
    {"AvailableSpace":"24514"}

MiTM azsphere CLI Tool

Since the REST API is over HTTPS, we must break into the encrypted tunnel in order to view the HTTP requests. We accomplished this by:

  1. Extracting the SSL certificate and private key from the device's firmware.
  2. Using ProxyChains to hook libc network functions to add proxy support.
  3. Using mitmproxy to record/proxy the azsphere CLI requests.

Extracting SSL Certificate/Key

The gatewayd image from the recovery Firmware contains the gatewayd-server-cert.pem and gatewayd-server-key.pem. When we extract the contents of the image's file system, the files are located in the bin directory.

ProxyChains Configuration

We used the following configuration for ProxyChains:

strict_chain
tcp_read_time_out 15000
tcp_connect_time_out 8000

[ProxyList]
http 127.0.0.1 8080

mitmproxy

For mitmproxy, we first merged the device's SSL certificate key and PEM files together:

> cat gatewayd-server-cert.pem gatewayd-server-key.pem > device_rest_api.pem

Then we started mitmproxy with the --ssl-insecure and the --ignore-hosts prod.releases.sphere.azure.net arguments. The --ignore-hosts option allows the CLI tool to access Microsoft's cloud services to download recovery images and obtain entitlements in order to enable features such as development mode.

> mitmproxy --ssl-insecure --certs /mnt/hgfs/MediaTek/Certs/device_rest_api.pem --ignore-hosts prod.releases.sphere.azure.net

Proxying

Now when using proxychains we can proxy the requests and review the actions taken by the CLI tool:

> proxychains azsphere dev wifi add -s ABCD -p BBBBBBBBBB -cn ZZZZ
ProxyChains-3.1 (http://proxychains.sf.net)
|S-chain|-<>-127.0.0.1:8080-<><>-192.168.35.2:443-<><>-OK
|S-chain|-<>-127.0.0.1:8080-<><>-192.168.35.2:443-<><>-OK
|S-chain|-<>-127.0.0.1:8080-<><>-192.168.35.2:443-<><>-OK
Add network succeeded:
ID                  : 10
SSID                : ABCD
Configuration state : enabled
Connection state    : unknown
Security state      : psk
Targeted scan       : False