GithubHelp home page GithubHelp logo

Comments (11)

talsec-app avatar talsec-app commented on July 2, 2024

Hi @reyesmfabian
Could you please confirm this is the bypass that you tried: https://codeshare.frida.re/@enovella/anti-frida-bypass/ ? This one should not be capable of bypassing freeRASP's hook detection.
Thank you in advance,
Talsec Team

from free-rasp-flutter.

reyesmfabian avatar reyesmfabian commented on July 2, 2024

Hi @reyesmfabian

Could you please confirm this is the bypass that you tried: https://codeshare.frida.re/@enovella/anti-frida-bypass/ ? This one should not be capable of bypassing freeRASP's hook detection.

Thank you in advance,

Talsec Team

Yes, that one.

I follow this steps:

  • Make a release APK of the App with freeRasp integration.
  • Install the APK in the rooted device and check the threats recognition. (It works)
  • Launch the Apk with Frida bypass to test the threats recognition. (Fail, the app don't recognize threats).

from free-rasp-flutter.

talsec-app avatar talsec-app commented on July 2, 2024

We tested the referenced script and it is definitely not able to bypass freeRASP's hook detection.

The possible culprit on your side may be caused by not refreshing the state of the widget once you receive the callback. Such a problem is explained in this issue: #13 (comment) . Hope this helps!

Thank you for using the freeRASP. Let us know if you need anything,
Talsec Team

Our test
We tested the script against the latest freeRASP.

  • no script: Hook is properly detected
  • with script: Hook is properly detected
$ frida -U --codeshare enovella/anti-frida-bypass -f com.talsec.demo --no-pause

from free-rasp-flutter.

reyesmfabian avatar reyesmfabian commented on July 2, 2024

Hi @talsec-app

I'm testing the solution as follows:

main.dart file:

 List<Threat> _threats = [];

 @override
  void initState() {
    super.initState();
    initSecurityState();
  }

Future<void> initSecurityState() async {
 TalsecConfig _config.........
 TalsecCallback _callback = TalsecCallback(
        // For Android
        androidCallback: AndroidCallback(
          onRootDetected: () => _updateThreats(Threat.RootDetected).......

   TalsecApp app = TalsecApp(
      config: _config,
      callback: _callback,
    );

    app.start();
}

 _updateThreats(Threat threat) {
    if (!_threats.contains(threat)) _threats.add(threat);
    setState(() {});
    securityServiceController.add(_threats);
  }

security_stream.dart

StreamController<List<Threat>> securityServiceController =
    new StreamController.broadcast();

login_page.dart

@override
initState() {
securityServiceController.stream.listen((threats) {
  if (threats.length != 0) {
    Navigator.pushReplacementNamed(context, 'testPage');
  }
});
  super.initState();
}

The thing is, with the normal start, the App reads the threats and goes to PageTest, everything is fine.

But, if I start the script with this

$ frida -U --codeshare enovella/anti-frida-bypass -f com.myapp.id

The application does not read the threats and works as normally.

Maybe i have something wrong that i can't see

from free-rasp-flutter.

talsec-app avatar talsec-app commented on July 2, 2024

Hello @reyesmfabian ,
We have tried your code mixed with the freeRASP example code (https://pub.dev/packages/freerasp/example). Check below. It still works for us as expected. Please try the code below and let us know if it helps you.

import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:freerasp/talsec_app.dart';
import 'package:freerasp/utils/hash_converter.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({final Key? key}) : super(key: key);

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  /// ThreatTypes to hold current state (Android)
  final ThreatType _root = ThreatType("Root");
  final ThreatType _emulator = ThreatType("Emulator");
  final ThreatType _tamper = ThreatType("Tamper");
  final ThreatType _hook = ThreatType("Hook");
  final ThreatType _deviceBinding = ThreatType("Device binding");
  final ThreatType _untrustedSource =
      ThreatType("Untrusted source of installation");

  /// ThreatTypes to hold current state (iOS)
  final ThreatType _signature = ThreatType("Signature");
  final ThreatType _jailbreak = ThreatType("Jailbreak");
  final ThreatType _runtimeManipulation = ThreatType("Runtime Manipulation");
  final ThreatType _simulator = ThreatType("Simulator");
  final ThreatType _deviceChange = ThreatType("Device change");
  final ThreatType _deviceId = ThreatType("Device ID");
  final ThreatType _unofficialStore = ThreatType("Unofficial Store");
  final ThreatType _passcode = ThreatType("Passcode");
  final ThreatType _missingSecureEnclave = ThreatType("Missing secure enclave");

  /// ThreatTypes to hold current state (common)
  final ThreatType _debugger = ThreatType("Debugger");

  /// Getter to determine which states we care about
  List<Widget> get overview {
    if (Platform.isAndroid) {
      return [
        Text(_root.state),
        Text(_debugger.state),
        Text(_emulator.state),
        Text(_tamper.state),
        Text(_hook.state),
        Text(_deviceBinding.state),
        Text(_untrustedSource.state),
      ];
    }
    return [
      Text(_signature.state),
      Text(_jailbreak.state),
      Text(_debugger.state),
      Text(_runtimeManipulation.state),
      Text(_passcode.state),
      Text(_simulator.state),
      Text(_missingSecureEnclave.state),
      Text(_deviceChange.state),
      Text(_deviceId.state),
      Text(_unofficialStore.state)
    ];
  }

  /// Override initState of the "highest" widget in order to start freeRASP
  /// as soon as possible.
  @override
  void initState() {
    super.initState();
    initSecurityState();
  }

  List<String> _threats = [];
  _updateThreats(String threat) {
    if (!_threats.contains(threat)) _threats.add(threat);
    setState(() {});
    securityServiceController.add(_threats);
  }

  StreamController<List<String>> securityServiceController =
      new StreamController.broadcast();

  Future<void> initSecurityState() async {
    /// Provide TalsecConfig your expected data and then use them in TalsecApp
    final TalsecConfig config = TalsecConfig(
      // For Android
      ...
    );

    /// Callbacks thrown by library
    final TalsecCallback callback = TalsecCallback(
      /// For Android
      androidCallback: AndroidCallback(
        onRootDetected: () => _updateState(_root),
        onEmulatorDetected: () => _updateState(_emulator),
        onHookDetected: () {
          _updateThreats("Hook");
        },
        onTamperDetected: () => _updateState(_tamper),
        onDeviceBindingDetected: () => _updateState(_deviceBinding),
        onUntrustedInstallationDetected: () => _updateState(_untrustedSource),
      ),

      /// For iOS
      iosCallback: IOSCallback(
        onSignatureDetected: () => _updateState(_signature),
        onRuntimeManipulationDetected: () => _updateState(_runtimeManipulation),
        onJailbreakDetected: () => _updateState(_jailbreak),
        onPasscodeDetected: () => _updateState(_passcode),
        onSimulatorDetected: () => _updateState(_simulator),
        onMissingSecureEnclaveDetected: () =>
            _updateState(_missingSecureEnclave),
        onDeviceChangeDetected: () => _updateState(_deviceChange),
        onDeviceIdDetected: () => _updateState(_deviceId),
        onUnofficialStoreDetected: () => _updateState(_unofficialStore),
      ),

      /// Debugger is common for both platforms
      onDebuggerDetected: () => _updateState(_debugger),
    );

    final TalsecApp app = TalsecApp(
      config: config,
      callback: callback,
    );

    /// Turn on freeRASP
    app.start();

    securityServiceController.stream.listen((threats) {
      if (threats.length != 0) {
        print("Broadcast received");
      }
    });

    if (!mounted) return;
  }

  void _updateState(final ThreatType type) {
    setState(() {
      // ignore: parameter_assignments
      type.threatFound();
    });
  }

  @override
  Widget build(final BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: overview,
          ),
        ),
      ),
    );
  }
}

class ThreatType {
  final String _text;
  bool _isSecure = true;

  ThreatType(this._text);

  void threatFound() => _isSecure = false;

  String get state => '$_text: ${_isSecure ? "Secured" : "Detected"}\n';
}

from free-rasp-flutter.

reyesmfabian avatar reyesmfabian commented on July 2, 2024

Hello @reyesmfabian , We have tried your code mixed with the freeRASP example code (https://pub.dev/packages/freerasp/example). Check below. It still works for us as expected. Please try the code below and let us know if it helps you.

Hi,

This is my main.dart file:

import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_translate/flutter_translate.dart';
import 'package:freerasp/talsec_app.dart';
import 'package:provider/provider.dart';
import 'package:my_project/pages/test_page.dart';
import 'package:my_project/provider/provider.dart';
import 'package:my_project/provider/socketService.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  var delegate = await LocalizationDelegate.create(
      fallbackLocale: 'en_US', supportedLocales: ['en_US', 'es']);
  runApp(LocalizedApp(delegate, MyApp()));
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final GlobalKey<NavigatorState> navigatorKey =
      new GlobalKey<NavigatorState>();

  /// ThreatTypes to hold current state (Android)
  final ThreatType _root = ThreatType("Root");
  final ThreatType _emulator = ThreatType("Emulator");
  final ThreatType _tamper = ThreatType("Tamper");
  final ThreatType _hook = ThreatType("Hook");
  final ThreatType _deviceBinding = ThreatType("Device binding");
  final ThreatType _untrustedSource =
      ThreatType("Untrusted source of installation");

  /// ThreatTypes to hold current state (iOS)
  final ThreatType _signature = ThreatType("Signature");
  final ThreatType _jailbreak = ThreatType("Jailbreak");
  final ThreatType _runtimeManipulation = ThreatType("Runtime Manipulation");
  final ThreatType _simulator = ThreatType("Simulator");
  final ThreatType _deviceChange = ThreatType("Device change");
  final ThreatType _deviceId = ThreatType("Device ID");
  final ThreatType _unofficialStore = ThreatType("Unofficial Store");
  final ThreatType _passcode = ThreatType("Passcode");
  final ThreatType _missingSecureEnclave = ThreatType("Missing secure enclave");

  /// ThreatTypes to hold current state (common)
  final ThreatType _debugger = ThreatType("Debugger");

  /// Getter to determine which states we care about
  List<Widget> get overview {
    if (Platform.isAndroid) {
      return [
        Text(_root.state),
        Text(_debugger.state),
        Text(_emulator.state),
        Text(_tamper.state),
        Text(_hook.state),
        Text(_deviceBinding.state),
        Text(_untrustedSource.state),
      ];
    }
    return [
      Text(_signature.state),
      Text(_jailbreak.state),
      Text(_debugger.state),
      Text(_runtimeManipulation.state),
      Text(_passcode.state),
      Text(_simulator.state),
      Text(_missingSecureEnclave.state),
      Text(_deviceChange.state),
      Text(_deviceId.state),
      Text(_unofficialStore.state)
    ];
  }

  @override
  void dispose() {
    securityServiceController.close();
    super.dispose();
  }

  @override
  void initState() {
    super.initState();
    initSecurityState();
  }

  Future<void> initSecurityState() async {
    TalsecConfig _config = TalsecConfig(
      // For Android
      androidConfig: AndroidConfig(
        expectedPackageName: 'com.my_identifier',
        expectedSigningCertificateHash:
            'cert_hash',
        supportedAlternativeStores: [],
      ),

      // For iOS
      iosConfig: IOSconfig(
        appBundleId: 'com.my_identifier',
        appTeamId: 'my_team',
      ),

      // Common email for Alerts and Reports
      watcherMail: 'email',
    );

    // Talsec callback handler
    TalsecCallback _callback = TalsecCallback(
      /// For Android
      androidCallback: AndroidCallback(
        onRootDetected: () => _updateThreats('root', _root),
        onEmulatorDetected: () => _updateThreats('emulator', _emulator),
        onHookDetected: () {
          _updateThreats("Hook", _hook);
        },
        onTamperDetected: () => _updateThreats('tamper', _tamper),
        onDeviceBindingDetected: () =>
            _updateThreats('device_binding', _deviceBinding),
        onUntrustedInstallationDetected: () =>
            _updateThreats('_untrustedSource', _untrustedSource),
      ),

      /// For iOS
      iosCallback: IOSCallback(
        onSignatureDetected: () => _updateThreats('_signature', _signature),
        onRuntimeManipulationDetected: () =>
            _updateThreats('_runtimeManipulation', _runtimeManipulation),
        onJailbreakDetected: () => _updateThreats('_jailbreak', _jailbreak),
        onPasscodeDetected: () => _updateThreats('_passcode', _passcode),
        onSimulatorDetected: () => _updateThreats('_simulator', _simulator),
        onMissingSecureEnclaveDetected: () =>
            _updateThreats('_missingSecureEnclave', _missingSecureEnclave),
        onDeviceChangeDetected: () =>
            _updateThreats('_deviceChange', _deviceChange),
        onDeviceIdDetected: () => _updateThreats('_deviceId', _deviceId),
        onUnofficialStoreDetected: () =>
            _updateThreats('_unofficialStore', _unofficialStore),
      ),

      /// Debugger is common for both platforms
      onDebuggerDetected: () => _updateThreats('_debugger', _debugger),
    );
    TalsecApp app = TalsecApp(
      config: _config,
      callback: _callback,
    );
    securityServiceController.stream.listen((threats) {
      if (threats.length != 0) {
        print("Broadcast received");
      }
    });

    if (!mounted) return;
    app.start();
  }

  List<String> _threats = [];
  _updateThreats(String threat, ThreatType type) {
    if (!_threats.contains(threat)) _threats.add(threat);
    setState(() {
      type.threatFound();
    });
    securityServiceController.add(_threats);
  }

  @override
  Widget build(BuildContext context) {
    var localizationDelegate = LocalizedApp.of(context).delegate;
    final ThemeData theme = ThemeData();
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => new SocketService()),
        ChangeNotifierProvider(create: (_) => new UsuarioActivo())
      ],
      child: LocalizationProvider(
        state: LocalizationProvider.of(context).state,
        child: MaterialApp(
            navigatorKey: navigatorKey,
            localizationsDelegates: [
              GlobalMaterialLocalizations.delegate,
              GlobalWidgetsLocalizations.delegate,
              GlobalCupertinoLocalizations.delegate,
              DefaultCupertinoLocalizations.delegate
            ],
            supportedLocales: localizationDelegate.supportedLocales,
            locale: localizationDelegate.currentLocale,
            debugShowCheckedModeBanner: false,
            title: 'App Name',
            initialRoute: 'testPage',
            routes: {
              'testPage': (_) => TestSecurityPage(),
            },
            theme: theme.copyWith(
                textTheme: theme.textTheme.apply(fontFamily: 'Nunito'),
                colorScheme: theme.colorScheme.copyWith(
                    secondary: Colors.red[900], primary: Colors.blue[900]))),
      ),
    );
  }
}

class ThreatType {
  final String _text;
  bool _isSecure = true;

  ThreatType(this._text);

  void threatFound() => _isSecure = false;

  String get state => '$_text: ${_isSecure ? "Secured" : "Detected"}\n';
}

StreamController<List<String>> securityServiceController =
    new StreamController.broadcast();

test_page.dart file

import 'package:flutter/material.dart';

import '../main.dart';

class TestSecurityPage extends StatefulWidget {
  const TestSecurityPage({Key key}) : super(key: key);

  @override
  State<TestSecurityPage> createState() => _TestSecurityPageState();
}

class _TestSecurityPageState extends State<TestSecurityPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
      child: StreamBuilder<List<String>>(
          stream: securityServiceController.stream,
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return ListView.builder(
                  itemCount: snapshot.data.length,
                  itemBuilder: (context, i) {
                    return ListTile(
                      title: Text(snapshot.data[i].toString()),
                    );
                  });
            } else {
              return Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text('No Threats Detected'),
                ],
              );
            }
          }),
    ));
  }
}

this is the behavior.

flutter run --release

https://www.youtube.com/shorts/goULuQPXh4Q

now, with the same release version installed and execute with frida:

frida -U --codeshare enovella/anti-frida-bypass -f com.my_identifier

https://www.youtube.com/shorts/EjuVBWLilCE

from free-rasp-flutter.

talsec-app avatar talsec-app commented on July 2, 2024

Thank you for your testing & videos. We will inspect this issue more and get back to you by the end of the following week.

from free-rasp-flutter.

talsec-app avatar talsec-app commented on July 2, 2024

We couldn't reproduce the issue. The anti-frida-bypass script is not able to mitigate Frida detection.

flutter run --release

The app is hooked with latest Frida v16.0.2. UI works. The button is tapped to increase the number in AppBar in the second half of the recording. The detection works as expected, and the hook callback is successfully received after some slight delay:

frida -U --codeshare enovella/anti-frida-bypass -f com.example.app

https://youtube.com/shorts/bJ5FDxlt0Dk?feature=share

The anti-frida-bypass outputs many errors:
1

from free-rasp-flutter.

reyesmfabian avatar reyesmfabian commented on July 2, 2024

We couldn't reproduce the issue. The anti-frida-bypass script is not able to mitigate Frida detection.

flutter run --release

The app is hooked with latest Frida v16.0.2. UI works. The button is tapped to increase the number in AppBar in the second half of the recording. The detection works as expected, and the hook callback is successfully received after some slight delay:

frida -U --codeshare enovella/anti-frida-bypass -f com.example.app

https://youtube.com/shorts/bJ5FDxlt0Dk?feature=share

The anti-frida-bypass outputs many errors: 1

Do you think that my approach with a stream controller is the problem?

Do you think it is possible to access that repo to test it in my own environment?

from free-rasp-flutter.

reyesmfabian avatar reyesmfabian commented on July 2, 2024

$ frida -U --codeshare enovella/anti-frida-bypass -f com.myapp.id

There is a problem with frida detection.

I am trying the CyberTribe application downloaded from the official store as suggested by Sergiy.

look: https://www.youtube.com/watch?v=KsgCfpakFkI&ab_channel=R-Tech

I didn't modify the apk, I just downloaded it and tested it.

from free-rasp-flutter.

talsec-app avatar talsec-app commented on July 2, 2024

Conclusion

We are closing this issue as we were unable to reproduce this behavior. This may be important in the future, but we can't do anything about it currently. If someone encounters this issue in the future, let us know, and it can be further inspected.

Thank you so much for your assistance,
Talsec Team

from free-rasp-flutter.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.