ai_root_shield 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/CHANGELOG.md +56 -0
- data/Gemfile +16 -0
- data/Gemfile.lock +88 -0
- data/LICENSE +21 -0
- data/README.md +310 -0
- data/Rakefile +36 -0
- data/examples/device_logs/clean_device.json +74 -0
- data/examples/device_logs/rooted_android.json +93 -0
- data/exe/ai_root_shield +155 -0
- data/lib/ai_root_shield/analyzers/emulator_detector.rb +331 -0
- data/lib/ai_root_shield/analyzers/hooking_detector.rb +375 -0
- data/lib/ai_root_shield/analyzers/integrity_checker.rb +407 -0
- data/lib/ai_root_shield/analyzers/network_analyzer.rb +352 -0
- data/lib/ai_root_shield/analyzers/root_detector.rb +292 -0
- data/lib/ai_root_shield/detector.rb +78 -0
- data/lib/ai_root_shield/device_log_parser.rb +118 -0
- data/lib/ai_root_shield/risk_calculator.rb +161 -0
- data/lib/ai_root_shield/version.rb +5 -0
- data/lib/ai_root_shield.rb +36 -0
- metadata +179 -0
@@ -0,0 +1,352 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "openssl"
|
4
|
+
|
5
|
+
module AiRootShield
|
6
|
+
module Analyzers
|
7
|
+
# Analyzes network security configurations and detects MITM threats
|
8
|
+
class NetworkAnalyzer
|
9
|
+
# Known proxy and MITM tools
|
10
|
+
MITM_INDICATORS = %w[
|
11
|
+
burpsuite
|
12
|
+
charles
|
13
|
+
fiddler
|
14
|
+
owasp zap
|
15
|
+
mitmproxy
|
16
|
+
proxyman
|
17
|
+
wireshark
|
18
|
+
tcpdump
|
19
|
+
packet capture
|
20
|
+
http toolkit
|
21
|
+
proxydroid
|
22
|
+
drony
|
23
|
+
].freeze
|
24
|
+
|
25
|
+
# Suspicious certificate authorities
|
26
|
+
SUSPICIOUS_CA_PATTERNS = %w[
|
27
|
+
burp
|
28
|
+
portswigger
|
29
|
+
charles
|
30
|
+
fiddler
|
31
|
+
zap
|
32
|
+
mitmproxy
|
33
|
+
proxy
|
34
|
+
intercept
|
35
|
+
debug
|
36
|
+
test
|
37
|
+
].freeze
|
38
|
+
|
39
|
+
# VPN indicators that might be used for malicious purposes
|
40
|
+
SUSPICIOUS_VPN_PATTERNS = %w[
|
41
|
+
tor
|
42
|
+
onion
|
43
|
+
proxy
|
44
|
+
tunnel
|
45
|
+
bypass
|
46
|
+
unblock
|
47
|
+
hide
|
48
|
+
anonymous
|
49
|
+
].freeze
|
50
|
+
|
51
|
+
def analyze(device_data)
|
52
|
+
factors = []
|
53
|
+
risk_score = 0
|
54
|
+
|
55
|
+
# Check TLS/SSL configuration
|
56
|
+
tls_result = check_tls_configuration(device_data)
|
57
|
+
factors.concat(tls_result[:factors])
|
58
|
+
risk_score += tls_result[:risk_score]
|
59
|
+
|
60
|
+
# Check for custom CA certificates
|
61
|
+
ca_result = check_custom_certificates(device_data)
|
62
|
+
factors.concat(ca_result[:factors])
|
63
|
+
risk_score += ca_result[:risk_score]
|
64
|
+
|
65
|
+
# Check proxy configuration
|
66
|
+
proxy_result = check_proxy_configuration(device_data)
|
67
|
+
factors.concat(proxy_result[:factors])
|
68
|
+
risk_score += proxy_result[:risk_score]
|
69
|
+
|
70
|
+
# Check VPN configuration
|
71
|
+
vpn_result = check_vpn_configuration(device_data)
|
72
|
+
factors.concat(vpn_result[:factors])
|
73
|
+
risk_score += vpn_result[:risk_score]
|
74
|
+
|
75
|
+
# Check for MITM tools
|
76
|
+
mitm_result = check_mitm_tools(device_data)
|
77
|
+
factors.concat(mitm_result[:factors])
|
78
|
+
risk_score += mitm_result[:risk_score]
|
79
|
+
|
80
|
+
{
|
81
|
+
factors: factors,
|
82
|
+
risk_score: [risk_score, 100].min
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def check_tls_configuration(device_data)
|
89
|
+
factors = []
|
90
|
+
risk_score = 0
|
91
|
+
|
92
|
+
network_config = device_data[:network_config] || {}
|
93
|
+
tls_config = network_config[:tls_config] || {}
|
94
|
+
|
95
|
+
# Check if certificate pinning is disabled
|
96
|
+
if tls_config["pinning_disabled"] == true
|
97
|
+
factors << "TLS_UNPINNED"
|
98
|
+
risk_score += 12
|
99
|
+
end
|
100
|
+
|
101
|
+
# Check for weak TLS versions
|
102
|
+
tls_version = tls_config["version"]
|
103
|
+
if tls_version && (tls_version.include?("1.0") || tls_version.include?("1.1"))
|
104
|
+
factors << "WEAK_TLS_VERSION"
|
105
|
+
risk_score += 8
|
106
|
+
end
|
107
|
+
|
108
|
+
# Check for weak cipher suites
|
109
|
+
cipher_suites = tls_config["cipher_suites"] || []
|
110
|
+
weak_ciphers = %w[RC4 DES 3DES MD5 SHA1]
|
111
|
+
|
112
|
+
weak_ciphers.each do |weak_cipher|
|
113
|
+
if cipher_suites.any? { |cipher| cipher.to_s.upcase.include?(weak_cipher) }
|
114
|
+
factors << "WEAK_CIPHER_SUITE"
|
115
|
+
risk_score += 6
|
116
|
+
break
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Check for disabled certificate validation
|
121
|
+
if tls_config["cert_validation_disabled"] == true
|
122
|
+
factors << "CERTIFICATE_VALIDATION_DISABLED"
|
123
|
+
risk_score += 15
|
124
|
+
end
|
125
|
+
|
126
|
+
{
|
127
|
+
factors: factors,
|
128
|
+
risk_score: risk_score
|
129
|
+
}
|
130
|
+
end
|
131
|
+
|
132
|
+
def check_custom_certificates(device_data)
|
133
|
+
factors = []
|
134
|
+
risk_score = 0
|
135
|
+
|
136
|
+
certificates = device_data[:certificates] || []
|
137
|
+
network_config = device_data[:network_config] || {}
|
138
|
+
network_certificates = network_config[:certificates] || []
|
139
|
+
|
140
|
+
all_certificates = certificates + network_certificates
|
141
|
+
|
142
|
+
all_certificates.each do |cert|
|
143
|
+
next unless cert.is_a?(Hash)
|
144
|
+
|
145
|
+
# Check for suspicious CA names
|
146
|
+
issuer = cert["issuer"].to_s.downcase
|
147
|
+
subject = cert["subject"].to_s.downcase
|
148
|
+
|
149
|
+
SUSPICIOUS_CA_PATTERNS.each do |pattern|
|
150
|
+
if issuer.include?(pattern) || subject.include?(pattern)
|
151
|
+
factors << "CUSTOM_CA_INSTALLED"
|
152
|
+
risk_score += 15
|
153
|
+
break
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Check for user-installed certificates
|
158
|
+
if cert["user_installed"] == true
|
159
|
+
factors << "USER_CA_CERTIFICATE"
|
160
|
+
risk_score += 10
|
161
|
+
end
|
162
|
+
|
163
|
+
# Check for certificates with suspicious purposes
|
164
|
+
key_usage = cert["key_usage"].to_s.downcase
|
165
|
+
if key_usage.include?("digital signature") && key_usage.include?("key encipherment")
|
166
|
+
# This is normal, but combined with other factors might be suspicious
|
167
|
+
end
|
168
|
+
|
169
|
+
# Check for wildcard certificates from suspicious issuers
|
170
|
+
if subject.start_with?("*.") && SUSPICIOUS_CA_PATTERNS.any? { |pattern| issuer.include?(pattern) }
|
171
|
+
factors << "SUSPICIOUS_WILDCARD_CERT"
|
172
|
+
risk_score += 12
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
{
|
177
|
+
factors: factors,
|
178
|
+
risk_score: risk_score
|
179
|
+
}
|
180
|
+
end
|
181
|
+
|
182
|
+
def check_proxy_configuration(device_data)
|
183
|
+
factors = []
|
184
|
+
risk_score = 0
|
185
|
+
|
186
|
+
network_config = device_data[:network_config] || {}
|
187
|
+
proxy_settings = network_config[:proxy_settings] || {}
|
188
|
+
|
189
|
+
# Check if proxy is configured
|
190
|
+
if proxy_settings["enabled"] == true
|
191
|
+
proxy_host = proxy_settings["host"].to_s.downcase
|
192
|
+
proxy_port = proxy_settings["port"]
|
193
|
+
|
194
|
+
# Check for common MITM proxy ports
|
195
|
+
mitm_ports = [8080, 8888, 3128, 8081, 8082, 9090, 9999]
|
196
|
+
if mitm_ports.include?(proxy_port.to_i)
|
197
|
+
factors << "MITM_PROXY_PORT"
|
198
|
+
risk_score += 12
|
199
|
+
end
|
200
|
+
|
201
|
+
# Check for localhost/loopback proxy (common with MITM tools)
|
202
|
+
if proxy_host.include?("localhost") || proxy_host.include?("127.0.0.1") || proxy_host.include?("::1")
|
203
|
+
factors << "LOCALHOST_PROXY"
|
204
|
+
risk_score += 10
|
205
|
+
end
|
206
|
+
|
207
|
+
# Check for suspicious proxy hostnames
|
208
|
+
MITM_INDICATORS.each do |indicator|
|
209
|
+
if proxy_host.include?(indicator.downcase.gsub(" ", ""))
|
210
|
+
factors << "MITM_PROXY_DETECTED"
|
211
|
+
risk_score += 18
|
212
|
+
break
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
# Any proxy configuration is somewhat suspicious for mobile apps
|
217
|
+
factors << "PROXY_CONFIGURED"
|
218
|
+
risk_score += 6
|
219
|
+
end
|
220
|
+
|
221
|
+
{
|
222
|
+
factors: factors,
|
223
|
+
risk_score: risk_score
|
224
|
+
}
|
225
|
+
end
|
226
|
+
|
227
|
+
def check_vpn_configuration(device_data)
|
228
|
+
factors = []
|
229
|
+
risk_score = 0
|
230
|
+
|
231
|
+
network_config = device_data[:network_config] || {}
|
232
|
+
|
233
|
+
# Check if VPN is active
|
234
|
+
if network_config[:vpn_active] == true
|
235
|
+
factors << "VPN_ACTIVE"
|
236
|
+
risk_score += 5 # VPN itself is not necessarily malicious
|
237
|
+
|
238
|
+
# Check installed packages for VPN apps
|
239
|
+
packages = device_data[:installed_packages] || []
|
240
|
+
package_names = packages.map { |pkg| pkg.is_a?(Hash) ? pkg["name"] : pkg.to_s }
|
241
|
+
|
242
|
+
SUSPICIOUS_VPN_PATTERNS.each do |pattern|
|
243
|
+
if package_names.any? { |pkg| pkg.downcase.include?(pattern) }
|
244
|
+
factors << "VPN_SUSPICIOUS"
|
245
|
+
risk_score += 8
|
246
|
+
break
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
# Check for VPN-related processes
|
252
|
+
processes = device_data[:processes] || []
|
253
|
+
process_names = processes.map { |proc| proc.is_a?(Hash) ? proc["name"] : proc.to_s }
|
254
|
+
|
255
|
+
vpn_processes = %w[openvpn strongswan racoon vpnc]
|
256
|
+
vpn_processes.each do |vpn_proc|
|
257
|
+
if process_names.any? { |proc| proc.downcase.include?(vpn_proc) }
|
258
|
+
factors << "VPN_PROCESS_DETECTED"
|
259
|
+
risk_score += 4
|
260
|
+
break
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
{
|
265
|
+
factors: factors,
|
266
|
+
risk_score: risk_score
|
267
|
+
}
|
268
|
+
end
|
269
|
+
|
270
|
+
def check_mitm_tools(device_data)
|
271
|
+
factors = []
|
272
|
+
risk_score = 0
|
273
|
+
|
274
|
+
# Check installed packages for MITM tools
|
275
|
+
packages = device_data[:installed_packages] || []
|
276
|
+
package_names = packages.map { |pkg| pkg.is_a?(Hash) ? pkg["name"] : pkg.to_s }
|
277
|
+
|
278
|
+
MITM_INDICATORS.each do |indicator|
|
279
|
+
clean_indicator = indicator.downcase.gsub(" ", "")
|
280
|
+
if package_names.any? { |pkg| pkg.downcase.include?(clean_indicator) }
|
281
|
+
factors << "MITM_TOOL_INSTALLED"
|
282
|
+
risk_score += 20
|
283
|
+
break
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
# Check running processes for MITM tools
|
288
|
+
processes = device_data[:processes] || []
|
289
|
+
process_names = processes.map { |proc| proc.is_a?(Hash) ? proc["name"] : proc.to_s }
|
290
|
+
|
291
|
+
MITM_INDICATORS.each do |indicator|
|
292
|
+
clean_indicator = indicator.downcase.gsub(" ", "")
|
293
|
+
if process_names.any? { |proc| proc.downcase.include?(clean_indicator) }
|
294
|
+
factors << "MITM_TOOL_RUNNING"
|
295
|
+
risk_score += 22
|
296
|
+
break
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
# Check for packet capture capabilities
|
301
|
+
file_system = device_data[:file_system] || {}
|
302
|
+
system_binaries = file_system[:system_binaries] || []
|
303
|
+
|
304
|
+
packet_capture_tools = %w[tcpdump wireshark tshark dumpcap]
|
305
|
+
packet_capture_tools.each do |tool|
|
306
|
+
if system_binaries.any? { |binary| binary.to_s.downcase.include?(tool) }
|
307
|
+
factors << "PACKET_CAPTURE_TOOL"
|
308
|
+
risk_score += 15
|
309
|
+
break
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
# Check system logs for MITM activity
|
314
|
+
logs = device_data[:logs] || []
|
315
|
+
mitm_log_patterns = [
|
316
|
+
"certificate pinning",
|
317
|
+
"ssl kill switch",
|
318
|
+
"trust user certs",
|
319
|
+
"certificate transparency",
|
320
|
+
"proxy intercept"
|
321
|
+
]
|
322
|
+
|
323
|
+
mitm_log_patterns.each do |pattern|
|
324
|
+
if logs.any? { |log| log.to_s.downcase.include?(pattern) }
|
325
|
+
factors << "MITM_LOG_ACTIVITY"
|
326
|
+
risk_score += 12
|
327
|
+
break
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
{
|
332
|
+
factors: factors,
|
333
|
+
risk_score: risk_score
|
334
|
+
}
|
335
|
+
end
|
336
|
+
|
337
|
+
# Helper methods for TLS pinning (future feature)
|
338
|
+
def self.create_pin_for_certificate(cert_data)
|
339
|
+
# This would create a certificate pin for use in certificate pinning
|
340
|
+
# Implementation would depend on the certificate format and pinning strategy
|
341
|
+
digest = OpenSSL::Digest::SHA256.new
|
342
|
+
digest.digest(cert_data)
|
343
|
+
end
|
344
|
+
|
345
|
+
def self.validate_certificate_chain(cert_chain, trusted_roots)
|
346
|
+
# This would validate a certificate chain against trusted roots
|
347
|
+
# Implementation would use OpenSSL certificate verification
|
348
|
+
true # Placeholder
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
@@ -0,0 +1,292 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AiRootShield
|
4
|
+
module Analyzers
|
5
|
+
# Detects root/jailbreak indicators on Android and iOS devices
|
6
|
+
class RootDetector
|
7
|
+
# Known root/jailbreak binaries and files
|
8
|
+
ROOT_BINARIES = %w[
|
9
|
+
/system/bin/su
|
10
|
+
/system/xbin/su
|
11
|
+
/sbin/su
|
12
|
+
/vendor/bin/su
|
13
|
+
/system/app/Superuser.apk
|
14
|
+
/system/app/SuperSU.apk
|
15
|
+
/system/etc/init.d/99SuperSUDaemon
|
16
|
+
/dev/com.koushikdutta.superuser.daemon/
|
17
|
+
/system/xbin/daemonsu
|
18
|
+
/system/xbin/sugote
|
19
|
+
/system/xbin/sugote-mksh
|
20
|
+
/system/xbin/supolicy
|
21
|
+
/system/bin/.ext/.su
|
22
|
+
/cache/su
|
23
|
+
/data/local/su
|
24
|
+
/data/local/bin/su
|
25
|
+
/data/local/xbin/su
|
26
|
+
/system/sd/xbin/su
|
27
|
+
/system/bin/failsafe/su
|
28
|
+
/data/local/tmp/su
|
29
|
+
].freeze
|
30
|
+
|
31
|
+
JAILBREAK_FILES = %w[
|
32
|
+
/Applications/Cydia.app
|
33
|
+
/Library/MobileSubstrate/MobileSubstrate.dylib
|
34
|
+
/bin/bash
|
35
|
+
/usr/sbin/sshd
|
36
|
+
/etc/apt
|
37
|
+
/private/var/lib/apt/
|
38
|
+
/private/var/lib/cydia
|
39
|
+
/private/var/mobile/Library/SBSettings/Themes
|
40
|
+
/Library/MobileSubstrate/DynamicLibraries/Veency.plist
|
41
|
+
/Library/MobileSubstrate/DynamicLibraries/LiveClock.plist
|
42
|
+
/System/Library/LaunchDaemons/com.ikey.bbot.plist
|
43
|
+
/System/Library/LaunchDaemons/com.saurik.Cydia.Startup.plist
|
44
|
+
/etc/ssh/sshd_config
|
45
|
+
/var/tmp/cydia.log
|
46
|
+
/Applications/Icy.app
|
47
|
+
/Applications/MxTube.app
|
48
|
+
/Applications/RockApp.app
|
49
|
+
/Applications/blackra1n.app
|
50
|
+
/Applications/SBSettings.app
|
51
|
+
/Applications/FakeCarrier.app
|
52
|
+
/Applications/WinterBoard.app
|
53
|
+
/Applications/IntelliScreen.app
|
54
|
+
].freeze
|
55
|
+
|
56
|
+
ROOT_PACKAGES = %w[
|
57
|
+
com.noshufou.android.su
|
58
|
+
com.noshufou.android.su.elite
|
59
|
+
eu.chainfire.supersu
|
60
|
+
com.koushikdutta.superuser
|
61
|
+
com.thirdparty.superuser
|
62
|
+
com.yellowes.su
|
63
|
+
com.koushikdutta.rommanager
|
64
|
+
com.koushikdutta.rommanager.license
|
65
|
+
com.dimonvideo.luckypatcher
|
66
|
+
com.chelpus.lackypatch
|
67
|
+
com.ramdroid.appquarantine
|
68
|
+
com.ramdroid.appquarantinepro
|
69
|
+
com.topjohnwu.magisk
|
70
|
+
de.robv.android.xposed.installer
|
71
|
+
com.saurik.substrate
|
72
|
+
].freeze
|
73
|
+
|
74
|
+
JAILBREAK_PACKAGES = %w[
|
75
|
+
cydia
|
76
|
+
apt7
|
77
|
+
com.saurik.substrate.safemode
|
78
|
+
com.bigboss.categories.sbsettings
|
79
|
+
com.exile90.icleanerpro
|
80
|
+
winterboard
|
81
|
+
com.saurik.cydia.startup
|
82
|
+
com.saurik.mobilesubstrate
|
83
|
+
com.rpetrich.rocketbootstrap
|
84
|
+
preferenceloader
|
85
|
+
applist
|
86
|
+
com.saurik.substrate
|
87
|
+
].freeze
|
88
|
+
|
89
|
+
def analyze(device_data)
|
90
|
+
factors = []
|
91
|
+
risk_score = 0
|
92
|
+
|
93
|
+
# Check for root/jailbreak based on platform
|
94
|
+
case device_data[:platform]
|
95
|
+
when "android"
|
96
|
+
android_result = check_android_root(device_data)
|
97
|
+
factors.concat(android_result[:factors])
|
98
|
+
risk_score += android_result[:risk_score]
|
99
|
+
when "ios"
|
100
|
+
ios_result = check_ios_jailbreak(device_data)
|
101
|
+
factors.concat(ios_result[:factors])
|
102
|
+
risk_score += ios_result[:risk_score]
|
103
|
+
end
|
104
|
+
|
105
|
+
{
|
106
|
+
factors: factors,
|
107
|
+
risk_score: [risk_score, 100].min
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
def check_android_root(device_data)
|
114
|
+
factors = []
|
115
|
+
risk_score = 0
|
116
|
+
|
117
|
+
# Check for root binaries in file system
|
118
|
+
root_binaries_found = check_root_binaries(device_data[:file_system])
|
119
|
+
factors.concat(root_binaries_found)
|
120
|
+
risk_score += root_binaries_found.length * 15
|
121
|
+
|
122
|
+
# Check for root packages
|
123
|
+
root_packages_found = check_root_packages(device_data[:installed_packages])
|
124
|
+
factors.concat(root_packages_found)
|
125
|
+
risk_score += root_packages_found.length * 12
|
126
|
+
|
127
|
+
# Check SELinux status
|
128
|
+
selinux_factor = check_selinux_status(device_data[:system_info])
|
129
|
+
factors << selinux_factor if selinux_factor
|
130
|
+
risk_score += 20 if selinux_factor
|
131
|
+
|
132
|
+
# Check bootloader status
|
133
|
+
bootloader_factor = check_bootloader_status(device_data[:system_info])
|
134
|
+
factors << bootloader_factor if bootloader_factor
|
135
|
+
risk_score += 15 if bootloader_factor
|
136
|
+
|
137
|
+
# Check for suspicious system properties
|
138
|
+
prop_factors = check_system_properties(device_data[:system_info])
|
139
|
+
factors.concat(prop_factors)
|
140
|
+
risk_score += prop_factors.length * 8
|
141
|
+
|
142
|
+
{
|
143
|
+
factors: factors,
|
144
|
+
risk_score: risk_score
|
145
|
+
}
|
146
|
+
end
|
147
|
+
|
148
|
+
def check_ios_jailbreak(device_data)
|
149
|
+
factors = []
|
150
|
+
risk_score = 0
|
151
|
+
|
152
|
+
# Check for jailbreak files
|
153
|
+
jailbreak_files_found = check_jailbreak_files(device_data[:file_system])
|
154
|
+
factors.concat(jailbreak_files_found)
|
155
|
+
risk_score += jailbreak_files_found.length * 18
|
156
|
+
|
157
|
+
# Check for jailbreak packages/apps
|
158
|
+
jailbreak_packages_found = check_jailbreak_packages(device_data[:installed_packages])
|
159
|
+
factors.concat(jailbreak_packages_found)
|
160
|
+
risk_score += jailbreak_packages_found.length * 15
|
161
|
+
|
162
|
+
# Check for suspicious URL schemes
|
163
|
+
url_scheme_factors = check_url_schemes(device_data)
|
164
|
+
factors.concat(url_scheme_factors)
|
165
|
+
risk_score += url_scheme_factors.length * 10
|
166
|
+
|
167
|
+
{
|
168
|
+
factors: factors,
|
169
|
+
risk_score: risk_score
|
170
|
+
}
|
171
|
+
end
|
172
|
+
|
173
|
+
def check_root_binaries(file_system)
|
174
|
+
factors = []
|
175
|
+
suspicious_files = file_system[:suspicious_files] || []
|
176
|
+
system_binaries = file_system[:system_binaries] || []
|
177
|
+
|
178
|
+
all_files = suspicious_files + system_binaries
|
179
|
+
|
180
|
+
ROOT_BINARIES.each do |binary_path|
|
181
|
+
if all_files.any? { |file| file.to_s.include?(binary_path) }
|
182
|
+
factors << "ROOT_SU_FOUND"
|
183
|
+
break
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# Check for Superuser APK
|
188
|
+
if all_files.any? { |file| file.to_s.include?("Superuser.apk") }
|
189
|
+
factors << "ROOT_SUPERUSER_APK"
|
190
|
+
end
|
191
|
+
|
192
|
+
factors
|
193
|
+
end
|
194
|
+
|
195
|
+
def check_root_packages(packages)
|
196
|
+
factors = []
|
197
|
+
package_names = packages.map { |pkg| pkg.is_a?(Hash) ? pkg["name"] : pkg.to_s }
|
198
|
+
|
199
|
+
ROOT_PACKAGES.each do |root_pkg|
|
200
|
+
if package_names.any? { |pkg| pkg&.include?(root_pkg) }
|
201
|
+
case root_pkg
|
202
|
+
when /magisk/i
|
203
|
+
factors << "ROOT_MAGISK_DETECTED"
|
204
|
+
when /xposed/i
|
205
|
+
factors << "ROOT_XPOSED_DETECTED"
|
206
|
+
when /supersu|superuser/i
|
207
|
+
factors << "ROOT_SUPERUSER_DETECTED"
|
208
|
+
else
|
209
|
+
factors << "ROOT_PACKAGE_DETECTED"
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
factors
|
215
|
+
end
|
216
|
+
|
217
|
+
def check_jailbreak_files(file_system)
|
218
|
+
factors = []
|
219
|
+
suspicious_files = file_system[:suspicious_files] || []
|
220
|
+
|
221
|
+
JAILBREAK_FILES.each do |jb_file|
|
222
|
+
if suspicious_files.any? { |file| file.to_s.include?(jb_file) }
|
223
|
+
if jb_file.include?("Cydia")
|
224
|
+
factors << "JAILBREAK_CYDIA"
|
225
|
+
elsif jb_file.include?("MobileSubstrate")
|
226
|
+
factors << "JAILBREAK_SUBSTRATE"
|
227
|
+
else
|
228
|
+
factors << "JAILBREAK_FILE_DETECTED"
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
factors
|
234
|
+
end
|
235
|
+
|
236
|
+
def check_jailbreak_packages(packages)
|
237
|
+
factors = []
|
238
|
+
package_names = packages.map { |pkg| pkg.is_a?(Hash) ? pkg["name"] : pkg.to_s }
|
239
|
+
|
240
|
+
JAILBREAK_PACKAGES.each do |jb_pkg|
|
241
|
+
if package_names.any? { |pkg| pkg&.include?(jb_pkg) }
|
242
|
+
factors << "JAILBREAK_PACKAGE_DETECTED"
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
factors
|
247
|
+
end
|
248
|
+
|
249
|
+
def check_selinux_status(system_info)
|
250
|
+
selinux_status = system_info[:selinux_status]
|
251
|
+
return "SELINUX_PERMISSIVE" if selinux_status&.downcase&.include?("permissive")
|
252
|
+
return "SELINUX_DISABLED" if selinux_status&.downcase&.include?("disabled")
|
253
|
+
|
254
|
+
nil
|
255
|
+
end
|
256
|
+
|
257
|
+
def check_bootloader_status(system_info)
|
258
|
+
bootloader_status = system_info[:bootloader_status]
|
259
|
+
return "BOOTLOADER_UNLOCKED" if bootloader_status&.downcase&.include?("unlocked")
|
260
|
+
|
261
|
+
nil
|
262
|
+
end
|
263
|
+
|
264
|
+
def check_system_properties(system_info)
|
265
|
+
factors = []
|
266
|
+
|
267
|
+
# Check developer options
|
268
|
+
if system_info[:developer_options] == true
|
269
|
+
factors << "DEVELOPER_OPTIONS_ENABLED"
|
270
|
+
end
|
271
|
+
|
272
|
+
# Check build fingerprint for custom ROMs
|
273
|
+
fingerprint = system_info[:build_fingerprint]
|
274
|
+
if fingerprint&.include?("test-keys") || fingerprint&.include?("unofficial")
|
275
|
+
factors << "CUSTOM_ROM_DETECTED"
|
276
|
+
end
|
277
|
+
|
278
|
+
factors
|
279
|
+
end
|
280
|
+
|
281
|
+
def check_url_schemes(device_data)
|
282
|
+
factors = []
|
283
|
+
|
284
|
+
# This would typically check if the device can open jailbreak-specific URL schemes
|
285
|
+
# For now, we'll check if there are any suspicious network configurations
|
286
|
+
# that might indicate jailbreak tweaks
|
287
|
+
|
288
|
+
factors
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|