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.
@@ -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