ptswarm / reFlutter

Flutter Reverse Engineering Framework
GNU General Public License v3.0
1.29k stars 180 forks source link

Demo: real HTTP Proxy, instead of destination socket rewrite #34

Open mame82 opened 3 years ago

mame82 commented 3 years ago

Hi, thx for the great project. I was working on a use case, where Flutter has to be forced to use a real HTTP proxy (instead of silently redirecting to a transparent proxy).

I want to share my patch for info, maybe sbdy could use it (targets Dart's HttpClient implementation, enforces proxy and prevents overwriting it via findProxy setter): 20211112_161915

Here's a short Twitter thread, showing it applied to a target app: https://twitter.com/mame82/status/1459157357989187592

Impact-I commented 3 years ago

Hi @mame82 , Thank you for your interest in the project.

When making these changes to the files /src/third_party/dart/tools/sdks/dart-sdk/lib/_http/http_impl.dart /src/third_party/dart/sdk/lib/_http/http_impl.dart Nothing happens. How did you get libflutter_patched.so? It will be great if you share the library.

mame82 commented 3 years ago

Okay, as already discussed on Twitter, this approach was invalid.

Patches for SDK code (namely HttpClient) do not end up in libflutter.so as the VM snapshot is compiled into libapp.so.

A working approach to make HttpClient use a proxy by modifying the Dart runtime (and thus ending up in libflutter.so) was found. This could be achieved by modifying the native code implementing Platfom::Environment to add in http_proxyand https_proxy environment variables, which are missing on Android.

The shortcoming of this (compared to overwriting the destination IP for socket connections): While the default behaviour of HttpClient is to determin the Proxy to use based on these environment variables, the application could use HttpClient.findProxy to define a Proxy on App-level, which would overwrite the Proxy defined by the patch.

The screenshot shows a patch-diff for Androids Platform::Environment implementation:

proxified4

Beside not having to rely on an interception proxy which works in transparent mode, a benefit is, that the environment variable also stores the proxy port in the string. So it could be easily overwritten on a pre-compiled binary, as reFlutter already does with the proxy IP. proxified5

Also adding no_proxy environment variable could add more fine-grained control (not tested).

Last but not least: Such a patch does not interfere with the socket.cc patches already applied. If the proxy defined in the environment variables is used by the app (which is the default for Flutter), the socket.cc patch would rewrite the destination which to the same values which are already set. The difference would be, that the client communicates with the proxy as expected (sends CONNECT requests and uses absolute URLs in request lines.

If the App overwrites the findProxy function, the connect.cc patch still would overwrite the target IP and port. Thus, traffic would still end up at the proxy, but has to be handled transparently (determine target host from Host header, as no absolute URLs are use in request line and no CONNECT requests get sent).

With that, I think there is not much more to add and I want to say THANK YOU for the great project, again!

mame82 commented 3 years ago

For completeness, I attach a compiled libflutter.so:

The following app currently uses a matching libflutter.so and was used for testing: "Knowunity". All flutter connections are correctly passed on to the proxy, without the need of destination IP rewrites.

libflutter_arm32_9cf77f4405212c45daf608e1cd646852.zip

Impact-I commented 3 years ago

@mame82 , Thanks for the contribution to the project. You are a purposeful person.

Ditching a transparent proxy is very tempting. I will need to write a universal patch for all supported Flutter Engine versions. Hopefully this patch will appear in reFlutter. Perfect solution!