Skip to content

Commit

Permalink
add support to log the secrets from BoringSSL when it is used in the …
Browse files Browse the repository at this point in the history
…android mono runtime
  • Loading branch information
monkeywave committed Oct 30, 2024
1 parent 3c53f66 commit 74b319b
Show file tree
Hide file tree
Showing 8 changed files with 514 additions and 118 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
</p>

# friTap
![version](https://img.shields.io/badge/version-1.2.2.8-blue) [![PyPI version](https://d25lcipzij17d.cloudfront.net/badge.svg?id=py&r=r&ts=1683906897&type=6e&v=1.2.2.8&x2=0)](https://badge.fury.io/py/friTap)
![version](https://img.shields.io/badge/version-1.2.3.0-blue) [![PyPI version](https://d25lcipzij17d.cloudfront.net/badge.svg?id=py&r=r&ts=1683906897&type=6e&v=1.2.3.0&x2=0)](https://badge.fury.io/py/friTap)

The goal of this project is to help researchers to analyze traffic encapsulated in SSL or TLS. For details have a view into the [OSDFCon webinar slides](assets/friTapOSDFConwebinar.pdf) or in [this blog post](https://lolcads.github.io/posts/2022/08/fritap/).

Expand Down
5 changes: 3 additions & 2 deletions agent/android/android_agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { java_execute} from "./android_java_tls_libs.js";
import { cronet_execute } from "./cronet_android.js";
import { flutter_execute } from "./flutter_android.js";
import { s2ntls_execute } from "./s2ntls_android.js";

import { mono_btls_execute } from "./mono_btls_android.js";

var plattform_name = "linux";
var moduleNames: Array<string> = getModuleNames();
Expand Down Expand Up @@ -84,7 +84,8 @@ export function load_android_hooking_agent() {
[/.*libwolfssl\.so/, invokeHookingFunction(wolfssl_execute)],
[/.*libnspr[0-9]?\.so/,invokeHookingFunction(nss_execute)],
[/libmbedtls\.so.*/, invokeHookingFunction(mbedTLS_execute)],
[/.*libs2n.so/, invokeHookingFunction(s2ntls_execute)]];
[/.*libs2n.so/, invokeHookingFunction(s2ntls_execute)],
[/.*mono-btls.*\.so/, invokeHookingFunction(mono_btls_execute)]];

install_java_hooks();
hook_native_Android_SSL_Libs(module_library_mapping, true);
Expand Down
86 changes: 86 additions & 0 deletions agent/android/mono_btls_android.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@

import { Mono_BTLS } from "../ssl_lib/monobtls.js";
import { socket_library } from "./android_agent.js";
import {PatternBasedHooking, get_CPU_specific_pattern } from "../shared/pattern_based_hooking.js";
import { patterns, isPatternReplaced } from "../ssl_log.js"
import { devlog, devlog_error } from "../util/log.js";


export class Mono_BTLS_Android extends Mono_BTLS {
private default_pattern: { [arch: string]: { primary: string; fallback: string } };

constructor(public moduleName:string, public socket_library:String, is_base_hook: boolean){
super(moduleName,socket_library,is_base_hook);

this.default_pattern = {
"x64": {
primary: "55 41 57 41 56 41 54 53 49 89 D4 49 89 F6 48 89 FB E8 5A F8 FF FF", // Primary pattern
fallback: "55 41 57 41 56 41 55 41 54 53 48 83 EC 38 48 8B 47 68 48 83 B8 10 02 00 00 00 0F 84 19 01 00 00" // Fallback pattern
},
"x86": {
primary: "55 89 E5 53 57 56 83 E4 F0 83 EC 10 E8 00 00 00 00", // Primary pattern
fallback: "55 53 57 56 83 EC 4C E8 00 00 00 00 5B 81 C3 A9 CB 13 00 8B 44 24 60 8B 40 34" // Fallback pattern
},
"arm64": {
primary: "F6 57 BD A9 F4 4F 01 A9 FD 7B 02 A9 FD 83 00 91 F3 03 02 AA F4 03 01 AA F5 03 00 AA 1F FE FF 97", // Primary pattern
fallback: "FF 83 01 D1 F6 1B 00 F9 F5 53 04 A9 F3 7B 05 A9 08 34 40 F9 08 09 41 F9 68 07 00 B4" // Fallback pattern
},
"arm": {
primary: "F0 B5 03 AF 4D F8 04 8D 14 46 0D 46 06 46 FF F7 5F FD", // Primary pattern
fallback: "2D E9 F0 41 86 B0 04 46 40 6B D0 F8 30 01 00 28 53 D0" // Fallback pattern
}
};
}




install_key_extraction_hook(){
const flutterModule = Process.findModuleByName(this.module_name);
const hooker = new PatternBasedHooking(flutterModule);

if (isPatternReplaced()){
devlog("Hooking Libmono functions by patterns from JSON file");
hooker.hook_DumpKeys(this.module_name,"libmono-btls-shared.so",patterns,(args: any[]) => {
this.dumpKeys(args[1], args[0], args[2]); // Unpack args into dumpKeys
});
}else{
// This are the default patterns for hooking ssl_log_secret in BoringSSL inside Libmono
hooker.hookModuleByPattern(
get_CPU_specific_pattern(this.default_pattern),
(args) => {
this.dumpKeys(args[1], args[0], args[2]); // Hook args passed to dumpKeys
}
);
}

}

execute_hooks(){
this.install_key_extraction_hook();
}

}


export function mono_btls_execute(moduleName:string, is_base_hook: boolean){
var mono_btls = new Mono_BTLS_Android(moduleName,socket_library,is_base_hook);
try {
mono_btls.execute_hooks();
}catch(error_msg){
devlog_error(`mono_btls_execute error: ${error_msg}`)
}

if (is_base_hook) {
try {
const init_addresses = mono_btls.addresses[moduleName];
// ensure that we only add it to global when we are not
if (Object.keys(init_addresses).length > 0) {
(global as any).init_addresses[moduleName] = init_addresses;
}
}catch(error_msg){
devlog_error(`mono_btls_execute base-hook error: ${error_msg}`)
}
}

}
2 changes: 1 addition & 1 deletion agent/ssl_lib/flutter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export class Flutter {
devlog("[Error] Argument 'key' is NULL");
}

//devlog("invoking ssl_log_secret() from BoringSSL statically linked into Cronet");
//devlog("invoking ssl_log_secret() from BoringSSL statically linked into Flutter");
var message: { [key: string]: string | number | null } = {}
message["contentType"] = "keylog"
message["keylog"] = labelStr+" "+client_random+" "+secret_key;
Expand Down
125 changes: 125 additions & 0 deletions agent/ssl_lib/monobtls.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { get_hex_string_from_byte_array, readAddresses } from "../shared/shared_functions.js";
import { devlog } from "../util/log.js";




export class Mono_BTLS {


// global variables
library_method_mapping: { [key: string]: Array<string> } = {};
addresses: { [libraryName: string]: { [functionName: string]: NativePointer } };
module_name: string;
is_base_hook: boolean;


constructor(public moduleName:string, public socket_library:String,is_base_hook: boolean ,public passed_library_method_mapping?: { [key: string]: Array<string> } ){
this.module_name = moduleName;
this.is_base_hook = is_base_hook;

if(typeof passed_library_method_mapping !== 'undefined'){
this.library_method_mapping = passed_library_method_mapping;
}else{
this.library_method_mapping[`*${socket_library}*`] = ["getpeername", "getsockname", "ntohs", "ntohl"]
}

this.addresses = readAddresses(moduleName,this.library_method_mapping);
}

get_client_random(s3_ptr: NativePointer, SSL3_RANDOM_SIZE: number): string {
if (!s3_ptr.isNull()) {
const client_random_ptr: NativePointer = s3_ptr.add(0x30); // Offset in s3 struct
//@ts-ignore
const client_random = Memory.readByteArray(client_random_ptr, SSL3_RANDOM_SIZE);

// Convert the byte array to a hex string
const hexClientRandom = get_hex_string_from_byte_array(new Uint8Array(client_random as ArrayBuffer));

return hexClientRandom;
} else {
devlog("[Error] s3 pointer is NULL");
return "";
}
}

get_client_random_from_ssl_struct(ssl_st_ptr: NativePointer): string {
const SSL3_RANDOM_SIZE = 32;
let offset_s3: number;

switch (Process.arch) {
case 'x64':
offset_s3 = 0x30;
break;
case 'arm64':
offset_s3 = 0x30;
break;
case 'ia32':
offset_s3 = 0x2C;
break;
case 'arm':
offset_s3 = 0x2C;
break;
default:
devlog("[Error] Unsupported architecture");
return "";
}

const s3_ptr = ssl_st_ptr.add(offset_s3).readPointer();
return this.get_client_random(s3_ptr, SSL3_RANDOM_SIZE);
}


dumpKeys(labelPtr: NativePointer, sslStructPtr: NativePointer, keyPtr: NativePointer): void {
const KEY_LENGTH = 32; // Assuming key length is 32 bytes

let labelStr = '';
let client_random = '';
let secret_key = '';

// Read the label (the label pointer might contain a C string)
if (!labelPtr.isNull()) {
labelStr = labelPtr.readCString() ?? ''; // Read label as a C string
//devlog(`Label: ${labelStr}`);
} else {
devlog("[Error] Argument 'labelPtr' is NULL");
}

// Extract client_random from the SSL structure
if (!sslStructPtr.isNull()) {
client_random = this.get_client_random_from_ssl_struct(sslStructPtr)
}else {
devlog("[Error] Argument 'sslStructPtr' is NULL");
}

if (!keyPtr.isNull()) {
//@ts-ignore
const keyData = Memory.readByteArray(keyPtr, KEY_LENGTH); // Read the key data (KEY_LENGTH bytes)

// Convert the byte array to a string of hex values
const hexKey = get_hex_string_from_byte_array(keyData);

secret_key = hexKey;
} else {
devlog("[Error] Argument 'key' is NULL");
}

//devlog("invoking ssl_log_secret() from BoringSSL statically linked into Mono BTLS");
var message: { [key: string]: string | number | null } = {}
message["contentType"] = "keylog"
message["keylog"] = labelStr+" "+client_random+" "+secret_key;
send(message)
}

install_plaintext_read_hook(){
// TBD
}

install_plaintext_write_hook(){
// TBD
}

install_key_extraction_hook(){
// needs to be setup for the specific plattform
}
}
Loading

0 comments on commit 74b319b

Please sign in to comment.