Skip to content

Commit

Permalink
Merge branch 'MobSF:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
peku-jamf authored Jul 30, 2024
2 parents f44558a + a9de033 commit 62ead08
Show file tree
Hide file tree
Showing 82 changed files with 2,937 additions and 904 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/mobsf-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ on:
pull_request:
branches: [ master ]

env:
MOBSF_DISABLE_AUTHENTICATION: "1"

jobs:
build:
strategy:
Expand Down Expand Up @@ -59,6 +62,7 @@ jobs:
poetry run python manage.py makemigrations
poetry run python manage.py makemigrations StaticAnalyzer
poetry run python manage.py migrate
poetry run python manage.py create_roles
- name: Unit Tests on Ubuntu, macOS and Windows
run: |
Expand Down
52 changes: 28 additions & 24 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,24 @@ LABEL \
contributor_2="Vincent Nadal <[email protected]>" \
description="Mobile Security Framework (MobSF) is an automated, all-in-one mobile application (Android/iOS/Windows) pen-testing, malware analysis and security assessment framework capable of performing static and dynamic analysis."

ENV DEBIAN_FRONTEND=noninteractive
ENV DEBIAN_FRONTEND=noninteractive \
MOBSF_USER=mobsf \
USER_ID=9901 \
MOBSF_PLATFORM=docker \
MOBSF_ADB_BINARY=/usr/bin/adb \
JDK_FILE=openjdk-20.0.2_linux-x64_bin.tar.gz \
JDK_FILE_ARM=openjdk-20.0.2_linux-aarch64_bin.tar.gz \
WKH_FILE=wkhtmltox_0.12.6.1-2.jammy_amd64.deb \
WKH_FILE_ARM=wkhtmltox_0.12.6.1-2.jammy_arm64.deb \
JAVA_HOME=/jdk-20.0.2 \
PATH=$JAVA_HOME/bin:$PATH \
LANG=en_US.UTF-8 \
LANGUAGE=en_US:en \
LC_ALL=en_US.UTF-8 \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONFAULTHANDLER=1 \
POETRY_VERSION=1.6.1

# See https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run
RUN apt update -y && apt install -y --no-install-recommends \
Expand All @@ -37,32 +54,13 @@ RUN apt update -y && apt install -y --no-install-recommends \
locale-gen en_US.UTF-8 && \
apt upgrade -y

ENV MOBSF_USER=mobsf \
MOBSF_PLATFORM=docker \
MOBSF_ADB_BINARY=/usr/bin/adb \
JDK_FILE=openjdk-20.0.2_linux-x64_bin.tar.gz \
JDK_FILE_ARM=openjdk-20.0.2_linux-aarch64_bin.tar.gz \
WKH_FILE=wkhtmltox_0.12.6.1-2.jammy_amd64.deb \
WKH_FILE_ARM=wkhtmltox_0.12.6.1-2.jammy_arm64.deb \
JAVA_HOME=/jdk-20.0.2 \
PATH=$JAVA_HOME/bin:$PATH \
LANG=en_US.UTF-8 \
LANGUAGE=en_US:en \
LC_ALL=en_US.UTF-8 \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONFAULTHANDLER=1 \
POETRY_VERSION=1.6.1

# Install wkhtmltopdf & OpenJDK
ARG TARGETPLATFORM

COPY scripts/install_java_wkhtmltopdf.sh .
RUN ./install_java_wkhtmltopdf.sh

RUN groupadd -g 9901 $MOBSF_USER
RUN adduser $MOBSF_USER --shell /bin/false -u 9901 --ingroup $MOBSF_USER --gecos "" --disabled-password

# Install Python dependencies
COPY poetry.lock pyproject.toml ./
RUN python3 -m pip install --upgrade --no-cache-dir pip poetry==${POETRY_VERSION} && \
poetry config virtualenvs.create false && \
Expand All @@ -89,10 +87,13 @@ COPY . .
# Check if Postgres support needs to be enabled.
# Disabled by default
ARG POSTGRES=False

ENV POSTGRES_USER=postgres \
POSTGRES_PASSWORD=password \
POSTGRES_DB=mobsf \
POSTGRES_HOST=postgres
POSTGRES_HOST=postgres \
DJANGO_SUPERUSER_USERNAME=mobsf \
DJANGO_SUPERUSER_PASSWORD=mobsf

RUN ./scripts/postgres_support.sh $POSTGRES

Expand All @@ -101,8 +102,11 @@ HEALTHCHECK CMD curl --fail http://host.docker.internal:8000/ || exit 1
# Expose MobSF Port and Proxy Port
EXPOSE 8000 8000 1337 1337

RUN chown -R $MOBSF_USER:$MOBSF_USER /home/mobsf
USER mobsf
# Create mobsf user
RUN groupadd --gid $USER_ID $MOBSF_USER && \
useradd $MOBSF_USER --uid $USER_ID --gid $MOBSF_USER --shell /bin/false && \
chown -R $MOBSF_USER:$MOBSF_USER /home/mobsf
USER $MOBSF_USER

# Run MobSF
CMD ["/home/mobsf/Mobile-Security-Framework-MobSF/scripts/entrypoint.sh"]
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Mobile Security Framework (MobSF)
Version: v3.9 beta
Version: v4.0

![](https://cloud.githubusercontent.com/assets/4301109/20019521/cc61f7fc-a2f2-11e6-95f3-407030d9fdde.png)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,3 +196,22 @@ Java.perform(function() {
}
} catch(e){}
})

/* React Native JailMonkey Detection Bypass */

Java.perform(function() {
try{
let hook = Java.use("com.gantix.JailMonkey.JailMonkeyModule")['isDevelopmentSettingsMode'];
if (hook) {
hook.overload("com.facebook.react.bridge.Promise").implementation = function(p) {
p.resolve(Java.use("java.lang.Boolean").$new(false));
}
}
let hook2 = Java.use("com.gantix.JailMonkey.JailMonkeyModule")['isDebuggedMode'];
if (hook2) {
hook2.overload("com.facebook.react.bridge.Promise").implementation = function(p) {
p.resolve(Java.use("java.lang.Boolean").$new(false));
}
}
} catch(e){}
});
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,6 @@ Java.performNow(function () {
}
} catch (err) {
send('[RootDetection Bypass] Error ' + className + '.' + classMethod + err);
return
}

try {
Expand All @@ -183,7 +182,6 @@ Java.performNow(function () {
}
} catch (err) {
send('[RootDetection Bypass] Error ' + className + '.' + classMethod + err);
return
}
try {
className = 'android.security.keystore.KeyInfo'
Expand All @@ -203,7 +201,6 @@ Java.performNow(function () {
}
} catch (err) {
send('[RootDetection Bypass] Error ' + className + '.' + classMethod + err);
return
}

// Native Root Check Bypass
Expand Down Expand Up @@ -257,4 +254,53 @@ Java.performNow(function () {
int execvpe(const char *file, char *const argv[], char *const envp[]);
*/
});
});
Java.perform(function() {
// Bypassing Root in React Native JailMonkey
// Source: https://codeshare.frida.re/@RohindhR/react-native-jail-monkey-bypass-all-checks/
try {
let toHook = Java.use('com.gantix.JailMonkey.JailMonkeyModule')['getConstants'];
toHook.implementation = function() {
var hashmap = this.getConstants();
hashmap.put('isJailBroken', Java.use("java.lang.Boolean").$new(false));
hashmap.put('hookDetected', Java.use("java.lang.Boolean").$new(false));
hashmap.put('canMockLocation', Java.use("java.lang.Boolean").$new(false));
hashmap.put('isOnExternalStorage', Java.use("java.lang.Boolean").$new(false));
hashmap.put('AdbEnabled', Java.use("java.lang.Boolean").$new(false));
return hashmap;
}
} catch (err) {}
try{
// Bypassing Rooted Check
let hook = Java.use('com.gantix.JailMonkey.Rooted.RootedCheck')['getResultByDetectionMethod']
hook.implementation = function() {
let map = this.getResultByDetectionMethod();
map.put("jailMonkey", Java.use("java.lang.Boolean").$new(false));
return map;
}

} catch (err) {}
try{
// Bypassing Root detection method's result of RootBeer library
var className = 'com.gantix.JailMonkey.Rooted.RootedCheck$RootBeerResults';
let toHook = Java.use(className)['isJailBroken'];
toHook.implementation = function() {
return false;
};

let toHook2 = Java.use(className)['toNativeMap']
toHook2.implementation = function() {
var map = this.toNativeMap.call(this);
map.put("detectRootManagementApps", Java.use("java.lang.Boolean").$new(false));
map.put("detectPotentiallyDangerousApps", Java.use("java.lang.Boolean").$new(false));
map.put("checkForSuBinary", Java.use("java.lang.Boolean").$new(false));
map.put("checkForDangerousProps", Java.use("java.lang.Boolean").$new(false));
map.put("checkForRWPaths", Java.use("java.lang.Boolean").$new(false));
map.put("detectTestKeys", Java.use("java.lang.Boolean").$new(false));
map.put("checkSuExists", Java.use("java.lang.Boolean").$new(false));
map.put("checkForRootNative", Java.use("java.lang.Boolean").$new(false));
map.put("checkForMagiskBinary", Java.use("java.lang.Boolean").$new(false));
return map;
};
} catch (err) {}
})
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@ function captureStringCompare() {
send('Capturing string comparisons')
Interceptor.attach(ObjC.classes.__NSCFString['- isEqualToString:'].implementation, {
onEnter: function (args) {
var src = new ObjC.Object(ptr(args[0])).toString()
var str = new ObjC.Object(ptr(args[2])).toString()
send('[AUXILIARY] [__NSCFString isEqualToString:] -> '+ str);
send('[AUXILIARY] [__NSCFString isEqualToString:] -> \nstring 1: '+ src + '\nstring 2: '+ str);
}
});
}

function captureStringCompare2(){
Interceptor.attach(ObjC.classes.NSTaggedPointerString['- isEqualToString:'].implementation, {
onEnter: function (args) {
var src = new ObjC.Object(ptr(args[0])).toString()
var str = new ObjC.Object(ptr(args[2])).toString()
send('[AUXILIARY] NSTaggedPointerString[- isEqualToString:] -> '+ str);
send('[AUXILIARY] NSTaggedPointerString[- isEqualToString:] -> \nstring 1: '+ src + '\nstring 2: '+ str);
}
});
}
Expand Down
23 changes: 22 additions & 1 deletion mobsf/DynamicAnalyzer/views/android/dynamic_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,25 @@
get_proxy_ip,
is_md5,
print_n_send_error_response,
python_dict,
python_list,
strict_package_check,
)
from mobsf.MobSF.views.scanning import add_to_recent_scan
from mobsf.StaticAnalyzer.models import StaticAnalyzerAndroid
from mobsf.MobSF.views.authentication import (
login_required,
)
from mobsf.MobSF.views.authorization import (
Permissions,
permission_required,
)

logger = logging.getLogger(__name__)


@login_required
@permission_required(Permissions.SCAN)
def android_dynamic_analysis(request, api=False):
"""Android Dynamic Analysis Entry point."""
try:
Expand Down Expand Up @@ -104,6 +114,8 @@ def android_dynamic_analysis(request, api=False):
return print_n_send_error_response(request, exp, api)


@login_required
@permission_required(Permissions.SCAN)
def dynamic_analyzer(request, checksum, api=False):
"""Android Dynamic Analyzer Environment."""
try:
Expand Down Expand Up @@ -144,9 +156,11 @@ def dynamic_analyzer(request, checksum, api=False):
static_android_db.EXPORTED_ACTIVITIES)
activities = python_list(
static_android_db.ACTIVITIES)
deeplinks = python_dict(
static_android_db.BROWSABLE_ACTIVITIES)
except ObjectDoesNotExist:
logger.warning(
'Failed to get Activities. '
'Failed to get Activities/Deeplinks. '
'Static Analysis not completed for the app.')
env = Environment(identifier)
if not env.connect_n_mount():
Expand Down Expand Up @@ -207,6 +221,7 @@ def dynamic_analyzer(request, checksum, api=False):
'version': settings.MOBSF_VER,
'activities': activities,
'exported_activities': exported_activities,
'deeplinks': deeplinks,
'title': 'Dynamic Analyzer'}
template = 'dynamic_analysis/android/dynamic_analyzer.html'
if api:
Expand All @@ -220,6 +235,8 @@ def dynamic_analyzer(request, checksum, api=False):
api)


@login_required
@permission_required(Permissions.SCAN)
def httptools_start(request):
"""Start httprools UI."""
logger.info('Starting httptools Web UI')
Expand All @@ -241,6 +258,8 @@ def httptools_start(request):
return print_n_send_error_response(request, err)


@login_required
@permission_required(Permissions.SCAN)
def logcat(request, api=False):
logger.info('Starting Logcat streaming')
try:
Expand Down Expand Up @@ -284,6 +303,8 @@ def read_process():
return print_n_send_error_response(request, err, api)


@login_required
@permission_required(Permissions.SCAN)
def trigger_static_analysis(request, checksum):
"""On device APK Static Analysis."""
try:
Expand Down
4 changes: 2 additions & 2 deletions mobsf/DynamicAnalyzer/views/android/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ def get_environment(self):
return 'emulator'
elif (b'genymotion' in out.lower()
or any(char.isdigit() for char in ver)):
logger.info('Found Genymotion x86 Android VM')
logger.info('Found Genymotion Android VM')
return 'genymotion'
elif b'corellium' in out:
logger.info('Found Corellium ARM Android VM')
Expand Down Expand Up @@ -652,7 +652,7 @@ def frida_setup(self):
elif arch == 'x86_64':
frida_arch = 'x86_64'
else:
logger.error('Make sure a Genymotion Android x86 VM'
logger.error('Make sure a Genymotion Android VM'
' or Android Studio Emulator'
' instance is running')
return
Expand Down
2 changes: 2 additions & 0 deletions mobsf/DynamicAnalyzer/views/android/frida_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@ def api_handler(self, api):
loaded_class_methods = []
implementations = []
try:
if not self.extras:
return
raction = self.extras.get('rclass_action')
rclass = self.extras.get('rclass_name')
rclass_pattern = self.extras.get('rclass_pattern')
Expand Down
Loading

0 comments on commit 62ead08

Please sign in to comment.