Initial commit — SetecSuite Camera MITM Framework
Original tooling from the Camhak research project (camera teardown of a
rebranded UBIA / Javiscam IP camera). PyQt6 GUI on top of a curses TUI on
top of a service controller; per-service start/stop, intruder detection,
protocol fingerprinting, OAM HMAC signing, CVE verifiers, OTA bucket
probe, firmware fetcher, fuzzer, packet injection.
Tabs: Dashboard, Live Log, Intruders, Cloud API, Fuzzer, Inject, CVEs,
Config, Help. Real-time per-packet protocol detection, conntrack-based
original-destination lookup, log rotation at 1 GiB.
See SECURITY_PAPER.md for the full writeup, site/index.html for the
public report, README.md for usage. Run with:
sudo /usr/bin/python3 gui.py
Co-authored by Setec Labs.
This commit is contained in:
19
iotc/build_bridge.sh
Executable file
19
iotc/build_bridge.sh
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
# Build the IOTC bridge program for ARM32 (runs under qemu-arm-static)
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
SODIR="$(pwd)/lib"
|
||||
|
||||
echo "Compiling IOTC bridge (dynamic, hard-float)..."
|
||||
arm-linux-gnueabihf-gcc -o iotc/iotc_bridge iotc/iotc_bridge.c -L"$SODIR" -lIOTCAPIs_ALL -lpthread -Wl,-rpath,"$SODIR"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Success: $(file iotc/iotc_bridge)"
|
||||
echo ""
|
||||
echo "Test with:"
|
||||
echo " qemu-arm-static -L /usr/arm-linux-gnueabi iotc/iotc_bridge"
|
||||
echo " Then type: init"
|
||||
else
|
||||
echo "Build failed"
|
||||
exit 1
|
||||
fi
|
||||
BIN
iotc/iotc_bridge
Executable file
BIN
iotc/iotc_bridge
Executable file
Binary file not shown.
269
iotc/iotc_bridge.c
Normal file
269
iotc/iotc_bridge.c
Normal file
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* IOTC Bridge — ARM32 process that loads the TUTK library and
|
||||
* communicates with the Python TUI over stdin/stdout JSON.
|
||||
*
|
||||
* Compile: arm-linux-gnueabi-gcc -o iotc_bridge iotc_bridge.c -L../lib -lIOTCAPIs_ALL -lpthread -ldl
|
||||
* Run: qemu-arm-static -L /usr/arm-linux-gnueabi ./iotc_bridge
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/* IOTC API declarations (from IOTCAPIs.h) */
|
||||
extern int IOTC_Initialize2(int udp_port);
|
||||
extern int IOTC_DeInitialize(void);
|
||||
extern int IOTC_Get_SessionID(void);
|
||||
extern int IOTC_Connect_ByUID_Parallel(const char *UID, int SID);
|
||||
extern int IOTC_Session_Close(int SID);
|
||||
extern int IOTC_Session_Check(int SID, void *info);
|
||||
extern int IOTC_Lan_Search2(void *result, int max, int timeout_ms);
|
||||
|
||||
/* AV API declarations (from AVAPIs.h) */
|
||||
extern int avInitialize(int max_channels);
|
||||
extern int avDeInitialize(void);
|
||||
extern int avClientStart(int SID, const char *user, const char *pass,
|
||||
int timeout, unsigned int *srvtype, int channel);
|
||||
extern void avClientStop(int avIndex);
|
||||
extern int avSendIOCtrl(int avIndex, int type, const char *data, int len);
|
||||
extern int avRecvIOCtrl(int avIndex, int *type, char *data, int len, int timeout_ms);
|
||||
|
||||
/* Simple JSON output helpers */
|
||||
static void json_ok(const char *key, int value) {
|
||||
printf("{\"ok\":true,\"%s\":%d}\n", key, value);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void json_ok_str(const char *key, const char *value) {
|
||||
printf("{\"ok\":true,\"%s\":\"%s\"}\n", key, value);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void json_err(const char *msg) {
|
||||
printf("{\"ok\":false,\"error\":\"%s\"}\n", msg);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void json_data(const char *cmd, const unsigned char *data, int len) {
|
||||
printf("{\"ok\":true,\"cmd\":\"%s\",\"len\":%d,\"hex\":\"", cmd, len);
|
||||
for (int i = 0; i < len && i < 4096; i++)
|
||||
printf("%02x", data[i]);
|
||||
printf("\"}\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
/* State */
|
||||
static int g_sid = -1;
|
||||
static int g_av_index = -1;
|
||||
static int g_initialized = 0;
|
||||
|
||||
static int do_init(void) {
|
||||
if (g_initialized) {
|
||||
json_err("already initialized");
|
||||
return -1;
|
||||
}
|
||||
int ret = IOTC_Initialize2(0);
|
||||
if (ret < 0) {
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "IOTC_Initialize2 failed: %d", ret);
|
||||
json_err(buf);
|
||||
return ret;
|
||||
}
|
||||
ret = avInitialize(16);
|
||||
if (ret < 0) {
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "avInitialize failed: %d", ret);
|
||||
json_err(buf);
|
||||
return ret;
|
||||
}
|
||||
g_initialized = 1;
|
||||
json_ok("init", 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_connect(const char *uid) {
|
||||
if (!g_initialized) {
|
||||
json_err("not initialized");
|
||||
return -1;
|
||||
}
|
||||
int sid = IOTC_Get_SessionID();
|
||||
if (sid < 0) {
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "IOTC_Get_SessionID failed: %d", sid);
|
||||
json_err(buf);
|
||||
return sid;
|
||||
}
|
||||
g_sid = IOTC_Connect_ByUID_Parallel(uid, sid);
|
||||
if (g_sid < 0) {
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "connect failed: %d", g_sid);
|
||||
json_err(buf);
|
||||
return g_sid;
|
||||
}
|
||||
json_ok("sid", g_sid);
|
||||
return g_sid;
|
||||
}
|
||||
|
||||
static int do_login(const char *user, const char *pass) {
|
||||
if (g_sid < 0) {
|
||||
json_err("not connected");
|
||||
return -1;
|
||||
}
|
||||
unsigned int srvtype = 0;
|
||||
g_av_index = avClientStart(g_sid, user, pass, 20, &srvtype, 0);
|
||||
if (g_av_index < 0) {
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "avClientStart failed: %d", g_av_index);
|
||||
json_err(buf);
|
||||
return g_av_index;
|
||||
}
|
||||
json_ok("av_index", g_av_index);
|
||||
return g_av_index;
|
||||
}
|
||||
|
||||
static int do_ioctrl(int cmd_type, const char *hex_data) {
|
||||
if (g_av_index < 0) {
|
||||
json_err("not logged in");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Parse hex data */
|
||||
int hex_len = strlen(hex_data);
|
||||
int data_len = hex_len / 2;
|
||||
unsigned char *data = calloc(1, data_len + 1);
|
||||
for (int i = 0; i < data_len; i++) {
|
||||
unsigned int byte;
|
||||
sscanf(hex_data + i * 2, "%2x", &byte);
|
||||
data[i] = (unsigned char)byte;
|
||||
}
|
||||
|
||||
int ret = avSendIOCtrl(g_av_index, cmd_type, (const char *)data, data_len);
|
||||
free(data);
|
||||
|
||||
if (ret < 0) {
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "avSendIOCtrl failed: %d", ret);
|
||||
json_err(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Try to receive response */
|
||||
unsigned char resp[8192];
|
||||
int resp_type = 0;
|
||||
int resp_len = avRecvIOCtrl(g_av_index, &resp_type, (char *)resp, sizeof(resp), 5000);
|
||||
if (resp_len > 0) {
|
||||
json_data("ioctrl_resp", resp, resp_len);
|
||||
} else {
|
||||
json_ok("sent", cmd_type);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_lan_search(void) {
|
||||
if (!g_initialized) {
|
||||
json_err("not initialized");
|
||||
return -1;
|
||||
}
|
||||
/* Search result struct: 84 bytes per entry (UID[20] + IP[16] + ...)] */
|
||||
unsigned char results[84 * 16];
|
||||
memset(results, 0, sizeof(results));
|
||||
int count = IOTC_Lan_Search2(results, 16, 3000);
|
||||
if (count < 0) {
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "lan_search failed: %d", count);
|
||||
json_err(buf);
|
||||
return count;
|
||||
}
|
||||
printf("{\"ok\":true,\"count\":%d,\"devices\":[", count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
unsigned char *entry = results + (i * 84);
|
||||
char uid[21] = {0};
|
||||
memcpy(uid, entry, 20);
|
||||
if (i > 0) printf(",");
|
||||
printf("\"%s\"", uid);
|
||||
}
|
||||
printf("]}\n");
|
||||
fflush(stdout);
|
||||
return count;
|
||||
}
|
||||
|
||||
static void do_disconnect(void) {
|
||||
if (g_av_index >= 0) {
|
||||
avClientStop(g_av_index);
|
||||
g_av_index = -1;
|
||||
}
|
||||
if (g_sid >= 0) {
|
||||
IOTC_Session_Close(g_sid);
|
||||
g_sid = -1;
|
||||
}
|
||||
json_ok("disconnected", 1);
|
||||
}
|
||||
|
||||
static void do_deinit(void) {
|
||||
do_disconnect();
|
||||
if (g_initialized) {
|
||||
avDeInitialize();
|
||||
IOTC_DeInitialize();
|
||||
g_initialized = 0;
|
||||
}
|
||||
json_ok("deinit", 1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char line[8192];
|
||||
|
||||
fprintf(stderr, "IOTC Bridge started. Send JSON commands on stdin.\n");
|
||||
|
||||
while (fgets(line, sizeof(line), stdin)) {
|
||||
/* Strip newline */
|
||||
line[strcspn(line, "\r\n")] = 0;
|
||||
if (strlen(line) == 0) continue;
|
||||
|
||||
/* Very simple command parsing: cmd arg1 arg2 ... */
|
||||
char cmd[64] = {0};
|
||||
char arg1[256] = {0};
|
||||
char arg2[256] = {0};
|
||||
char arg3[8192] = {0};
|
||||
sscanf(line, "%63s %255s %255s %8191s", cmd, arg1, arg2, arg3);
|
||||
|
||||
if (strcmp(cmd, "init") == 0) {
|
||||
do_init();
|
||||
} else if (strcmp(cmd, "connect") == 0) {
|
||||
if (strlen(arg1) == 0) {
|
||||
json_err("usage: connect <UID>");
|
||||
} else {
|
||||
do_connect(arg1);
|
||||
}
|
||||
} else if (strcmp(cmd, "login") == 0) {
|
||||
if (strlen(arg1) == 0 || strlen(arg2) == 0) {
|
||||
json_err("usage: login <user> <pass>");
|
||||
} else {
|
||||
do_login(arg1, arg2);
|
||||
}
|
||||
} else if (strcmp(cmd, "ioctrl") == 0) {
|
||||
if (strlen(arg1) == 0) {
|
||||
json_err("usage: ioctrl <cmd_id> [hex_data]");
|
||||
} else {
|
||||
int cmd_id = atoi(arg1);
|
||||
do_ioctrl(cmd_id, strlen(arg2) > 0 ? arg2 : "");
|
||||
}
|
||||
} else if (strcmp(cmd, "search") == 0) {
|
||||
do_lan_search();
|
||||
} else if (strcmp(cmd, "disconnect") == 0) {
|
||||
do_disconnect();
|
||||
} else if (strcmp(cmd, "quit") == 0 || strcmp(cmd, "exit") == 0) {
|
||||
do_deinit();
|
||||
break;
|
||||
} else if (strcmp(cmd, "help") == 0) {
|
||||
printf("{\"commands\":[\"init\",\"connect <UID>\",\"login <user> <pass>\",\"ioctrl <cmd_id> [hex]\",\"search\",\"disconnect\",\"quit\"]}\n");
|
||||
fflush(stdout);
|
||||
} else {
|
||||
json_err("unknown command");
|
||||
}
|
||||
}
|
||||
|
||||
do_deinit();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user