diff --git a/Dockerfile b/Dockerfile index 8cc692f741..89180a2cb4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,24 @@ LABEL \ contributor_2="Vincent Nadal " \ 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 \ @@ -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 && \ @@ -104,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"] diff --git a/mobsf/DynamicAnalyzer/tools/frida_scripts/android/default/debugger_check_bypass.js b/mobsf/DynamicAnalyzer/tools/frida_scripts/android/default/debugger_check_bypass.js index aa50c92d3d..8ae94fa651 100644 --- a/mobsf/DynamicAnalyzer/tools/frida_scripts/android/default/debugger_check_bypass.js +++ b/mobsf/DynamicAnalyzer/tools/frida_scripts/android/default/debugger_check_bypass.js @@ -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){} +}); \ No newline at end of file diff --git a/mobsf/DynamicAnalyzer/tools/frida_scripts/android/default/root_bypass.js b/mobsf/DynamicAnalyzer/tools/frida_scripts/android/default/root_bypass.js index 3ca264049f..3defe9e745 100644 --- a/mobsf/DynamicAnalyzer/tools/frida_scripts/android/default/root_bypass.js +++ b/mobsf/DynamicAnalyzer/tools/frida_scripts/android/default/root_bypass.js @@ -163,7 +163,6 @@ Java.performNow(function () { } } catch (err) { send('[RootDetection Bypass] Error ' + className + '.' + classMethod + err); - return } try { @@ -183,7 +182,6 @@ Java.performNow(function () { } } catch (err) { send('[RootDetection Bypass] Error ' + className + '.' + classMethod + err); - return } try { className = 'android.security.keystore.KeyInfo' @@ -203,7 +201,6 @@ Java.performNow(function () { } } catch (err) { send('[RootDetection Bypass] Error ' + className + '.' + classMethod + err); - return } // Native Root Check Bypass @@ -257,4 +254,53 @@ Java.performNow(function () { int execvpe(const char *file, char *const argv[], char *const envp[]); */ -}); \ No newline at end of file +}); +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) {} +}) \ No newline at end of file diff --git a/mobsf/MobSF/init.py b/mobsf/MobSF/init.py index b41dc746df..22465dc383 100644 --- a/mobsf/MobSF/init.py +++ b/mobsf/MobSF/init.py @@ -10,7 +10,7 @@ logger = logging.getLogger(__name__) -VERSION = '4.0.2' +VERSION = '4.0.3' BANNER = """ __ __ _ ____ _____ _ _ ___ | \/ | ___ | |__/ ___|| ___|_ _| || | / _ \ diff --git a/mobsf/StaticAnalyzer/views/android/rules/android_rules.yaml b/mobsf/StaticAnalyzer/views/android/rules/android_rules.yaml index 79453deb62..8fa738f1d1 100644 --- a/mobsf/StaticAnalyzer/views/android/rules/android_rules.yaml +++ b/mobsf/StaticAnalyzer/views/android/rules/android_rules.yaml @@ -161,6 +161,23 @@ owasp-mobile: m1 masvs: platform-7 ref: https://github.com/MobSF/owasp-mstg/blob/master/Document/0x05h-Testing-Platform-Interaction.md#testing-javascript-execution-in-webviews-mstg-platform-5 +- id: android_webview_allow_file_from_url + message: >- + Ensure that user controlled URLs never reaches the Webview. Enabling file access + from URLs in WebView can leak sensitive information from the file system. + type: RegexAndOr + pattern: + - setJavaScriptEnabled\(true\) + - - \.setAllowFileAccessFromFileURLs\(true\) + - \.setAllowUniversalAccessFromFileURLs\(true\) + severity: warning + input_case: exact + metadata: + cvss: 6.1 + cwe: cwe-200 + owasp-mobile: m1 + masvs: platform-7 + ref: https://github.com/MobSF/owasp-mstg/blob/master/Document/0x05h-Testing-Platform-Interaction.md#static-analysis-6 - id: android_sql_cipher_aes256 message: >- This App uses SQL Cipher. SQLCipher provides 256-bit AES encryption to diff --git a/mobsf/StaticAnalyzer/views/common/shared_func.py b/mobsf/StaticAnalyzer/views/common/shared_func.py index a8c90bd854..d62086dcb1 100755 --- a/mobsf/StaticAnalyzer/views/common/shared_func.py +++ b/mobsf/StaticAnalyzer/views/common/shared_func.py @@ -198,31 +198,28 @@ def ar_extract(src, dst): def url_n_email_extract(dat, relative_path): """Extract URLs and Emails from Source Code.""" - urls = [] - emails = [] + urls = set() + emails = set() urllist = [] url_n_file = [] email_n_file = [] # URL Extraction urllist = URL_REGEX.findall(dat.lower()) - uflag = 0 for url in urllist: - if url not in urls: - urls.append(url) - uflag = 1 - if uflag == 1: - url_n_file.append( - {'urls': urls, 'path': escape(relative_path)}) + urls.add(url) + if urls: + url_n_file.append({ + 'urls': list(urls), + 'path': escape(relative_path)}) # Email Extraction - eflag = 0 for email in EMAIL_REGEX.findall(dat.lower()): - if (email not in emails) and (not email.startswith('//')): - emails.append(email) - eflag = 1 - if eflag == 1: - email_n_file.append( - {'emails': emails, 'path': escape(relative_path)}) + if not email.startswith('//'): + emails.add(email) + if emails: + email_n_file.append({ + 'emails': list(emails), + 'path': escape(relative_path)}) return urllist, url_n_file, email_n_file diff --git a/poetry.lock b/poetry.lock index 975fdcd193..ecec144e77 100644 --- a/poetry.lock +++ b/poetry.lock @@ -348,13 +348,13 @@ beautifulsoup4 = "*" [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.6.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"}, + {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, ] [[package]] @@ -736,24 +736,24 @@ dotenv = ["python-dotenv"] [[package]] name = "frida" -version = "16.2.5" +version = "16.3.1" description = "Dynamic instrumentation toolkit for developers, reverse-engineers, and security researchers" optional = false python-versions = ">=3.7" files = [ - {file = "frida-16.2.5-cp37-abi3-macosx_10_13_x86_64.whl", hash = "sha256:2ad75fce6507641b92e9910be81d894631ae7d4b0c61a7cd0f2224edb963e186"}, - {file = "frida-16.2.5-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:746286dc3e44c21beec3e7818038ce175df2debd850780343564b27995f78d6c"}, - {file = "frida-16.2.5-cp37-abi3-manylinux1_i686.whl", hash = "sha256:6ff76a814e1a1fbf492a380c5ace4e415a71bd71f40d250f1593517a31bcc504"}, - {file = "frida-16.2.5-cp37-abi3-manylinux1_x86_64.whl", hash = "sha256:9f05a10c63ce2ef2063e2288ac497c8be311c39664b658f4757003a3ff6a546b"}, - {file = "frida-16.2.5-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:d0c6082a37c7814d45daddb9744febd52dba691e5c0ef5db2660e66e1b266b6e"}, - {file = "frida-16.2.5-cp37-abi3-manylinux2014_armv7l.whl", hash = "sha256:af2d6077aced6c47fe94014f5a0680e541c49897b030b383b8666acd70f015e0"}, - {file = "frida-16.2.5-cp37-abi3-manylinux_2_17_aarch64.whl", hash = "sha256:f53212a24fb190aa10738021f2f8e402ee305621f0bbc528b8de3ff1182d6d0c"}, - {file = "frida-16.2.5-cp37-abi3-manylinux_2_17_armv7l.whl", hash = "sha256:06779eb8e8412c407c55dd1476a18f43232a916dc5fc80dcf1247d2bc1ded553"}, - {file = "frida-16.2.5-cp37-abi3-manylinux_2_5_i686.whl", hash = "sha256:d3dfd8206f05e832c00163ba9630a007b0ad83a766225c72f3a3134b50f0d808"}, - {file = "frida-16.2.5-cp37-abi3-manylinux_2_5_x86_64.whl", hash = "sha256:3a1dcf378e370e58af76c8dff5ea93d3c59025193d493b69dc23c48170dafe65"}, - {file = "frida-16.2.5-cp37-abi3-win32.whl", hash = "sha256:6ee90623b2945964b72169a56de12a6d23996b1c93d4310ab3942060cca5e42e"}, - {file = "frida-16.2.5-cp37-abi3-win_amd64.whl", hash = "sha256:42650e5a0595e527cb8fd909e2b32b9d6601ac4dd23b0d051ea46241d13cd6a7"}, - {file = "frida-16.2.5.tar.gz", hash = "sha256:4804e136fd344bbd5d22fee10e38bcbd6762a6f388e36e5146c55ea64b8cbe52"}, + {file = "frida-16.3.1-cp37-abi3-macosx_10_13_x86_64.whl", hash = "sha256:48dfc17d03700a6e9d0270a187a35360c8abac52a4d8ad88b4ac8cc4308c8b60"}, + {file = "frida-16.3.1-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:735ce89036d1e2f92af85a1763c3110cb7fec4b0204dcd1b18ffd7a21723d27a"}, + {file = "frida-16.3.1-cp37-abi3-manylinux1_i686.whl", hash = "sha256:e95f335cf93d6f3ce0e7533c5e6dc3914ba3694283f25721a8da8f5aa6d9ff76"}, + {file = "frida-16.3.1-cp37-abi3-manylinux1_x86_64.whl", hash = "sha256:e3c98b03f49ea325b98e9095b73fe581a7b7aa8e4d6190a65f4e32505de30b44"}, + {file = "frida-16.3.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:5086c2ccadd4ebdba7a98b721cb9ae1b208270373fb15f39b207b4b0742cad47"}, + {file = "frida-16.3.1-cp37-abi3-manylinux2014_armv7l.whl", hash = "sha256:20acfe2eff088e41b677d59747d2f6dbfee8aaab09223d6ca46fb29f4fda63f2"}, + {file = "frida-16.3.1-cp37-abi3-manylinux_2_17_aarch64.whl", hash = "sha256:0230989bef733f95d65c72544e5b13983c2d5b4b48e22c0ba0c06ff70e150cc4"}, + {file = "frida-16.3.1-cp37-abi3-manylinux_2_17_armv7l.whl", hash = "sha256:de2425faa66a1769ea3eb299eb90fc007cb1922fd1f9a7dc5e22da18dc088902"}, + {file = "frida-16.3.1-cp37-abi3-manylinux_2_5_i686.whl", hash = "sha256:35f60b36cd7abad510dfa8889ff39ee332d129e28cfabd6c0d8830122ca8d733"}, + {file = "frida-16.3.1-cp37-abi3-manylinux_2_5_x86_64.whl", hash = "sha256:c01dcfc1e2b8a4d6bd3ea4381c54e54a10e169c046b8f9593444fb729b4de646"}, + {file = "frida-16.3.1-cp37-abi3-win32.whl", hash = "sha256:c637c3c4f6281e4677c48d91030ead6ed52c5066908a69ab170658414d12355d"}, + {file = "frida-16.3.1-cp37-abi3-win_amd64.whl", hash = "sha256:b3770d3040a51e60bcd33f6080b6d3c93e8950cea23773044b07b46e5bbfc02f"}, + {file = "frida-16.3.1.tar.gz", hash = "sha256:652f7badc6f27dd8e08a6fb9ba63265d277b37c54f360e521241675a65a9c82f"}, ] [package.dependencies] @@ -1852,13 +1852,13 @@ files = [ [[package]] name = "requests" -version = "2.32.2" +version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" files = [ - {file = "requests-2.32.2-py3-none-any.whl", hash = "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c"}, - {file = "requests-2.32.2.tar.gz", hash = "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -2285,13 +2285,13 @@ telegram = ["requests"] [[package]] name = "typing-extensions" -version = "4.12.0" +version = "4.12.1" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.12.0-py3-none-any.whl", hash = "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"}, - {file = "typing_extensions-4.12.0.tar.gz", hash = "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8"}, + {file = "typing_extensions-4.12.1-py3-none-any.whl", hash = "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a"}, + {file = "typing_extensions-4.12.1.tar.gz", hash = "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1"}, ] [[package]] diff --git a/pyproject.toml b/pyproject.toml index eeaaa898fa..42bc0717b3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "mobsf" -version = "4.0.2" +version = "4.0.3" 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." keywords = ["mobsf", "mobile security framework", "mobile security", "security tool", "static analysis", "dynamic analysis", "malware analysis"] authors = ["Ajin Abraham "] diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh index 8893c7bc8a..e6ec00668f 100755 --- a/scripts/entrypoint.sh +++ b/scripts/entrypoint.sh @@ -4,7 +4,9 @@ set -e python3 manage.py makemigrations && \ python3 manage.py makemigrations StaticAnalyzer && \ python3 manage.py migrate +set +e python3 manage.py createsuperuser --noinput --email "" +set -e python3 manage.py create_roles exec gunicorn -b 0.0.0.0:8000 "mobsf.MobSF.wsgi:application" --workers=1 --threads=10 --timeout=3600 \