Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4.2.6 #2459

Merged
merged 8 commits into from
Nov 24, 2024
Merged

4.2.6 #2459

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion mobsf/MobSF/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

logger = logging.getLogger(__name__)

VERSION = '4.2.5'
VERSION = '4.2.6'
BANNER = r"""
__ __ _ ____ _____ _ _ ____
| \/ | ___ | |__/ ___|| ___|_ _| || | |___ \
Expand Down
12 changes: 2 additions & 10 deletions mobsf/MobSF/views/home.py
Original file line number Diff line number Diff line change
Expand Up @@ -480,15 +480,13 @@ def download(request):

@login_required
def generate_download(request):
"""Generate downloads for uploaded binaries/source."""
"""Generate downloads for smali/java zip."""
try:
binary = ('apk', 'ipa', 'jar', 'aar', 'so', 'dylib', 'a')
source = ('smali', 'java')
logger.info('Generating Downloads')
md5 = request.GET['hash']
file_type = request.GET['file_type']
if (not is_md5(md5)
or file_type not in binary + source):
or file_type not in ('smali', 'java')):
msg = 'Invalid download type or hash'
logger.exception(msg)
return print_n_send_error_response(request, msg)
Expand All @@ -509,12 +507,6 @@ def generate_download(request):
shutil.make_archive(
dwd_file.as_posix(), 'zip', directory.as_posix())
file_name = f'{md5}-smali.zip'
elif file_type in binary:
# Binaries
file_name = f'{md5}.{file_type}'
src = app_dir / file_name
dst = dwd_dir / file_name
shutil.copy2(src.as_posix(), dst.as_posix())
return redirect(f'/download/{file_name}')
except Exception:
msg = 'Generating Downloads'
Expand Down
2 changes: 1 addition & 1 deletion mobsf/StaticAnalyzer/tools/androguard4/apk.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from asn1crypto import cms, x509, keys

logger = logging.getLogger(__name__)
logger.setLevel(level=logging.INFO)
logger.setLevel(level=logging.CRITICAL)

NS_ANDROID_URI = 'http://schemas.android.com/apk/res/android'
NS_ANDROID = '{{{}}}'.format(NS_ANDROID_URI) # Namespace as used by etree
Expand Down
2 changes: 1 addition & 1 deletion mobsf/StaticAnalyzer/tools/androguard4/axml.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import logging

logger = logging.getLogger(__name__)
logger.setLevel(level=logging.INFO)
logger.setLevel(level=logging.CRITICAL)

# Constants for ARSC Files
# see http://aospxref.com/android-13.0.0_r3/xref/frameworks/base/libs/androidfw/include/androidfw/ResourceTypes.h#233
Expand Down
36 changes: 22 additions & 14 deletions mobsf/StaticAnalyzer/views/android/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,31 @@ def get_app_name(a, app_dir, is_apk):
if is_apk:
if a:
# Parsed Androguard APK Object
return a.get_app_name()
else:
# Look for app_name in values folder.
val = base / 'apktool_out' / 'res' / 'values'
if val.exists():
try:
return a.get_app_name()
except Exception:
logger.warning('Failed to get app name from parsed APK object')
# Look for app_name in values folder.
val = base / 'apktool_out' / 'res' / 'values'
if val.exists():
try:
return get_app_name_from_values_folder(val.as_posix())
except Exception:
logger.error('Failed to get app name from values folder')
else:
# For source code
strings_path = base / 'app' / 'src' / 'main' / 'res' / 'values'
eclipse_path = base / 'res' / 'values'
if strings_path.exists():
return get_app_name_from_values_folder(
strings_path.as_posix())
elif eclipse_path.exists():
return get_app_name_from_values_folder(
eclipse_path.as_posix())
logger.warning('Cannot find values folder.')
try:
strings_path = base / 'app' / 'src' / 'main' / 'res' / 'values'
eclipse_path = base / 'res' / 'values'
if strings_path.exists():
return get_app_name_from_values_folder(
strings_path.as_posix())
elif eclipse_path.exists():
return get_app_name_from_values_folder(
eclipse_path.as_posix())
except Exception:
logger.error('Failed to get app name')
logger.warning('Cannot find app name')
return ''


Expand Down
8 changes: 6 additions & 2 deletions mobsf/StaticAnalyzer/views/android/icon_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,12 @@ def get_icon_src(a, app_dic, res_dir):
icon_resolution = 0xFFFE - 1
icon_name = None
if a:
icon_name = a.get_app_icon(max_dpi=icon_resolution)
if icon_name and is_path_traversal(icon_name):
try:
icon_name = a.get_app_icon(max_dpi=icon_resolution)
if icon_name and is_path_traversal(icon_name):
icon_name = None
except Exception:
logger.warning('Failed to get icon from parsed APK object')
icon_name = None
if not icon_name:
# androguard cannot find icon file.
Expand Down
14 changes: 14 additions & 0 deletions mobsf/StaticAnalyzer/views/android/kb/dvm_permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,20 @@
'UPDATE_PACKAGES_WITHOUT_USER_ACTION': ['normal', 'allows updating packages without requiring user action.', 'Allows an application to indicate via PackageInstaller.SessionParams.setRequireUserAction(int) that user action should not be required for an app update.'],
'USE_EXACT_ALARM': ['normal', 'allows using exact alarms without user permission.', 'Allows apps to use exact alarms just like with SCHEDULE_EXACT_ALARM but without needing to request this permission from the user. This is only intended for use by apps that rely on exact alarms for their core functionality. You should continue using SCHEDULE_EXACT_ALARM if your app needs exact alarms for a secondary feature that users may or may not use within your app. Keep in mind that this is a powerful permission and app stores may enforce policies to audit and review the use of this permission. Such audits may involve removal from the app store if the app is found to be misusing this permission.'],
'UWB_RANGING': ['dangerous', 'required for ranging to devices using ultra-wideband.', 'Required to be able to range to devices using ultra-wideband.'],
'ACCESS_HIDDEN_PROFILES': ['normal', 'Add support for private space by declaring the ACCESS_HIDDEN_PROFILES permission.', 'Allows applications to access profiles with android.content.pm.UserProperties#PROFILE_API_VISIBILITY_HIDDEN user property, e.g. UserManager.USER_TYPE_PROFILE_PRIVATE .'],
'BIND_APP_FUNCTION_SERVICE': ['signature', 'This must be required by an AppFunctionService to ensure that only the system is permitted to bind to it.', 'Must be required by an AppFunctionService , to ensure that only the system can bind to it.'],
'FOREGROUND_SERVICE_MEDIA_PROCESSING': ['normal', 'Allows a regular application to invoke Service.startForeground using the type "mediaProcessing".', 'Allows a regular application to use Service.startForeground with the type "mediaProcessing".'],
'MANAGE_DEVICE_POLICY_ASSIST_CONTENT': ['internal', 'Grants an application the ability to configure policies for sharing assist content with privileged apps, such as the Assistant app.', 'Allows an application to set policy related to sending assist content to a privileged app such as the Assistant app.'],
'DETECT_SCREEN_RECORDING': ['normal', 'Grants an application the ability to receive notifications when audio or screen recording is in progress.', 'Allows an application to get notified when it is being recorded.'],
'MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL': ['internal', 'Allows an application to control policies that prevent the uninstallation of specific packages.', 'Allows an application to manage policy related to block package uninstallation.'],
'MANAGE_DEVICE_POLICY_CAMERA_TOGGLE': ['internal', 'Allows an application to enforce policies that control the state of the camera toggle.', 'Allows an application to manage policy related to camera toggle.'],
'MANAGE_DEVICE_POLICY_CONTENT_PROTECTION': ['internal', 'Grants an application the ability to enforce policies that restrict the uninstallation of designated packages.', 'Allows an application to manage policy related to content protection.'],
'MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS': ['internal', 'Grants an application the ability to configure policies for managing subscriptions downloaded by an administrator.', 'Allows an application to set policy related to subscriptions downloaded by an admin.'],
'MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE': ['internal', 'Grants an application the ability to control policies for managing the microphone toggle state.', 'Allows an application to manage policy related to microphone toggle.'],
'MEDIA_ROUTING_CONTROL': ['normal', 'Allows an application to manage the routing of media applications, restricted to use by the role COMPANION_DEVICE_WATCH.', 'Allows an application to control the routing of media apps. Only for use by role COMPANION_DEVICE_WATCH'],
'READ_DROPBOX_DATA': ['normal', 'Allows an application to access data stored in Dropbox, intended exclusively for use by system-level or first-party applications, and not available for third-party applications.', 'Allows an application to access the data in Dropbox. Not for use by third-party applications.'],
'SET_BIOMETRIC_DIALOG_ADVANCED': ['normal', 'Allows an application to customize BiometricDialog features, including logo and content view. Restricted to system use only.', 'Allows an application to set the advanced features on BiometricDialog (SystemUI), including logo, logo description, and content view with more options button. Not for use by third-party applications.'],
'ACCESS_ORIENTATION': ['normal', 'Allows an application to access the device\'s orientation.', 'Allows an application to access the device\'s orientation.'],
},

'SPECIAL_PERMISSIONS': {
Expand Down
78 changes: 71 additions & 7 deletions mobsf/StaticAnalyzer/views/android/rules/android_permissions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,10 @@
- getLastKnownLocation\(
- getBestProvider\(
- sendExtraCommand\(
- getScanResults\(
- startDiscovery\(
- enableReaderMode\(
- requestPeers\(
input_case: exact
severity: info
- id: android.permission.ACCESS_FINE_LOCATION
Expand Down Expand Up @@ -692,6 +696,11 @@
- sendExtraCommand\(
- Manifest\.permission\.ACCESS_FINE_LOCATION
- Context\.LOCATION_SERVICE
- addGeofences\(
- getScanResults\(
- startDiscovery\(
- enableReaderMode\(
- requestActivityTransitionUpdates\(
input_case: exact
severity: info
- id: android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
Expand All @@ -706,7 +715,7 @@
message: android.permission.WAKE_LOCK
type: RegexAndOr
pattern:
- android\.media\.AsyncPlayer|android\.media\.MediaPlayer|android\.media\.Ringtone|android\.media\.RingtoneManager|android\.net\.sip|android\.net\.wifi|android\.os\.PowerManager|android\.widget\.VideoView|com\.android\.server
- android\.media\.AsyncPlayer|android\.media\.MediaPlayer|android\.media\.Ringtone|android\.media\.RingtoneManager|android\.net\.sip|android\.net\.wifi|android\.os\.PowerManager|android\.widget\.VideoView|com\.android\.server|android\.app\.DownloadManager|androidx\.work\.WorkManager|android\.app\.AlarmManager|com\.google\.android\.gms\.location
- - stopPreviousRingtone\(
- acquire\(
- endCall\(
Expand Down Expand Up @@ -738,6 +747,10 @@
- start\(
- stopPlayback\(
- suspend\(
- enqueue\(
- setAndAllowWhileIdle\(
- setExactAndAllowWhileIdle\(
- requestLocationUpdates\(
input_case: exact
severity: info
- id: android.permission.MODIFY_AUDIO_SETTINGS
Expand Down Expand Up @@ -3759,11 +3772,12 @@
message: android.permission.DELETE_PACKAGES
type: RegexAndOr
pattern:
- com\.android\.server
- com\.android\.server|android\.content\.Intent
- - uninstall\(
- deletePackage\(
- deletePackageAsUser\(
- setBlockUninstallForUser\(
- Intent\.ACTION_UNINSTALL_PACKAGE
input_case: exact
severity: info
- id: android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS
Expand Down Expand Up @@ -5342,8 +5356,12 @@
message: android.permission.FOREGROUND_SERVICE
type: RegexAndOr
pattern:
- android\.content\.Context
- android\.content\.Context|android\.app\.Service|android\.media|androidx\.work\.WorkManager
- - startForegroundService\(
- startForeground\(
- stopForeground\(
- stopSelf\(
- enqueue\(
input_case: exact
severity: info
- id: android.permission.POST_NOTIFICATIONS
Expand All @@ -5370,6 +5388,18 @@
- createBond\(
input_case: exact
severity: info
- id: android.permission.BLUETOOTH_ADVERTISE
message: android.permission.BLUETOOTH_ADVERTISE
type: RegexAndOr
pattern:
- android\.bluetooth|com\.google\.android\.gms\.nearby\.connection
- - startAdvertising\(
- stopAdvertising\(
- addService\(
- openGattServer\(
- getConnectionsClient\(
input_case: exact
severity: info
- id: android.permission.BLUETOOTH_SCAN
message: android.permission.BLUETOOTH_SCAN
type: RegexAndOr
Expand Down Expand Up @@ -5440,15 +5470,14 @@
message: com.google.android.c2dm.permission.RECEIVE
type: RegexAndOr
pattern:
- android\.content\.Intent
- - com\.google\.android\.c2dm\.intent\.REGISTRATION"
input_case: exact
- android\.content\.Intent|com\.google\.android\.gms\.gcm
- - com\.google\.android\.c2dm\.intent\.REGISTRATION|com\.google\.firebase\.messaging|onNewToken\(|onMessageReceived\(
severity: info
- id: com.google.android.c2dm.permission.SEND
message: com.google.android.c2dm.permission.SEND
type: RegexAndOr
pattern:
- android\.content\.Intent
- android\.content\.Intent|com\.google\.android\.gms\.gcm
- - com\.google\.android\.c2dm\.intent\.REGISTER
input_case: exact
severity: info
Expand Down Expand Up @@ -5481,3 +5510,38 @@
- getExternalStorageDirectory\(
input_case: exact
severity: info
- id: com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE
message: com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE
type: RegexAndOr
pattern:
- com\.android\.installreferrer\.api
- - newBuilder\(
- getInstallReferrer\(
- getReferrerClickTimestampSeconds\(
- getInstallBeginTimestampSeconds\(
- onInstallReferrerServiceDisconnected\(
- endConnection\(
input_case: exact
severity: info
- id: com.google.android.gms.permission.AD_ID
message: com.google.android.gms.permission.AD_ID
type: RegexAndOr
pattern:
- com\.google\.android\.gms\.ads
- - getAdvertisingIdInfo\(
- getDetectedActivity\(
- \.isLimitAdTrackingEnabled
input_case: exact
severity: info
- id: android.permission.ACCESS_ORIENTATION
message: android.permission.ACCESS_ORIENTATION
type: RegexAndOr
pattern:
- android\.hardware\.Sensor
- - getDefaultSensor\(
- \.TYPE_ACCELEROMETER
- onSensorChanged\(
- getRotationMatrix\(
- onAccuracyChanged\(
input_case: exact
severity: info
81 changes: 46 additions & 35 deletions mobsf/StaticAnalyzer/views/android/strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,51 +52,62 @@ def strings_from_so(checksum, elf_strings):

def strings_from_apk(checksum, apk):
"""Extract Strings from an APK."""
dat = []
secrets = []
urls = []
urls_nf = []
emails_nf = []
firebase_creds = {}
results = {
'strings': [],
'urls_list': [],
'urls_nf': [],
'emails_nf': [],
'secrets': [],
'firebase_creds': {},
}
try:
msg = 'Extracting String data from APK'
logger.info(msg)
append_scan_status(checksum, msg)

rsrc = apk.get_android_resources()
if rsrc:
pkg = rsrc.get_packages_names()[0]
rsrc.get_strings_resources()
for i in rsrc.values[pkg].keys():
res_string = rsrc.values[pkg][i].get('string')
if not res_string:
if not rsrc:
return results

pkg = rsrc.get_packages_names()[0]
rsrc.get_strings_resources()

# Iterate over resource strings
for _res_key, res_value in rsrc.values.get(pkg, {}).items():
res_string = res_value.get('string')
if not res_string:
continue

for key, value in res_string:
if not value:
continue
for duo in res_string:
if (duo[0] == 'google_api_key'
and GOOGLE_API_KEY_REGEX.match(duo[1])):
firebase_creds['google_api_key'] = duo[1]
if (duo[0] == 'google_app_id'
and GOOGLE_APP_ID_REGEX.match(duo[1])):
firebase_creds['google_app_id'] = duo[1]
cap_str = '"' + duo[0] + '" : "' + duo[1] + '"'
# Extract possible secret holding keys
if is_secret_key(duo[0] + '"') and ' ' not in duo[1]:
secrets.append(cap_str)
dat.append(cap_str)
# Extract URLs and Emails from Android String Resources
urls, urls_nf, emails_nf = url_n_email_extract(
''.join(dat), 'Android String Resource')

# Extract Firebase credentials
if key == 'google_api_key' and GOOGLE_API_KEY_REGEX.match(value):
results['firebase_creds']['google_api_key'] = value
elif key == 'google_app_id' and GOOGLE_APP_ID_REGEX.match(value):
results['firebase_creds']['google_app_id'] = value

# Format and collect strings
formatted_str = f'"{key}" : "{value}"'
results['strings'].append(formatted_str)

# Check for possible secrets
if is_secret_key(key) and ' ' not in value:
results['secrets'].append(formatted_str)

# Extract URLs and Emails from collected strings
results['strings'] = list(set(results['strings']))
ul, u_nf, e_nf = url_n_email_extract(
''.join(results['strings']), 'Android String Resource')
results['urls_list'], results['urls_nf'], results['emails_nf'] = ul, u_nf, e_nf

except Exception as exp:
msg = 'Failed to extract String data from APK'
logger.exception(msg)
append_scan_status(checksum, msg, repr(exp))
return {
'strings': list(set(dat)),
'urls_list': urls,
'urls_nf': urls_nf,
'emails_nf': emails_nf,
'secrets': secrets,
'firebase_creds': firebase_creds,
}

return results


def strings_from_code(checksum, src_dir, typ, exts):
Expand Down
Loading
Loading