proj: Add PoC
This commit is contained in:
2
Makefile
2
Makefile
@@ -1,5 +1,7 @@
|
|||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
all:
|
all:
|
||||||
$(MAKE) -C proj/test1/
|
$(MAKE) -C proj/test1/
|
||||||
|
$(MAKE) -C proj/test2/ -C /usr/src/linux-`uname -r` SUBDIRS=$PWD modules
|
||||||
clean:
|
clean:
|
||||||
$(MAKE) -C proj/test1/
|
$(MAKE) -C proj/test1/
|
||||||
|
$(MAKE) -C proj/test2/
|
||||||
|
|||||||
7
doc/intercept.md
Normal file
7
doc/intercept.md
Normal 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
34
proj/server/src/server.py
Executable 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()
|
||||||
@@ -1,20 +1,48 @@
|
|||||||
|
|
||||||
CC=gcc
|
CC=gcc
|
||||||
CFLAGS=-std=c99 -pedantic -Wall -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE -D_POSIX_C_SOURCE=200809L -g
|
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
|
.PHONY: all clean
|
||||||
all: default
|
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
|
bin:
|
||||||
$(CC) -shared -fPIC -o $@ $^ $(CFLAGS) $(LDFLAGS)
|
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
|
main: src/main.c
|
||||||
$(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS)
|
$(CC) -o $@ $^ $(CFLAGS) -lc
|
||||||
|
|
||||||
main_wrapped: src/main.c src/test_wrap.c
|
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:
|
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
|
||||||
|
|||||||
65
proj/test1/src/test_kernel.c
Normal file
65
proj/test1/src/test_kernel.c
Normal 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);
|
||||||
@@ -1,93 +1,208 @@
|
|||||||
|
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <errno.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) {
|
static void log_prefix(void) {
|
||||||
fprintf(out, "%p:\"", str);
|
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++) {
|
for (char ch; (ch = *str) != 0; str++) {
|
||||||
if (ch == '\\' || ch == '"') {
|
if (ch == '\\' || ch == '"') {
|
||||||
fputc('\\', out);
|
log(intercept, "\\%c", ch);
|
||||||
fputc(ch, out);
|
|
||||||
} else if (ch == '\t') {
|
} else if (ch == '\t') {
|
||||||
fputs("\\t", out);
|
log(intercept, "\\t");
|
||||||
} else if (ch == '\n') {
|
} else if (ch == '\n') {
|
||||||
fputs("\\n", out);
|
log(intercept, "\\n");
|
||||||
} else if (ch == '\r') {
|
} else if (ch == '\r') {
|
||||||
fputs("\\r", out);
|
log(intercept, "\\r");
|
||||||
} else if ((ch >= 0 && ch < 0x20) || ch == 0x7F) {
|
} else if ((ch >= 0 && ch < 0x20) || ch == 0x7F) {
|
||||||
fprintf(out, "\\x%02x", ch);
|
log(intercept, "\\x%02x", ch);
|
||||||
} else {
|
} else {
|
||||||
fputc(ch, out);
|
log(intercept, "%c", ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fputc('"', out);
|
log(intercept, "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void log_array_str(FILE *out, char *const array[], int n) {
|
static void log_array_str(char *const array[], int n) {
|
||||||
fprintf(out, "%p:[", (void *)array);
|
log(intercept, "%p:[", (void *)array);
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
if (i > 0) fputs(", ", stderr);
|
if (i > 0) log(intercept, ", ");
|
||||||
log_str(stderr, array[i]);
|
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) {
|
void *malloc(size_t size) {
|
||||||
fprintf(stderr, PREFIX "malloc(%li)\n", size);
|
init();
|
||||||
void *(*_malloc)(size_t);
|
if (intercept) {
|
||||||
if ((_malloc = dlsym(RTLD_NEXT, "malloc")) == NULL) {
|
log_prefix();
|
||||||
|
log(intercept, "malloc(%li)\n", size);
|
||||||
|
}
|
||||||
|
if ((__real_malloc = dlsym(RTLD_NEXT, "malloc")) == NULL) {
|
||||||
errno = ENOSYS;
|
errno = ENOSYS;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
void *ret = _malloc(size);
|
void *ret = __real_malloc(size);
|
||||||
fprintf(stderr, PREFIX "-> %p\n", ret);
|
if (intercept) {
|
||||||
|
log_prefix();
|
||||||
|
log(intercept, "return %p\n", ret);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *calloc(size_t nmemb, size_t size) {
|
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);
|
void *(*_calloc)(size_t, size_t);
|
||||||
if ((_calloc = dlsym(RTLD_NEXT, "calloc")) == NULL) {
|
if ((_calloc = dlsym(RTLD_NEXT, "calloc")) == NULL) {
|
||||||
errno = ENOSYS;
|
errno = ENOSYS;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
void *ret = _calloc(nmemb, size);
|
void *ret = _calloc(nmemb, size);
|
||||||
fprintf(stderr, PREFIX "-> %p\n", ret);
|
if (intercept) {
|
||||||
|
log_prefix();
|
||||||
|
log(intercept, "return %p\n", ret);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *realloc(void *ptr, size_t size) {
|
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);
|
void *(*_realloc)(void *, size_t);
|
||||||
if ((_realloc = dlsym(RTLD_NEXT, "realloc")) == NULL) {
|
if ((_realloc = dlsym(RTLD_NEXT, "realloc")) == NULL) {
|
||||||
errno = ENOSYS;
|
errno = ENOSYS;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
void *ret = _realloc(ptr, size);
|
void *ret = _realloc(ptr, size);
|
||||||
fprintf(stderr, PREFIX "-> %p\n", ret);
|
if (intercept) {
|
||||||
|
log_prefix();
|
||||||
|
log(intercept, "return %p\n", ret);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free(void *ptr) {
|
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 *);
|
void (*_free)(void *);
|
||||||
if ((_free = dlsym(RTLD_NEXT, "free")) == NULL) {
|
if ((_free = dlsym(RTLD_NEXT, "free")) == NULL) {
|
||||||
errno = ENOSYS;
|
errno = ENOSYS;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_free(ptr);
|
_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) {
|
int getopt(const int argc, char *const argv[], const char *shortopts) {
|
||||||
fprintf(stderr, PREFIX "getopt(%i, ", argc);
|
init();
|
||||||
log_array_str(stderr, argv, argc);
|
|
||||||
fputs(", ", stderr);
|
if (intercept) {
|
||||||
log_str(stderr, shortopts);
|
log_prefix();
|
||||||
fputs(")\n", stderr);
|
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 *);
|
int (*_getopt)(int, char *const[], const char *);
|
||||||
if ((_getopt = dlsym(RTLD_NEXT, "getopt")) == NULL) {
|
if ((_getopt = dlsym(RTLD_NEXT, "getopt")) == NULL) {
|
||||||
@@ -95,11 +210,16 @@ int getopt(const int argc, char *const argv[], const char *shortopts) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int ret = _getopt(argc, argv, shortopts);
|
int ret = _getopt(argc, argv, shortopts);
|
||||||
fprintf(stderr, PREFIX "-> %i", ret);
|
|
||||||
|
if (intercept) {
|
||||||
|
log_prefix();
|
||||||
|
log(intercept, "return %i", ret);
|
||||||
if (ret >= 0x20 && ret < 0x7F) {
|
if (ret >= 0x20 && ret < 0x7F) {
|
||||||
fprintf(stderr, " ('%c')\n", ret);
|
log(intercept, " ('%c')\n", ret);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "\n");
|
log(intercept, "\n");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user