summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--iv/orodja/ldmitm/ldmitm.c203
1 files changed, 203 insertions, 0 deletions
diff --git a/iv/orodja/ldmitm/ldmitm.c b/iv/orodja/ldmitm/ldmitm.c
new file mode 100644
index 0000000..66cba41
--- /dev/null
+++ b/iv/orodja/ldmitm/ldmitm.c
@@ -0,0 +1,203 @@
+/*
+DISKUSIJA
+Bolje bi bilo uporabiti frida gadget: https://frida.re/docs/gadget/
+Kako deluje: https://tbrindus.ca/correct-ld-preload-hooking-libc/
+Prevedi z: gcc -shared -fPIC -ldl ldmitm.c -o ldmitm.so
+Poženi z: LD_PRELOAD=$PWD/ldmitm.so php -S 0:1234
+A je treba beležit execve in fopen? Po mojem ne. Odtekanje flagov itak vidimo v TCP sessionu.
+TODO: add mutex locks!!!
+*/
+#include <stdio.h>
+#include <dlfcn.h>
+#include <sys/socket.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sqlite3.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#if SQLITE_VERSION_NUMBER < 3037000
+#error "we require sqlite newer than 3037000, yours is " #SQLITE_VERSION_NUMBER " --- because of STRICT!"
+#endif
+#define LOG(x, ...) if (getenv("LDMITM_LOG")) printf("[ldmitm %s] " x "\n", __func__ __VA_OPT__(,) __VA_ARGS__)
+struct stream {
+ bool active;
+ bool silenced;
+ int id; // id in sqlite3 database
+};
+typedef int (*accept_t)(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);
+typedef int (*close_t)(int fd);
+static accept_t real_accept;
+static close_t real_close;
+static __thread sqlite3 * db = NULL;
+struct stream * streams = NULL;
+int streams_sizeof = 0;
+static void setup_db () { // should be able to ignore being called in case db is already set up on this thread
+ if (db)
+ return;
+ int ret = sqlite3_open_v2(getenv("LDMITM_DB") ? getenv("LDMITM_DB") : ":memory:", &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_URI | SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_EXRESCODE, NULL);
+ if (ret != SQLITE_OK) {
+ LOG("failed to open db: %s", sqlite3_errstr(ret));
+ goto fail;
+ }
+ sqlite3_stmt * stmt = NULL;
+ ret = sqlite3_prepare_v3(db, "PRAGMA foreign_keys = ON;", -1, 0, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ LOG("failed to prepare pragma foreign_keys: %s", sqlite3_errstr(ret));
+ if (stmt)
+ sqlite3_finalize(stmt);
+ stmt = NULL;
+ goto fail;
+ }
+ ret = sqlite3_step(stmt);
+ sqlite3_finalize(stmt);
+ stmt = NULL;
+ if (ret != SQLITE_DONE) {
+ LOG("failed to step pragma foreign_keys: %s", sqlite3_errstr(ret));
+ goto fail;
+ }
+#define CREATE_TABLE(name, columns) \
+ ret = sqlite3_prepare_v3(db, "create table if not exists " name " (" columns ") STRICT;", -1, 0, &stmt, NULL); \
+ if (ret != SQLITE_OK) { \
+ LOG("failed to prepare create " name ": %s, statement: %s", sqlite3_errstr(ret), "create table if not exists " name " (" columns ") STRICT;"); \
+ if (stmt) \
+ sqlite3_finalize(stmt); \
+ stmt = NULL; \
+ goto fail; \
+ } \
+ ret = sqlite3_step(stmt); \
+ sqlite3_finalize(stmt); \
+ stmt = NULL; \
+ if (ret != SQLITE_DONE) { \
+ LOG("failed to step create " name ": %s", sqlite3_errstr(ret)); \
+ goto fail; \
+ }
+ CREATE_TABLE("connections", "id INTEGER PRIMARY KEY, peer TEXT NOT NULL, accepted TEXT DEFAULT (strftime('%FT%R:%f', 'now')) NOT NULL, closed TEXT, silenced TEXT"); // accepted, closed and silenced are iso datestrings
+ CREATE_TABLE("messages", "connection INTEGER NOT NULL, direction INTEGER NOT NULL CHECK (direction IN (0, 1)), time TEXT DEFAULT (strftime('%FT%R:%f', 'now')) NOT NULL, FOREIGN KEY(connection) REFERENCES connections(id)");
+ return;
+fail:
+ if (db)
+ sqlite3_close_v2(db);
+ db = NULL;
+ return;
+}
+static void end_stream (int fd) { // cleanup function, should be able to handle being called on already ended stream
+ if (fd >= streams_sizeof || !streams[fd].active)
+ return;
+ setup_db();
+ if (db) {
+ sqlite3_stmt * stmt = NULL;
+ int ret = sqlite3_prepare_v3(db, "update connections set closed=strftime('%FT%R:%f', 'now') WHERE id=:i;", -1, 0, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ LOG("failed to prepare update connections set closed: %s", sqlite3_errstr(ret));
+ sqlite3_finalize(stmt);
+ stmt = NULL;
+ goto fail;
+ }
+ ret = sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, ":i"), streams[fd].id);
+ if (ret != SQLITE_OK) {
+ LOG("failed to bind update connections set closed: %s", sqlite3_errstr(ret));
+ sqlite3_finalize(stmt);
+ stmt = NULL;
+ goto fail;
+ }
+ ret = sqlite3_step(stmt);
+ sqlite3_finalize(stmt);
+ stmt = NULL;
+ if (ret != SQLITE_DONE) {
+ LOG("failed to step update connections set closed: %s", sqlite3_errstr(ret));
+ goto fail;
+ }
+ }
+fail:
+ memset(&(streams[fd]), 0, sizeof streams[fd]);
+}
+int close (int fd) {
+ if (!real_close)
+ real_close = dlsym(RTLD_NEXT, "close");
+ LOG("called close()");
+ int ret = real_close(fd);
+ int old_errno = errno;
+ end_stream(fd);
+ errno = old_errno;
+ return ret;
+}
+int accept (int socket, struct sockaddr *restrict address, socklen_t *restrict address_len) {
+ if (!real_accept)
+ real_accept = dlsym(RTLD_NEXT, "accept");
+ LOG("called accept()");
+ int ret = real_accept(socket, address, address_len);
+ int saved_errno = errno;
+ if (ret >= streams_sizeof) {
+ int streams_sizeof_new;
+ if (streams_sizeof == 0)
+ streams_sizeof_new = 128;
+ else
+ streams_sizeof_new = streams_sizeof * 2;
+ struct stream * streams_new = realloc(streams, streams_sizeof_new*sizeof *streams);
+ if (!streams_new) {
+ LOG("ENOMEM realloc streams!");
+ goto fail;
+ }
+ memset(streams_new+streams_sizeof, 0, (streams_sizeof_new-streams_sizeof)*sizeof *streams);
+ streams = streams_new;
+ streams_sizeof = streams_sizeof_new;
+ }
+ end_stream(ret);
+ streams[ret].active = true;
+ setup_db();
+ if (db) {
+ sqlite3_stmt * stmt = NULL;
+ int sqlret = sqlite3_prepare_v3(db, "insert into connections (peer) values (:p);", -1, 0, &stmt, NULL);
+ if (sqlret != SQLITE_OK) {
+ LOG("failed to prepare insert connections: %s", sqlite3_errstr(sqlret));
+ goto sqlfail;
+ }
+ char peeraddress[INET_ADDRSTRLEN+128];
+ switch (address->sa_family) {
+ case AF_INET:
+ if (!inet_ntop(AF_INET, &(((struct sockaddr_in *) address)->sin_addr), peeraddress, *address_len)) {
+ int myerrno = errno;
+ strcpy(peeraddress, "!");
+ strcat(peeraddress, strerror(myerrno));
+ }
+ sprintf(peeraddress+strlen(peeraddress), "/%d", ntohs(((struct sockaddr_in *) address)->sin_port));
+ break;
+ case AF_INET6:
+ if (!inet_ntop(AF_INET6, &(((struct sockaddr_in6 *) address)->sin6_addr), peeraddress, *address_len)) {
+ int myerrno = errno;
+ strcpy(peeraddress, "!");
+ strcat(peeraddress, strerror(myerrno));
+ }
+ sprintf(peeraddress+strlen(peeraddress), "/%d", ntohs(((struct sockaddr_in6 *) address)->sin6_port));
+ break;
+ default:
+ strcpy(peeraddress, "unknown family");
+ break;
+ }
+ sqlret = sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":p"), peeraddress, -1, SQLITE_STATIC);
+ if (sqlret != SQLITE_OK) {
+ LOG("failed to bind insert connection: %s", sqlite3_errstr(sqlret));
+ goto sqlfail;
+ }
+ sqlret = sqlite3_step(stmt);
+ sqlite3_finalize(stmt);
+ stmt = NULL;
+ if (sqlret != SQLITE_DONE) {
+ LOG("failed to step insert connection: %s", sqlite3_errstr(ret));
+ goto sqlfail;
+ }
+sqlfail:
+ sqlite3_finalize(stmt);
+ stmt = NULL;
+ goto fail;
+ }
+fail:
+ errno = saved_errno;
+ return ret;
+}
+__attribute__((constructor)) static void setup (void) {
+ LOG("called setup()");
+}