Intercept a macOS app traffic using mitmproxy
July 20, 2021
July 20, 2021
I’ll take as an example for this use case a project of mine that exposes a hidden endpoint of the Spotify app, allowing to see the friend activity feed (what your friends are currently playing).
In most cases I’ll try to reverse a web app directly in the browser by monitoring the HTTP calls in the network tab of the developer tools, but the Spotify web player doesn’t support the friend activity feature, it’s only available in the desktop app, so this wasn’t an option here.
In this post, I’ll go through the steps necessary to intercept the Spotify macOS app traffic using mitmproxy, but this could work with other apps as well.
An intercepting proxy like mitmproxy uses HTTP tunnelling to forward (and optionally capture) all the traffic that is sent to it.
Typically, you can configure a specific app, browser, or the whole system to use a HTTP proxy to forward requests, so that, instead of connecting directly to the desired hosts, it sends the traffic to the configured proxy.
This can be useful for a number of reasons, and in our case, it allows us to configure a proxy that we control, so that we can inspect the HTTP traffic going through it.
Assuming you use Homebrew:
brew install mitmproxy
mitmproxy
This starts a terminal interface that will show all the requests going through the proxy. Press ? to see the keybindings.
By default the proxy runs on localhost:8080
.
The first thing I usually try for this is to configure the proxy settings directly at the system level, because most apps don’t allow configuring a proxy in their settings. On macOS, this will be in “System Preferences”, “Network”, “Advanced…”, “Proxies”, “Web Proxy (HTTP)”.
But when opening the Spotify app, I only see a single authentication request going through (interestingly), but definitely not the whole traffic. It appears that the Spotify app currently ignores the system proxy settings.
For other apps, especially ones that don’t allow configuring a proxy inside the app, this might work.
To my surprise, Spotify allows you to configure a proxy directly inside
the app. Go in “Spotify”, “Preferences”, “Show advanced settings”,
“Proxy settings” to configure localhost:8080
as a proxy.
But after restarting the app we get an error in the mitmproxy console:
Warn: [::1]:65468: Client TLS handshake failed. The client may not trust the proxy's certificate for login5.spotify.com (OpenSSL Error([('SSL routines', 'ssl3_read_bytes', 'sslv3 alert certificate unknown')]))
This is because to inspect HTTPS traffic, mitmproxy needs to use its own SSL certificate, otherwise all we would see would be the encrypted traffic between the app and Spotify servers.
mitmproxy comes with a CA certificate that trusts the certificate used by mitmproxy to terminate the SSL connection. By adding this CA certificate to the system list of trusted certificate, the app should allow the traffic to go through (unless it does certificate pinning).
To do this, open the ~/.mitmproxy
directory which contains the
certificate files, open Keychain Access, and drop
mitmproxy-ca-cert.pem
into it.
By default, macOS will not trust that new certificate, so you need to double-click on it, and in the “Trust” section, set “Always Trust”.
After restarting the Spotify app, you should now see the traffic going through in mitmproxy.
Note: I usually delete the certificate after I’m done inspecting requests, just to be safe.
Then it’s a matter of browsing all the requests in the mitmproxy UI.
Here, it’ll be particularly handy to use the filter function by pressing F. This allows us to specify a filter pattern.
For example, if I know the URL I’m looking for contains the string
buddylist
, I can type that in the filter prompt, which equals to the
command set view_filter 'buddylist'
, so that mitmproxy only shows the
matching calls.
If I didn’t know this string was part of the URL, but instead wanted to
match on the body, which I know contains the string shaktirockgym
(one
of my Spotify friends), I can use ~b shaktirockgym
as a filter.
Then, most of the work will be about curl
ing the endpoints to get
successful responses, identifying what headers are necessary, what
parameters to pass, how to deal with authentication and other security
means the app have in place.
This should be enough to get you started on reversing a macOS app network requests, to build your own client, scripts or whatnot. Happy hacking!