1
0

proj: Add PoC

This commit is contained in:
2025-01-09 09:42:02 +01:00
parent 235dc631aa
commit 6c70a3c401
6 changed files with 300 additions and 44 deletions

View File

@@ -1,5 +1,7 @@
.PHONY: all clean
all:
$(MAKE) -C proj/test1/
$(MAKE) -C proj/test2/ -C /usr/src/linux-`uname -r` SUBDIRS=$PWD modules
clean:
$(MAKE) -C proj/test1/
$(MAKE) -C proj/test2/

7
doc/intercept.md Normal file
View File

@@ -0,0 +1,7 @@
# Interception Protocol
* `ok` - Do not modify the function call
* `modify ARGS...` - Modify the arguments of the function call
* `return VALUE` - Return the given value without calling the real function
* `fail ERROR` - Return with the given error code without calling the real function

34
proj/server/src/server.py Executable file
View File

@@ -0,0 +1,34 @@
#!/usr/bin/env python3
from socketserver import UnixStreamServer, StreamRequestHandler, ThreadingMixIn
import os
class Handler(StreamRequestHandler):
def handle(self):
first = self.rfile.readline()
pid = int(first.split(b':')[1])
print(f'Process with PID {pid} connected')
while True:
msg = self.rfile.readline()
if not msg:
return
timestamp, data = msg.split(b' ', 1)
if not data.startswith(b'return '):
print(data)
#self.wfile.write(b'ok\n')
else:
print(data)
class ThreadedUnixStreamServer(ThreadingMixIn, UnixStreamServer):
pass
def main() -> None:
os.unlink('/tmp/test')
with ThreadedUnixStreamServer('/tmp/test', Handler) as server:
server.serve_forever()
if __name__ == '__main__':
main()

View File

@@ -1,20 +1,48 @@
CC=gcc
CFLAGS=-std=c99 -pedantic -Wall -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE -D_POSIX_C_SOURCE=200809L -g
LDFLAGS=-lc
.PHONY: all clean
all: default
default: main main_wrapped test_preload.so
default: bin main test_preload.so main_wrapped #test_kernel.ko
test_preload.so: src/test_preload.c
$(CC) -shared -fPIC -o $@ $^ $(CFLAGS) $(LDFLAGS)
bin:
mkdir -p bin/
bin/test_preload.o: src/test_preload.c
$(CC) -fPIC -c -o $@ $^ $(CFLAGS)
test_preload.so: bin/test_preload.o
$(CC) -shared -o $@ $^ $(CFLAGS) -lc -ldl
test_kernel.ko: src/test_kernel.c
$(CC) -D__KERNEL__ -DMODULE -I/usr/src/linux/include -o $@ $^
main: src/main.c
$(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS)
$(CC) -o $@ $^ $(CFLAGS) -lc
main_wrapped: src/main.c src/test_wrap.c
$(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) -Wl,--wrap=malloc -Wl,--wrap=free -Wl,--wrap=calloc -Wl,--wrap=realloc -Wl,--wrap=getopt
$(CC) -o $@ $^ $(CFLAGS) -lc -Wl,--wrap=malloc,--wrap=free,--wrap=calloc,--wrap=realloc,--wrap=getopt
clean:
rm -rf main test_preload.so main_wrapped
rm -rf main main_wrapped bin/* *.so *.ko *.o
#ifneq ($(KERNELRELEASE),)
# # call from kernel build system
# lifo-objs := main.o
# obj-m := lifo.o
#else
# KERNELDIR ?= /lib/modules/$(shell uname -r)/build
# PWD := $(shell pwd)
#modules:
# echo $(MAKE) -C $(KERNELDIR) M=$(PWD) LDDINC=$(PWD)/../include modules
# $(MAKE) -C $(KERNELDIR) M=$(PWD) LDDINC=$(PWD)/../include modules
#endif
#
#depend .depend dep:
# $(CC) $(CFLAGS) -M *.c > .depend
#
#ifeq (.depend,$(wildcard .depend))
# include .depend
#endif

View File

@@ -0,0 +1,65 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/syscalls.h>
#include <linux/unistd.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/namei.h>
MODULE_LICENSE("GPL");
unsigned long *sys_call_table;
asmlinkage long (*original_sys_open)(const char __user *filename, int flags, int mode);
asmlinkage int our_fake_open_function(const char __user *filename, int flags, int mode) {
struct nameidata nd, nd_t;
struct inode *inode, *inode_t;
int error = user_path_walk(filename, &nd);
if (!error) {
inode = nd.dentry->d_inode;
// Have to do this before calling user_path_walk() from kernel space:
mm_segment_t fs = get_fs();
set_fs(get_ds());
// Protect /tmp/test. Change this to whatever file you want to protect
error = user_path_walk("/tmp/test", &nd_t);
set_fs(fs);
if (!error) {
inode_t = nd_t.dentry->d_inode;
if (inode == inode_t)
return -EACCES;
}
}
return original_sys_open(filename, flags, mode);
}
static int __init my_init(void) {
unsigned long *sys_table = (unsigned long *)&system_utsname;
int found = 0;
for (int i = 0; i < 1024; i++, sys_table++) {
if (sys_table[__NR_read] == (unsigned long)sys_read) {
sys_call_table = sys_table;
found = 1;
break;
}
}
if (found) {
original_sys_open = (void *)xchg(&sys_call_table[__NR_open], our_fake_open_function);
}
return 0;
}
static void my_exit(void) {
xchg(&sys_call_table[__NR_open], original_sys_open);
}
module_init(my_init);
module_exit(my_exit);

View File

@@ -1,93 +1,208 @@
#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <time.h>
#define PREFIX "---====[ "
static int mode = 0;
static int intercept = 0;
static int *(*log)(int fd, const char *fmt, ...);
static void log_str(FILE *out, const char *str) {
fprintf(out, "%p:\"", str);
static void log_prefix(void) {
struct timespec spec;
clock_gettime(CLOCK_REALTIME, &spec);
log(intercept, "%li.%09li ", spec.tv_sec, spec.tv_nsec);
}
static void log_str(const char *str) {
log(intercept, "%p:\"", str);
for (char ch; (ch = *str) != 0; str++) {
if (ch == '\\' || ch == '"') {
fputc('\\', out);
fputc(ch, out);
log(intercept, "\\%c", ch);
} else if (ch == '\t') {
fputs("\\t", out);
log(intercept, "\\t");
} else if (ch == '\n') {
fputs("\\n", out);
log(intercept, "\\n");
} else if (ch == '\r') {
fputs("\\r", out);
log(intercept, "\\r");
} else if ((ch >= 0 && ch < 0x20) || ch == 0x7F) {
fprintf(out, "\\x%02x", ch);
log(intercept, "\\x%02x", ch);
} else {
fputc(ch, out);
log(intercept, "%c", ch);
}
}
fputc('"', out);
log(intercept, "\"");
}
static void log_array_str(FILE *out, char *const array[], int n) {
fprintf(out, "%p:[", (void *)array);
static void log_array_str(char *const array[], int n) {
log(intercept, "%p:[", (void *)array);
for (int i = 0; i < n; i++) {
if (i > 0) fputs(", ", stderr);
log_str(stderr, array[i]);
if (i > 0) log(intercept, ", ");
log_str(array[i]);
}
fputc(']', out);
log(intercept, "]");
}
static void fin(void) {
if (intercept && mode > 2)
close(intercept);
if (mode > 0)
fprintf(stderr, "intercept: stopped\n");
mode = 0, intercept = 0;
}
static void init(void) {
if (mode) return;
if ((log = dlsym(RTLD_NEXT, "dprintf")) == NULL) {
fprintf(stderr, "intercept: unable to find dlsym dprintf: %s\n", strerror(errno));
errno = 0;
mode = -1;
return;
}
atexit(fin);
const char *val = getenv("INTERCEPT");
if (val && strcmp(val, "stdout") == 0) {
mode = 1;
fprintf(stderr, "intercept: intercepting function/system calls and logging to stdout\n");
intercept = STDOUT_FILENO;
} else if (val && strcmp(val, "stderr") == 0) {
mode = 2;
fprintf(stderr, "intercept: intercepting function/system calls and logging to stderr\n");
intercept = STDERR_FILENO;
} else if (val && strncmp(val, "file:", 5) == 0) {
mode = 3;
if ((intercept = open(val + 5, O_CREAT | O_TRUNC | O_WRONLY, 0644)) == -1) {
fprintf(stderr, "intercept: unable to open log file '%s': %s\nintercept: not logging or manipulating function/system calls\n", val + 5, strerror(errno));
errno = 0;
mode = -1;
return;
}
fprintf(stderr, "intercept: intercepting function/system calls and logging to file\n");
} else if (val && strncmp(val, "unix:", 5) == 0) {
mode = 4;
if ((intercept = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
fprintf(stderr, "intercept: unable to open unix socket '%s': %s\nintercept: not logging or manipulating function/system calls\n", val + 5, strerror(errno));
errno = 0;
mode = -1;
return;
}
struct sockaddr_un addr = {.sun_family = AF_UNIX};
strncpy(addr.sun_path, val + 5, sizeof(addr.sun_path));
if (connect(intercept, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
fprintf(stderr, "intercept: unable to connect to unix socket '%s': %s\nintercept: not logging or manipulating function/system calls\n", val + 5, strerror(errno));
close(intercept);
errno = 0;
mode = -1;
return;
}
fprintf(stderr, "intercept: intercepting function/system calls and logging to unix socket\n");
log_prefix();
log(intercept, "PID:%li\n", getpid());
} else if (val && strncmp(val, "tcp://", 6) == 0) {
mode = 5;
// TODO
} else {
mode = -1;
fprintf(stderr, "intercept: not logging or manipulating function/system calls\n");
}
}
void *(*__real_malloc)(size_t);
void *__real_malloc(size_t);
void *malloc(size_t size) {
fprintf(stderr, PREFIX "malloc(%li)\n", size);
void *(*_malloc)(size_t);
if ((_malloc = dlsym(RTLD_NEXT, "malloc")) == NULL) {
init();
if (intercept) {
log_prefix();
log(intercept, "malloc(%li)\n", size);
}
if ((__real_malloc = dlsym(RTLD_NEXT, "malloc")) == NULL) {
errno = ENOSYS;
return NULL;
}
void *ret = _malloc(size);
fprintf(stderr, PREFIX "-> %p\n", ret);
void *ret = __real_malloc(size);
if (intercept) {
log_prefix();
log(intercept, "return %p\n", ret);
}
return ret;
}
void *calloc(size_t nmemb, size_t size) {
fprintf(stderr, PREFIX "calloc(%li, %li)\n", nmemb, size);
init();
if (intercept) {
log_prefix();
log(intercept, "calloc(%li, %li)\n", nmemb, size);
}
void *(*_calloc)(size_t, size_t);
if ((_calloc = dlsym(RTLD_NEXT, "calloc")) == NULL) {
errno = ENOSYS;
return NULL;
}
void *ret = _calloc(nmemb, size);
fprintf(stderr, PREFIX "-> %p\n", ret);
if (intercept) {
log_prefix();
log(intercept, "return %p\n", ret);
}
return ret;
}
void *realloc(void *ptr, size_t size) {
fprintf(stderr, PREFIX "realloc(%p, %li)\n", ptr, size);
init();
if (intercept) {
log_prefix();
log(intercept, "realloc(%p, %li)\n", ptr, size);
}
void *(*_realloc)(void *, size_t);
if ((_realloc = dlsym(RTLD_NEXT, "realloc")) == NULL) {
errno = ENOSYS;
return NULL;
}
void *ret = _realloc(ptr, size);
fprintf(stderr, PREFIX "-> %p\n", ret);
if (intercept) {
log_prefix();
log(intercept, "return %p\n", ret);
}
return ret;
}
void free(void *ptr) {
fprintf(stderr, PREFIX "free(%p)\n", ptr);
init();
if (intercept) {
log_prefix();
log(intercept, "free(%p)\n", ptr);
}
void (*_free)(void *);
if ((_free = dlsym(RTLD_NEXT, "free")) == NULL) {
errno = ENOSYS;
return;
}
_free(ptr);
fprintf(stderr, PREFIX "-> void\n");
if (intercept) {
log_prefix();
log(intercept, "return void\n");
}
}
int getopt(const int argc, char *const argv[], const char *shortopts) {
fprintf(stderr, PREFIX "getopt(%i, ", argc);
log_array_str(stderr, argv, argc);
fputs(", ", stderr);
log_str(stderr, shortopts);
fputs(")\n", stderr);
init();
if (intercept) {
log_prefix();
log(intercept, "getopt(%i, ", argc);
log_array_str(argv, argc);
log(intercept, ", ");
log_str(shortopts);
log(intercept, ")\n");
}
int (*_getopt)(int, char *const[], const char *);
if ((_getopt = dlsym(RTLD_NEXT, "getopt")) == NULL) {
@@ -95,11 +210,16 @@ int getopt(const int argc, char *const argv[], const char *shortopts) {
return -1;
}
int ret = _getopt(argc, argv, shortopts);
fprintf(stderr, PREFIX "-> %i", ret);
if (ret >= 0x20 && ret < 0x7F) {
fprintf(stderr, " ('%c')\n", ret);
} else {
fprintf(stderr, "\n");
if (intercept) {
log_prefix();
log(intercept, "return %i", ret);
if (ret >= 0x20 && ret < 0x7F) {
log(intercept, " ('%c')\n", ret);
} else {
log(intercept, "\n");
}
}
return ret;
}