Try โ€‚โ€‰HackMD

Pentesting Flutter mobile apps (Android)

Recently I had an opportunity to perform a penetration test of a mobile application created in Flutter - a relatively new development framework created by Google. Flutter mobile applications are written in Dart. In this post I'll share some notes on the first steps I took when testing this application on Android:

  • redirecting traffic to Burp (http.dart ignores system proxy settings, user certificates and Network Security Config),
  • bypassing root detection.

If you want to try it yourself, I created a sample Flutter app available here

Setting intercepting machine as a gateway

Because setting network proxy is not sufficient in this case, instead I set my Mac (IP 192.168.1.4) as a gateway for Android phone (IP 192.168.1.8). On the Mac:

$ sudo sysctl -w net.inet.ip.forwarding=1

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More โ†’

On the phone:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More โ†’

Now all the traffic goes through the intercepting Mac and is ready to be analysed with Wireshark/tcpdump/whatever. Based on analysis of the traffic generated by the Flutter application, let's redirect some of it to Burp Proxy.

Redirecting traffic to Burp

Once the communication between the application and its server-side API is passing through the intercepting machine, it's easy to redirect specific connections to Burp:

$ cat pfctl.txt
rdr pass inet proto tcp from 192.168.1.8 to runic.pl port 443 -> 127.0.0.1 port 8443

$ sudo pfctl -f pfctl.txt

$ sudo pfctl -s nat
rdr pass inet proto tcp from 192.168.1.8 to 37.187.60.243 port = 443 -> 127.0.0.1 port 8443

This redirects https traffic sent to runic.pl to Burp Proxy listening on 127.0.0.1:8443. In Proxy options, let's create a listener on port 8443 supporting invisible proxying:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More โ†’

Of course the application doesn't accept Burp Proxy SSL certificate as valid yet. There is a good post on fixing this in Android 7.0+ at blog.ropnop.com - I won't repeat it here. You have to use the first method (installing Burp Proxy certificate as a system-level CA), because http.dart in Flutter ignores Network Security Config. This means a rooted device is needed.

Once this is done, all is ready to start testing HTTP trafficโ€ฆ unless there is root detection in place.

Bypassing root detection

There are currently three root/jailbreak detection packages available for Flutter:

In the test app above I used the first one. After using dex2jar on the test app's APK and loading the generated jar file in JD-GUI, it's quite easy to find the class responsible for root detection on Android:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More โ†’

I used Frida to overload isRooted() method. The script is short:

console.log("Loading flutter_jailbreak_detection bypass...");
setImmediate(function() {
  Java.perform(function () {
    var root = Java.use("com.scottyab.rootbeer.RootBeer");
    root.isRooted.overload().implementation = function() {
      console.log("isRooted() called, returning false");
      return false;
    }
  });
});

Once frida-server is running on Android device, let's run the script:

$ frida -U -f pl.runic.ip -l frida-flutter-jailbreak-detection-bypass.js

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More โ†’

That's it - the app runs on a rooted device and the traffic passes through Burp - let's start testing!


If it helps you in any way, the Frida scripts for flutter_jailbreak_detection and root_checker bypasses are on Github:

I didn't check trust_fall plugin, but it uses RootBeer as the first one above, so I guess the script should work too.


2019-06-08 @runicpl