Skip to content

Commit e90acee

Browse files
committed
chore: tests + demo update.
1 parent 06ac6fa commit e90acee

File tree

12 files changed

+278
-168
lines changed

12 files changed

+278
-168
lines changed

demos/android/MASVS-RESILIENCE/MASTG-DEMO-0023/MASTG-DEMO-0023.md

-32
This file was deleted.

demos/android/MASVS-RESILIENCE/MASTG-DEMO-0023/RootDetection.kt

-50
This file was deleted.

demos/android/MASVS-RESILIENCE/MASTG-DEMO-0023/root_detection.r2

-50
This file was deleted.

demos/android/MASVS-RESILIENCE/MASTG-DEMO-0023/run.sh

-1
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
platform: android
3+
title: Verifying root detection techniques in applications via static analysis
4+
code: [kotlin]
5+
id: MASTG-DEMO-0033
6+
test: MASTG-TEST-0245
7+
---
8+
9+
### Sample
10+
11+
The code snippet below shows sample code that performs root detection checks on the device.
12+
13+
{{ MastgTest.kt }}
14+
15+
### Steps
16+
17+
1. Let's run our @MASTG-TOOL-0110 rule against the reversed java code.
18+
19+
{{ ../../../../rules/mastg-android-root-detection.yml }}
20+
21+
{{ run.sh }}
22+
23+
### Observation
24+
25+
The output reveals the presence of root detection mechanisms in the app, including the use of `Runtime.getRuntime().exec` to check for the `su` command.
26+
27+
{{ output.txt }}
28+
29+
### Evaluation
30+
31+
The test passes because root detection checks are implemented in the app.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package org.owasp.mastestapp
2+
3+
import android.util.Log
4+
import android.content.Context
5+
import java.io.BufferedReader
6+
import java.io.File
7+
import java.io.IOException
8+
import java.io.InputStreamReader
9+
10+
class MastgTest(private val context: Context) {
11+
12+
companion object {
13+
private const val TAG = "RootCheck"
14+
}
15+
16+
fun mastgTest(): String {
17+
return when {
18+
checkRootFiles() || checkSuperUserApk() || checkSuCommand() || checkDangerousProperties() -> {
19+
"Device is rooted"
20+
}
21+
else -> {
22+
"Device is not rooted"
23+
}
24+
}
25+
}
26+
27+
private fun checkRootFiles(): Boolean {
28+
val rootPaths = setOf(
29+
"/system/app/Superuser.apk",
30+
"/system/xbin/su",
31+
"/system/bin/su",
32+
"/sbin/su",
33+
"/system/sd/xbin/su",
34+
"/system/bin/.ext/.su",
35+
"/system/usr/we-need-root/su-backup",
36+
"/system/xbin/mu"
37+
)
38+
rootPaths.forEach { path ->
39+
if (File(path).exists()) {
40+
Log.d(TAG, "Found root file: $path")
41+
}
42+
}
43+
return rootPaths.any { path -> File(path).exists() }
44+
}
45+
46+
private fun checkSuperUserApk(): Boolean {
47+
val superUserApk = File("/system/app/Superuser.apk")
48+
val exists = superUserApk.exists()
49+
if (exists) {
50+
Log.d(TAG, "Found Superuser.apk")
51+
}
52+
return exists
53+
}
54+
55+
private fun checkSuCommand(): Boolean {
56+
return try {
57+
val process = Runtime.getRuntime().exec(arrayOf("which", "su"))
58+
val reader = BufferedReader(InputStreamReader(process.inputStream))
59+
val result = reader.readLine()
60+
if (result != null) {
61+
Log.d(TAG, "su command found at: $result")
62+
true
63+
} else {
64+
Log.d(TAG, "su command not found")
65+
false
66+
}
67+
} catch (e: IOException) {
68+
Log.e(TAG, "Error checking su command: ${e.message}", e)
69+
false
70+
}
71+
}
72+
73+
private fun checkDangerousProperties(): Boolean {
74+
val dangerousProps = arrayOf("ro.debuggable", "ro.secure", "ro.build.tags")
75+
dangerousProps.forEach { prop ->
76+
val value = getSystemProperty(prop)
77+
if (value != null) {
78+
Log.d(TAG, "Dangerous property $prop: $value")
79+
if (value.contains("debug")) {
80+
return true
81+
}
82+
}
83+
}
84+
return false
85+
}
86+
87+
private fun getSystemProperty(prop: String): String? {
88+
return try {
89+
val process = Runtime.getRuntime().exec(arrayOf("getprop", prop))
90+
val reader = BufferedReader(InputStreamReader(process.inputStream))
91+
reader.readLine()
92+
} catch (e: IOException) {
93+
Log.e(TAG, "Error checking system property $prop: ${e.message}", e)
94+
null
95+
}
96+
}
97+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package org.owasp.mastestapp;
2+
3+
import android.content.Context;
4+
import android.util.Log;
5+
import java.io.BufferedReader;
6+
import java.io.File;
7+
import java.io.IOException;
8+
import java.io.InputStreamReader;
9+
import java.util.Collection;
10+
import kotlin.Metadata;
11+
import kotlin.collections.CollectionsKt;
12+
import kotlin.jvm.internal.Intrinsics;
13+
14+
/* compiled from: MastgTest.kt */
15+
@Metadata(d1 = {"\u0000 \n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0010\u000b\n\u0002\b\u0005\n\u0002\u0010\u000e\n\u0000\b\u0007\u0018\u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u00020\u0003¢\u0006\u0002\u0010\u0004J\r\u0010\u0005\u001a\u00020\u0006H\u0000¢\u0006\u0002\b\u0007J\r\u0010\b\u001a\u00020\u0006H\u0000¢\u0006\u0002\b\tJ\b\u0010\n\u001a\u00020\u0006H\u0002J\u0006\u0010\u000b\u001a\u00020\fR\u000e\u0010\u0002\u001a\u00020\u0003X\u0082\u0004¢\u0006\u0002\n\u0000¨\u0006\r"}, d2 = {"Lorg/owasp/mastestapp/MastgTest;", "", "context", "Landroid/content/Context;", "(Landroid/content/Context;)V", "checkRootFiles", "", "checkRootFiles$app_debug", "checkSuCommand", "checkSuCommand$app_debug", "checkSuperUserApk", "mastgTest", "", "app_debug"}, k = 1, mv = {1, 9, 0}, xi = 48)
16+
/* loaded from: classes4.dex */
17+
public final class MastgTest {
18+
public static final int $stable = 8;
19+
private final Context context;
20+
21+
public MastgTest(Context context) {
22+
Intrinsics.checkNotNullParameter(context, "context");
23+
this.context = context;
24+
}
25+
26+
public final String mastgTest() {
27+
if (checkRootFiles$app_debug() || checkSuperUserApk() || checkSuCommand$app_debug()) {
28+
return "Device is rooted";
29+
}
30+
return "Device is not rooted";
31+
}
32+
33+
public final boolean checkRootFiles$app_debug() {
34+
Iterable rootPaths = CollectionsKt.listOf((Object[]) new String[]{"/system/app/Superuser.apk", "/system/xbin/su", "/system/bin/su", "/sbin/su", "/system/sd/xbin/su", "/system/bin/.ext/.su", "/system/usr/we-need-root/su-backup", "/system/xbin/mu"});
35+
Iterable $this$forEach$iv = rootPaths;
36+
for (Object element$iv : $this$forEach$iv) {
37+
String path = (String) element$iv;
38+
if (new File(path).exists()) {
39+
Log.d("RootCheck", "Found root file: " + path);
40+
}
41+
}
42+
Iterable $this$any$iv = rootPaths;
43+
if (($this$any$iv instanceof Collection) && ((Collection) $this$any$iv).isEmpty()) {
44+
return false;
45+
}
46+
for (Object element$iv2 : $this$any$iv) {
47+
if (new File((String) element$iv2).exists()) {
48+
return true;
49+
}
50+
}
51+
return false;
52+
}
53+
54+
private final boolean checkSuperUserApk() {
55+
File superUserApk = new File("/system/app/Superuser.apk");
56+
if (superUserApk.exists()) {
57+
Log.d("RootCheck", "Found Superuser.apk");
58+
}
59+
return superUserApk.exists();
60+
}
61+
62+
public final boolean checkSuCommand$app_debug() {
63+
boolean z = false;
64+
try {
65+
Process process = Runtime.getRuntime().exec(new String[]{"which", "su"});
66+
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
67+
String result = reader.readLine();
68+
if (result != null) {
69+
Log.d("RootCheck", "su command found at: " + result);
70+
z = true;
71+
} else {
72+
Log.d("RootCheck", "su command not found");
73+
}
74+
} catch (IOException e) {
75+
Log.d("RootCheck", "Error checking su command: " + e.getMessage());
76+
}
77+
return z;
78+
}
79+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
3+
┌────────────────┐
4+
│ 1 Code Finding │
5+
└────────────────┘
6+
7+
MastgTest_reversed.java
8+
❱ rules.mastg-android-root-detection
9+
Root detection mechanisms have been identified in this application.
10+
11+
65┆ Process process = Runtime.getRuntime().exec(new String[]{"which", "su"});
12+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
NO_COLOR=true semgrep -c ../../../../rules/mastg-android-root-detection.yml ./MastgTest_reversed.java --text > output.txt
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
rules:
2+
- id: mastg-android-root-detection
3+
languages: [java, kotlin]
4+
severity: INFO
5+
message: Root detection mechanisms have been identified in this application.
6+
patterns:
7+
- pattern-either:
8+
- pattern: File("/system/app/Superuser.apk").exists()
9+
- pattern: File("/system/xbin/su").exists()
10+
- pattern: File("/system/bin/su").exists()
11+
- pattern: File("/sbin/su").exists()
12+
- pattern: File("/system/sd/xbin/su").exists()
13+
- pattern: File("/system/bin/.ext/.su").exists()
14+
- pattern: File("/system/usr/we-need-root/su-backup").exists()
15+
- pattern: File("/system/xbin/mu").exists()
16+
- pattern: Runtime.getRuntime().exec("which su")
17+
- pattern: Runtime.getRuntime().exec(arrayOf("which", "su"))
18+
- pattern: Runtime.getRuntime().exec(arrayOf("getprop", "ro.debuggable"))
19+
- pattern: Runtime.getRuntime().exec(arrayOf("getprop", "ro.secure"))
20+
- pattern: Runtime.getRuntime().exec(arrayOf("getprop", "ro.build.tags"))
21+
- pattern: Runtime.getRuntime().exec($_)
22+
- pattern-not: |
23+
try {
24+
Runtime.getRuntime().exec($_);
25+
} catch (Exception e) {
26+
$_;
27+
}

0 commit comments

Comments
 (0)