【Android】Cross-end security subtotal

Preface

When digging into mobile terminals, we usually pay attention to cross-terminal issues, because we can directly access the native code from the webview container. From the client's perspective, we can directly go deep into the client from the front end, so there is more research on the cross-terminal aspect. significance.

This article introduces in detail the basic knowledge of cross-end communication from Android front-end to client and related vulnerability mining ideas.

basic knowledge

When we want to understand cross-end (here refers to front-end and client cross-end), we usually need to master some basic knowledge, as follows:

1. Cross-end

Cross-end development of mobile front-end and client usually refers to using a technology or framework to simultaneously apply it to the front-end and client development of mobile applications. This cross-end technology typically uses Web technologies (such as HTML, CSS, and JavaScript) to develop applications and then integrates them into native applications through WebView or similar technologies.

In this cross-end development, front-end developers can use familiar Web technologies to develop applications without the need to learn and use native development languages ​​and tools. At the same time, client developers can use native development languages ​​and tools to integrate front-end developed applications.

2. Common mobile front-end and client cross-end technologies

1. React Native: React Native can use Web technology to develop applications and interact with native applications through JavaScript Bridge technology to achieve cross-end development.

2. Flutter: Flutter can use Web technology to develop applications and interact with native applications through Flutter Engine technology to achieve cross-end development.

3. WebView: WebView is a native control that can embed Web applications in native applications. Front-end developers can use Web technologies to develop applications and then integrate them into native applications through WebView technology.

4. Hybrid: Hybrid is a cross-end development model that combines native and Web technologies. Web technologies can be used to develop applications, and native technologies can be used to implement underlying functions.

3.1 React Native - ReactContextBaseJavaModule

From an attacker's perspective, I'm more concerned about how the front-end calls the client.

In React Native, Native Modules are used to encapsulate native functions into  functions or methods that JavaScript  can call.

In the native code, create a Native Module through which the client code can be called. For example, on the Android platform, you can create a Java class, implement  ReactContextBaseJavaModule the interface, and define a function in the class that can be called by JavaScript. The sample code is as follows

public class MyNativeModule extends ReactContextBaseJavaModule {
    private Context mContext;

    public MyNativeModule(ReactApplicationContext reactContext) {
        super(reactContext);
        mContext = reactContext;
    }

    @Override
    public String getName() {
        return "MyNativeModule";
    }

    @ReactMethod
    public void showSessionID() {
        Toast.makeText(mContext, getCookie(), Toast.LENGTH_SHORT).show();
    }
}

3.2 React Native - ReactApplication

Inherit ReactApplication and rewrite the getPackages function to register the module we created in 3.1.

import com.example.MyNativeModule;

...

public class MainApplication extends Application implements ReactApplication {
    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
        @Override
        public boolean getUseDeveloperSupport() {
            return BuildConfig.DEBUG;
        }

        @Override
        protected List<ReactPackage> getPackages() {
            return Arrays.asList(
                new MainReactPackage(),
                new MyNativeModule()
            );
        }
    };
}

3.3 React Native - Front-end call

The front end can directly trigger the nativemodule's showSessionID method through events.

import React from 'react';
import { TouchableOpacity, Text, NativeModules } from 'react-native';

const MyButton = () => {
  const onPress = () => {
    NativeModules.MyNativeModule.showSessionID();
  };

  return (
    <TouchableOpacity onPress={onPress}>
      <Text>Click me</Text>
    </TouchableOpacity>
  );
};

export default MyButton;

So if there is remote dynamic loading of some front-end code, or storage classes or other security issues can control the front-end code, then we can further call the registered client code, such as the above-mentioned sessionid.

4.1 webview -     @JavascriptInterface

Create a new javascript interface

class MyNativeInterface {
    @JavascriptInterface
    public void showCookie() {
        Toast.makeText(mContext, getcookie(), Toast.LENGTH_SHORT).show();
    }
}

4.2 webview -     addJavascriptInterface

Register the interface into the webview container

 

import android.webkit.WebView;
import android.webkit.WebViewClient;

...

public class MainActivity extends AppCompatActivity {
    private WebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWebView = findViewById(R.id.webView);
        mWebView.setWebViewClient(new MyWebViewClient());
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.addJavascriptInterface(new MyNativeInterface(), "MyNativeInterface");
    }
}

4.3 webview - front-end call

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>WebView Example</title>
</head>
<body>
  <button onclick="window.MyNativeInterface.showcookie()">Click me</button>
</body>
</html>

Webview attacks are relatively smooth, because as long as you open a webview container, you can have the opportunity to attack the registered cross-end interface. Scan, Deeplink, IM, search, etc.

5. Hybrid

Hybrid applications are more complex than ordinary WebView applications and need to implement some native functions in the client code, such as calling system APIs, accessing local databases, etc., a development model that combines Web technology and native technology for development Cross-platform applications. But the implementation principle is webview. So just refer to 4.1~4.3.

6. Flutter

The implementation principle is similar to React Native. Inherit MethodCallHandler to define the channel and write the cross-end method -> setMethodCallHandler registers the channel to Flutter -> the front end calls the cross-end method.

public class MyChannel implements MethodCallHandler {
    private static final String CHANNEL_NAME = "com.example.my_channel";

    private Context mContext;

    private MyChannel(Context context) {
        mContext = context;
    }

    public static void registerWith(Registrar registrar) {
        final MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL_NAME);
        channel.setMethodCallHandler(new MyChannel(registrar.context()));
    }

    @Override
    public void onMethodCall(MethodCall call, MethodChannel.Result result) {
        if (call.method.equals("showToast")) {
            String message = call.argument("message");
            Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();
            result.success(true);
        } else {
            result.notImplemented();
        }
    }
}


--------

import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.plugin.common.MethodChannel;

public class MainActivity extends FlutterActivity {
    private static final String CHANNEL_NAME = "com.example.my_channel";

    @Override
    public void configureFlutterEngine(FlutterEngine flutterEngine) {
        GeneratedPluginRegistrant.registerWith(flutterEngine);
        new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL_NAME)
                .setMethodCallHandler(new MyChannel(this));
    }
}


-----------
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

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

class MyApp extends StatelessWidget {
  static const platform = const MethodChannel('com.example.my_channel');

  void _showToast() async {
    try {
      await platform.invokeMethod('showToast', {'message': 'Hello, world!'});
    } on PlatformException catch (e) {
      print(e);
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Demo'),
        ),
        body: Center(
          child: RaisedButton(
            child: Text('Click me'),
            onPressed: _showToast,
          ),
        ),
      ),
    );
  }
}

Practical exercises

We reverse the APK, search whether the webview container has injected cross-end methods, and search globally for @JavascriptInterface

Then the found cross-end method analyzes the structure of the calling parameters and filters out all sensitive methods, then constructs the front-end calling point and triggers the client code.

For example poc

<script>window.xxxx.yyyy(aaa,bbb);

 

Afterword

Different application vendors may choose different solutions for cross-end applications, or develop some cross-end frameworks themselves. At this time, you may need to reverse-engineer the code logic before proceeding. In addition, cross-end calls are often not smooth sailing. Developers will add various restrictions, such as permission restrictions, access domain name restrictions, etc. This also requires further bypassing ideas, and this requires slowly diverging ideas and learning. 

Guess you like

Origin blog.csdn.net/xiru9972/article/details/131427321