From 3213f9e9ada022bae6cb8ebb2865b2e6adeea925 Mon Sep 17 00:00:00 2001 From: Kevin Haubris Date: Tue, 26 Apr 2022 12:55:27 -0500 Subject: [PATCH] Initial commit --- .gitignore | 2 + Makefile | 133 +++++++++ README.md | 55 ++++ SA/src/cat.c | 51 ++++ SA/src/chmod.c | 92 +++++++ SA/src/env.c | 31 +++ SA/src/find.c | 232 ++++++++++++++++ SA/src/grep.c | 240 +++++++++++++++++ SA/src/id.c | 64 +++++ SA/src/ifconfig.c | 99 +++++++ SA/src/pwd.c | 32 +++ SA/src/tasklist.c | 238 +++++++++++++++++ SA/src/uname.c | 26 ++ SA/src/walk.c | 145 ++++++++++ SA/src/whoami.c | 39 +++ Scripts/beacon_generate.py | 96 +++++++ includes/ELFLoader.h | 65 +++++ includes/beacon_api.h | 58 ++++ includes/beacon_compatibility.h | 66 +++++ includes/debug.h | 9 + includes/minimal_elf.h | 205 ++++++++++++++ src/ELFLoader.c | 431 ++++++++++++++++++++++++++++++ src/beacon_compatibility.c | 314 ++++++++++++++++++++++ testobjects/getuid.c | 39 +++ testobjects/test.c | 16 ++ testobjects/test2.c | 19 ++ testobjects/test2_duplicatetext.c | 37 +++ 27 files changed, 2834 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 SA/src/cat.c create mode 100644 SA/src/chmod.c create mode 100644 SA/src/env.c create mode 100644 SA/src/find.c create mode 100644 SA/src/grep.c create mode 100644 SA/src/id.c create mode 100644 SA/src/ifconfig.c create mode 100644 SA/src/pwd.c create mode 100644 SA/src/tasklist.c create mode 100644 SA/src/uname.c create mode 100644 SA/src/walk.c create mode 100644 SA/src/whoami.c create mode 100644 Scripts/beacon_generate.py create mode 100644 includes/ELFLoader.h create mode 100644 includes/beacon_api.h create mode 100644 includes/beacon_compatibility.h create mode 100644 includes/debug.h create mode 100644 includes/minimal_elf.h create mode 100644 src/ELFLoader.c create mode 100644 src/beacon_compatibility.c create mode 100644 testobjects/getuid.c create mode 100644 testobjects/test.c create mode 100644 testobjects/test2.c create mode 100644 testobjects/test2_duplicatetext.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..17fbe89 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +*.out diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b8dbd5d --- /dev/null +++ b/Makefile @@ -0,0 +1,133 @@ + +all: x86_64 x86 mac_x86_64 test2_dup test2 test whoami whoami32 tasklist tasklist32 cat cat32 uname uname32 id id32 uname uname32 walk walk32 grep grep32 find find32 chmod chmod32 env env32 pwd pwd32 ifconfig ifconfig32 + +SOURCES:=./src/beacon_compatibility.c ./src/ELFLoader.c + +x86_64: + gcc -Wall -I ./includes/ -DTESTING_MAIN $(SOURCES) -ldl -o ELFLoader.out + +x86_64D: + gcc -g -DDEBUG -Wall -I ./includes/ -DTESTING_MAIN $(SOURCES) -ldl -o ELFLoaderD.out + +mac_x86_64: + x86_64-apple-darwin20-clang -Wall -I ./includes/ -DTESTING_MAIN $(SOURCES) -ldl -o ELFLoader_mac.out + +mac_x86_64D: + x86_64-apple-darwin20-clang -g -DDEBUG -I ./includes/ -DTESTING_MAIN $(SOURCES) -ldl -o ELFLoaderD_mac.out + +mac_aarch64: + aarch64-apple-darwin20-clang -Wall -I ./includes/ -DTESTING_MAIN $(SOURCES) -ldl -o ELFLoader_mac_aarch64.out + +mac_aarch64D: + aarch64-apple-darwin20-clang -g -DDEBUG -Wall -I ./includes/ -DTESTING_MAIN $(SOURCES) -ldl -o ELFLoaderD_mac_aarch64.out + +win64: + x86_64-w64-mingw32-gcc -I ./includes/ -DTESTING_MAIN $(SOURCES) -o ELFLoader_win64.exe + +win64D: + x86_64-w64-mingw32-gcc -DDEBUG -I ./includes/ -DTESTING_MAIN $(SOURCES) -o ELFLoaderD_win64.exe + +win32: + i686-w64-mingw32-gcc -I ./includes/ -DTESTING_MAIN $(SOURCES) -o ELFLoader_win32.exe + +win32D: + i686-w64-mingw32-gcc -DDEBUG -I ./includes/ -DTESTING_MAIN $(SOURCES) -o ELFLoaderD_win32.exe + +test2_dup: + gcc -c -fPIC -I ./includes/ testobjects/test2_duplicatetext.c -o testobjects/test2_duplicatetext.o + +test2: + gcc -c -fPIC -I ./includes/ testobjects/test2.c -o testobjects/test2.o + +test: + gcc -c -fPIC -I ./includes/ testobjects/test.c -o testobjects/test.o + +x86: + gcc -m32 -I ./includes/ -DTESTING_MAIN $(SOURCES) -ldl -o ELFLoader32.out + +x86D: + gcc -m32 -DDEBUG -I ./includes/ -DTESTING_MAIN $(SOURCES) -ldl -o ELFLoader32.out + +# Example of compiling object files for 32 bit x86 architecture. +test32: + gcc -m32 -c -fno-stack-protector -fno-pie ./testobjects/test.c -o ./testobjects/test32.o + +whoami: + gcc -c -fPIC -I ./includes/ SA/src/whoami.c -o SA/src/whoami.o + +whoami32: + gcc -m32 -c -fno-stack-protector -fno-pie -I ./includes/ SA/src/whoami.c -o SA/src/whoami32.o + +tasklist: + gcc -c -fPIC -I ./includes/ SA/src/tasklist.c -o SA/src/tasklist.o + +tasklist32: + gcc -m32 -c -fno-stack-protector -fno-pie -I ./includes/ SA/src/tasklist.c -o SA/src/tasklist32.o + +cat: + gcc -c -fPIC -I ./includes/ SA/src/cat.c -o SA/src/cat.o + +cat32: + gcc -m32 -c -fno-stack-protector -fno-pie -I ./includes/ SA/src/cat.c -o SA/src/cat32.o + +uname: + gcc -c -fPIC -I ./includes/ SA/src/uname.c -o SA/src/uname.o + +uname32: + gcc -m32 -c -fno-stack-protector -fno-pie -I ./includes/ SA/src/uname.c -o SA/src/uname32.o + +id: + gcc -c -fPIC -I ./includes/ SA/src/id.c -o SA/src/id.o + +id32: + gcc -m32 -c -fno-stack-protector -fno-pie -I ./includes/ SA/src/id.c -o SA/src/id32.o + +walk: + gcc -c -fPIC -I ./includes/ SA/src/walk.c -o SA/src/walk.o + +walk32: + gcc -m32 -c -fno-stack-protector -fno-pie -I ./includes/ SA/src/walk.c -o SA/src/walk32.o + +env: + gcc -c -fPIC -I ./includes/ SA/src/env.c -o SA/src/env.o + +env32: + gcc -m32 -c -fno-stack-protector -fno-pie -I ./includes/ SA/src/env.c -o SA/src/env32.o + +grep: + gcc -c -fPIC -I ./includes/ SA/src/grep.c -o SA/src/grep.o + +grep32: + gcc -m32 -c -fno-stack-protector -fno-pie -I ./includes/ SA/src/grep.c -o SA/src/grep32.o + +find: + gcc -c -fPIC -I ./includes/ SA/src/find.c -o SA/src/find.o + +find32: + gcc -m32 -c -fno-stack-protector -fno-pie -I ./includes/ SA/src/find.c -o SA/src/find32.o + +chmod: + gcc -c -fPIC -I ./includes/ SA/src/chmod.c -o SA/src/chmod.o + +chmod32: + gcc -m32 -c -fno-stack-protector -fno-pie -I ./includes/ SA/src/chmod.c -o SA/src/chmod32.o + +pwd: + gcc -c -fPIC -I ./includes/ SA/src/pwd.c -o SA/src/pwd.o + +pwd32: + gcc -m32 -c -fno-stack-protector -fno-pie -I ./includes/ SA/src/pwd.c -o SA/src/pwd32.o + +ifconfig: + gcc -c -fPIC -I ./includes/ SA/src/ifconfig.c -o SA/src/ifconfig.o + +ifconfig32: + gcc -m32 -c -fno-stack-protector -fno-pie -I ./includes/ SA/src/ifconfig.c -o SA/src/ifconfig32.o + +clean: + rm -f ELFLoader*.out + rm -f ELFLoader*.exe + rm -f ./SA/src/*.o + rm -f testobjects/*.o + rm -f ELFLoader_public +.PHONY: x86_64 x86_64D test2_dup test2 test clean diff --git a/README.md b/README.md new file mode 100644 index 0000000..3de0028 --- /dev/null +++ b/README.md @@ -0,0 +1,55 @@ +# ELFLoader + +This is a ELF object in memory loader/runner. The goal is to create a single +elf loader that can be used to run follow on capabilities across all x86_64 and +x86 nix operating systems. + +## How it works +The way this loader works is that it has all the code needed to build and load +an ELF object for the OS its been compiled for, anything that gets sent to it +that isn't an elf file, isn't for the right arch, or if it links to something +that can't be resolved it ends up exiting out without attempting to run. + +## Resolving Symbols +A key difference between the COFFLoader and this is that it uses the standard +definitions from the OS's libc instead of having to redefine every function used. + +## Project Layout + +``` sh +. +├── includes +│   ├── beacon_api.h +│   ├── beacon_compatibility.h +│   ├── debug.h +│   ├── ELFLoader.h +│   └── minimal_elf.h +├── Makefile +├── README.md +├── SA +│   └── src +│   ├── cat.c +│   ├── chmod.c +│   ├── env.c +│   ├── find.c +│   ├── grep.c +│   ├── id.c +│   ├── ifconfig.c +│   ├── pwd.c +│   ├── tasklist.c +│   ├── uname.c +│   ├── walk.c +│   └── whoami.c +├── Scripts +│   └── beacon_generate.py +├── src +│   ├── beacon_compatibility.c +│   └── ELFLoader.c +└── testobjects + ├── getuid.c + ├── test2.c + ├── test2_duplicatetext.c + └── test.c + +6 directories, 26 files +``` diff --git a/SA/src/cat.c b/SA/src/cat.c new file mode 100644 index 0000000..873424d --- /dev/null +++ b/SA/src/cat.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include + +#include "beacon_api.h" + +int run_cat(char* filestr){ + FILE* fin = NULL; + char readin[2049]; + size_t readsize = 1; + + memset(readin, 0, 2049); + if (filestr == NULL){ + return 1; + } + + fin = fopen(filestr, "r"); + if (fin == NULL){ + BeaconPrintf(CALLBACK_OUTPUT, "Failed to open file: %s\n", filestr); + return 1; + } + while (readsize != 0){ + readsize = fread(readin, 1, 2048, fin); + BeaconPrintf(CALLBACK_OUTPUT, "%s", readin); + memset(readin, 0, 2049); + } + BeaconPrintf(CALLBACK_OUTPUT, "\n"); + (void)fclose(fin); + return 0; +} + + +int go(char* indata, int inlen){ + datap parser; + char* filepath = NULL; + + BeaconDataParse(&parser, indata, inlen); + filepath = BeaconDataExtract(&parser, NULL); + + (void)run_cat(filepath); + + return 0; +} +#ifdef TEST_CAT +int main(int argc, char* argv[]){ + return run_cat(argv[1]); +} +#endif + diff --git a/SA/src/chmod.c b/SA/src/chmod.c new file mode 100644 index 0000000..fd3c3d7 --- /dev/null +++ b/SA/src/chmod.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include + +#include "beacon_api.h" + +int run_chmod(char* permissionString, char* filepath){ + int arg1len = 0; + mode_t permissions = 0; + int tempvalue = 0; + char temparg[2] = {0}; + int startvalue = 0; + int counter = 0; + /* NOTE: Yes this is gross, but I don't know of a better way to convert + * inputted ascii text to octal numbers, so this is how I'm doing it. + * It's a table of permission values that we can iterate over and use + * sort of as a state table. */ + int options[][6] = {{00, 01000, 02000, 00, 04000}, + {00, 00100, 00200, 00, 00400}, + {00, 00010, 00020, 00, 00040}, + {00, 00001, 00002, 00, 00004}}; + + + if (permissionString == NULL || filepath == NULL){ + return 1; + } + arg1len = strlen(permissionString); + printf("Arg1Len: %d\n", arg1len); + /* If len is 4, start at 0 */ + if (arg1len == 3){ + startvalue = 1; + } + + if (arg1len < 3 || arg1len > 4){ + return 1; + } + for (counter = 0; counter <= arg1len; counter++){ + temparg[0] = permissionString[counter]; + tempvalue = atoi(temparg); + printf("Tempvalue:%d\n", tempvalue); + if (tempvalue & 1){ + permissions |= options[counter+startvalue][1]; + } + if (tempvalue & 2){ + permissions |= options[counter+startvalue][2]; + } + if (tempvalue & 4){ + permissions |= options[counter+startvalue][4]; + } + } + + chmod(filepath, permissions); + + return 0; +} + +int go(char* indata, int inlen){ + datap parser; + char* filepath = NULL; + char* permissions = NULL; + int checkcode = 0; + + BeaconDataParse(&parser, indata, inlen); + permissions = BeaconDataExtract(&parser, NULL); + filepath = BeaconDataExtract(&parser, NULL); + + checkcode = run_chmod(permissions, filepath); + if (checkcode == 0){ + BeaconPrintf(CALLBACK_OUTPUT, "Chmod Success\n"); + } + else{ + BeaconPrintf(CALLBACK_OUTPUT, "Chmod Success\n"); + } + + + return 0; +} + + + +#ifdef TEST_CHMOD +int main(int argc, char* argv[]){ + if (argc < 2){ + printf("%s 777 ./path/to/file.txt\n", argv[0]); + return 0; + } + + return run_chmod(argv[1], argv[2]); +} +#endif diff --git a/SA/src/env.c b/SA/src/env.c new file mode 100644 index 0000000..178c098 --- /dev/null +++ b/SA/src/env.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include + +#include "beacon_api.h" + + +int run_env(void){ + int counter = 0; + char** environ = getEnviron(); + if (environ == NULL){ + return 1; + } + while (environ[counter] != NULL){ + BeaconPrintf(CALLBACK_OUTPUT, "%s\n", environ[counter]); + counter++; + } + return 0; +} + +int go(char* indata, int inlen){ + + (void)run_env(); + return 0; +} +#ifdef TEST_ENV +int main(void){ + return run_env(); +} +#endif diff --git a/SA/src/find.c b/SA/src/find.c new file mode 100644 index 0000000..8a554b9 --- /dev/null +++ b/SA/src/find.c @@ -0,0 +1,232 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "beacon_api.h" + +int cat_action(char* filestr){ + FILE* fin = NULL; + char readin[2049]; + size_t readsize = 1; + + memset(readin, 0, 2049); + if (filestr == NULL){ + return 1; + } + + fin = fopen(filestr, "r"); + if (fin == NULL){ + BeaconPrintf(CALLBACK_OUTPUT, "Failed to open file: %s\n", filestr); + return 1; + } + while (readsize != 0){ + readsize = fread(readin, 1, 2048, fin); + BeaconPrintf(CALLBACK_OUTPUT, "%s", readin); + memset(readin, 0, 2049); + } + BeaconPrintf(CALLBACK_OUTPUT, "\n"); + (void)fclose(fin); + return 0; +} + + + +int readlink_action(char* filepath){ + char outdata[255] = {0}; + ssize_t readsize = 0; + readsize = readlink(filepath, outdata, 255); + if (readsize == -1){ + BeaconPrintf(CALLBACK_OUTPUT, "%s: Failure\n", filepath); + } + else{ + BeaconPrintf(CALLBACK_OUTPUT, "%s: %s\n", filepath, outdata); + } + + return 0; +} + + + +/* Search section of bytes to see if searchTerm is there */ +char* memsearch(char* bytes, char* searchTerm, int size){ + int compareval = 0; + int counter = 0; + char* retcode = NULL; + + for (counter=0; counter < size; counter++){ + compareval = memcmp(bytes+counter, searchTerm, strlen(searchTerm)); + if (compareval == 0){ + retcode = bytes+counter; + break; + } + } + return retcode; +} + +/* Search contents of a file, by reading everything in a loop and + * then compare it to the searchTerm with memsearch */ +int search_contents(char* filestr, char* searchTerm){ + FILE* fin = NULL; + char readin[2049]; + size_t readsize = 1; + char* results = 0; + int returncode = 0; + + memset(readin, 0, 2049); + if (filestr == NULL){ + return 0; + } + + fin = fopen(filestr, "r"); + if (fin == NULL){ + //printf("Failed to open file: %s\n", filestr); + return 0; + } + while (readsize != 0){ + readsize = fread(readin, 1, 2048, fin); + results = memsearch(readin, searchTerm, readsize); + if (results != NULL){ + returncode = 1; + break; + } + memset(readin, 0, 2049); + } + (void)fclose(fin); + return returncode; +} + + + +/* Type == 1 == Find + * Type == 2 == Grep + * findaction == 1 == cat + * findaction == 2 == readlink + * partOrWhole == 1 == part + * */ +char* GrepAndFind(int type, int depth, int maxdepth, const char *sDir, char* searchTerm, char* filename, int findaction, int partOrWhole) +{ + char* buffer = NULL; + char *p = NULL; + DIR *dir_ptr; // the directory + struct dirent *direntp; // each entry + struct stat statval; + int foundtext = 0; + char* results = NULL; + int throttleCount = 0; + + if (maxdepth != -1 && depth > maxdepth){ + return NULL; + } + + if (type != 0 && searchTerm == NULL){ + return NULL; + } + + if((dir_ptr = opendir(sDir)) == NULL){ + #ifdef DEBUG + fprintf(stderr, "ls: cannot open %s\n", sDir); + #endif + } + else + { + while((direntp=readdir(dir_ptr)) != NULL){ + p = (char *)malloc(strlen(sDir) + strlen(direntp->d_name) + 2); + if (p == NULL){ + break; + } + strcpy(p, sDir); + strcat(p, "/"); + strcat(p, direntp->d_name); + __xstat(0, p, &statval); + throttleCount++; + if (throttleCount%10 == 0){ + throttleCount = 0; + usleep(1000); + } + /* Skip the . or .. files */ + if (strcmp(".", direntp->d_name) != 0 && strcmp("..", direntp->d_name)){ + if ((statval.st_mode & S_IFMT) == S_IFDIR){ + //printf("Its a folder\n"); + GrepAndFind(type, depth+1, maxdepth, p, searchTerm, filename, findaction, partOrWhole); + } + if (type == 1){ + results = NULL; + if (partOrWhole == 1){ + results = strstr(direntp->d_name, searchTerm); + } + else{ + if (0 == strcmp(direntp->d_name, searchTerm)){ + results = (void*)-1; + } + } + if (results != NULL && findaction == 0){ + BeaconPrintf(CALLBACK_OUTPUT, "Found: %s\n", p); + } + else if (results != NULL && findaction == 2){ + readlink_action(p); + } + else if (results != NULL && findaction == 1){ + cat_action(p); + } + } + else if (type == 2){ + if (filename == NULL){ + foundtext = search_contents(p, searchTerm); + if (foundtext){ + BeaconPrintf(CALLBACK_OUTPUT, "Found: %s\n", p); + } + } + else{ + results = strstr(direntp->d_name, filename); + if (results){ + foundtext = search_contents(p, searchTerm); + if (foundtext){ + BeaconPrintf(CALLBACK_OUTPUT, "Found: %s\n", p); + } + } + } + } + else{ + BeaconPrintf(CALLBACK_OUTPUT, "%s\n", p); + } + } + free(p); + } + closedir(dir_ptr); + } + return buffer; +} + +int go(char* indata, int inlen){ + datap parser; + char* folderpath = NULL; + char* searchpath = NULL; + char* filepath = NULL; + int maxdepth = 0; + int findaction = 0; + int partOrWhole = 0; + + BeaconDataParse(&parser, indata, inlen); + folderpath = BeaconDataExtract(&parser, NULL); + searchpath = BeaconDataExtract(&parser, NULL); + filepath = BeaconDataExtract(&parser, NULL); + maxdepth = BeaconDataInt(&parser); + findaction = BeaconDataInt(&parser); + partOrWhole = BeaconDataInt(&parser); + + (void)GrepAndFind(1, 0, maxdepth, folderpath, searchpath, filepath, findaction, partOrWhole); + + return 0; +} + +#ifdef TEST_FIND +int main(int argc, char* argv[]){ + GrepAndFind(1, 0, atoi(argv[1]), argv[4], argv[5], argv[6], atoi(argv[2]), atoi(argv[3])); + return 0; +} +#endif diff --git a/SA/src/grep.c b/SA/src/grep.c new file mode 100644 index 0000000..1dee192 --- /dev/null +++ b/SA/src/grep.c @@ -0,0 +1,240 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "beacon_api.h" + +int cat_action(char* filestr){ + FILE* fin = NULL; + char readin[2049]; + size_t readsize = 1; + + memset(readin, 0, 2049); + if (filestr == NULL){ + return 1; + } + + fin = fopen(filestr, "r"); + if (fin == NULL){ + BeaconPrintf(CALLBACK_OUTPUT, "Failed to open file: %s\n", filestr); + return 1; + } + while (readsize != 0){ + readsize = fread(readin, 1, 2048, fin); + BeaconPrintf(CALLBACK_OUTPUT, "%s", readin); + memset(readin, 0, 2049); + } + BeaconPrintf(CALLBACK_OUTPUT, "\n"); + (void)fclose(fin); + return 0; +} + + + +int readlink_action(char* filepath){ + char outdata[255] = {0}; + ssize_t readsize = 0; + readsize = readlink(filepath, outdata, 255); + if (readsize == -1){ + BeaconPrintf(CALLBACK_OUTPUT, "%s: Failure\n", filepath); + } + else{ + BeaconPrintf(CALLBACK_OUTPUT, "%s: %s\n", filepath, outdata); + } + + return 0; +} + + + +/* Search section of bytes to see if searchTerm is there */ +char* memsearch(char* bytes, char* searchTerm, int size){ + int compareval = 0; + int counter = 0; + char* retcode = NULL; + + for (counter=0; counter < size; counter++){ + compareval = memcmp(bytes+counter, searchTerm, strlen(searchTerm)); + if (compareval == 0){ + retcode = bytes+counter; + break; + } + } + return retcode; +} + +/* Search contents of a file, by reading everything in a loop and + * then compare it to the searchTerm with memsearch */ +int search_contents(char* filestr, char* searchTerm){ + FILE* fin = NULL; + char readin[2049]; + size_t readsize = 1; + char* results = 0; + int returncode = 0; + + memset(readin, 0, 2049); + if (filestr == NULL){ + return 0; + } + + fin = fopen(filestr, "r"); + if (fin == NULL){ + //printf("Failed to open file: %s\n", filestr); + return 0; + } + while (readsize != 0){ + readsize = fread(readin, 1, 2048, fin); + results = memsearch(readin, searchTerm, readsize); + if (results != NULL){ + returncode = 1; + break; + } + memset(readin, 0, 2049); + } + (void)fclose(fin); + return returncode; +} + + + +/* Type == 1 == Find + * Type == 2 == Grep + * findaction == 1 == cat + * findaction == 2 == readlink + * partOrWhole == 1 == part + * */ +char* GrepAndFind(int type, int depth, int maxdepth, const char *sDir, char* searchTerm, char* filename, int findaction, int partOrWhole) +{ + char* buffer = NULL; + char *p = NULL; + DIR *dir_ptr; // the directory + struct dirent *direntp; // each entry + struct stat statval; + int foundtext = 0; + char* results = NULL; + int throttleCount = 0; + + if (maxdepth != -1 && depth > maxdepth){ + return NULL; + } + + if (type != 0 && searchTerm == NULL){ + return NULL; + } + + if((dir_ptr = opendir(sDir)) == NULL){ + #ifdef DEBUG + fprintf(stderr, "ls: cannot open %s\n", sDir); + #endif + } + else + { + while((direntp=readdir(dir_ptr)) != NULL){ + p = (char *)malloc(strlen(sDir) + strlen(direntp->d_name) + 2); + if (p == NULL){ + break; + } + strcpy(p, sDir); + strcat(p, "/"); + strcat(p, direntp->d_name); + __xstat(0, p, &statval); + throttleCount++; + if (throttleCount%10 == 0){ + throttleCount = 0; + usleep(1000); + } + /* Skip the . or .. files */ + if (strcmp(".", direntp->d_name) != 0 && strcmp("..", direntp->d_name)){ + if ((statval.st_mode & S_IFMT) == S_IFDIR){ + //printf("Its a folder\n"); + GrepAndFind(type, depth+1, maxdepth, p, searchTerm, filename, findaction, partOrWhole); + } + if (type == 1){ + results = NULL; + if (partOrWhole == 1){ + results = strstr(direntp->d_name, searchTerm); + } + else{ + if (0 == strcmp(direntp->d_name, searchTerm)){ + results = (void*)-1; + } + } + if (results != NULL && findaction == 0){ + BeaconPrintf(CALLBACK_OUTPUT, "Found: %s\n", p); + } + else if (results != NULL && findaction == 2){ + readlink_action(p); + } + else if (results != NULL && findaction == 1){ + cat_action(p); + } + } + else if (type == 2){ + if (filename == NULL){ + foundtext = search_contents(p, searchTerm); + if (foundtext){ + BeaconPrintf(CALLBACK_OUTPUT, "Found: %s\n", p); + } + } + else{ + results = strstr(direntp->d_name, filename); + if (results){ + foundtext = search_contents(p, searchTerm); + if (foundtext){ + BeaconPrintf(CALLBACK_OUTPUT, "Found: %s\n", p); + } + } + } + } + else{ + BeaconPrintf(CALLBACK_OUTPUT, "%s\n", p); + } + } + free(p); + } + closedir(dir_ptr); + } + return buffer; +} + +int go(char* indata, int inlen){ + datap parser; + char* folderpath = NULL; + char* searchpath = NULL; + char* filepath = NULL; + int maxdepth = 0; + int findaction = 0; + int partOrWhole = 0; + + BeaconDataParse(&parser, indata, inlen); + folderpath = BeaconDataExtract(&parser, NULL); + searchpath = BeaconDataExtract(&parser, NULL); + filepath = BeaconDataExtract(&parser, NULL); + maxdepth = BeaconDataInt(&parser); + findaction = BeaconDataInt(&parser); + partOrWhole = BeaconDataInt(&parser); + + BeaconPrintf(CALLBACK_OUTPUT, "Folder: %s\n", folderpath); + BeaconPrintf(CALLBACK_OUTPUT, "Search: %s\n", searchpath); + BeaconPrintf(CALLBACK_OUTPUT, "Filename: %s\n", filepath); + if (filepath[0] == 0){ + BeaconPrintf(CALLBACK_OUTPUT, "Setting it to NULL\n"); + filepath = NULL; + } + BeaconPrintf(CALLBACK_OUTPUT, "Depth: %d\n", maxdepth); + (void)GrepAndFind(2, 0, maxdepth, folderpath, searchpath, filepath, findaction, partOrWhole); + + return 0; +} + +#ifdef TEST_GREP +int main(int argc, char* argv[]){ + GrepAndFind(2, 0, atoi(argv[1]), argv[4], argv[5], argv[6], atoi(argv[2]), atoi(argv[3])); + return 0; +} +#endif diff --git a/SA/src/id.c b/SA/src/id.c new file mode 100644 index 0000000..f4712f8 --- /dev/null +++ b/SA/src/id.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "beacon_api.h" + +int run_id(void){ + uid_t uid = 0; + gid_t gid = 0; + gid_t gidList[25] = {0}; + char* username = NULL; + char* groupname = NULL; + struct passwd *pwd; + struct group *groupval; + int checkval = 0; + int counter = 0; + + uid = getuid(); + pwd = getpwuid(uid); + if (pwd == NULL){ + username = calloc(strlen("UNKNOWN")+1, 1); + if (username) { + memcpy(username, "UNKNOWN", strlen("UNKNOWN")); + } + } + else{ + username = calloc(strlen(pwd->pw_name)+1, 1); + if (username) { + memcpy(username, pwd->pw_name, strlen(pwd->pw_name)); + } + } + gid = getgid(); + checkval = getgroups(25, gidList); + groupval = getgrgid(gid); + BeaconPrintf(CALLBACK_OUTPUT, "uid=%d(%s) gid=%d(%s), groups=%d(%s)", uid, username?username:"ERROR", gid, groupval?groupval->gr_name:"ERROR", gid, groupval?groupval->gr_name:"ERROR"); + if (checkval >0){ + for (counter=0; counter < checkval; counter++){ + groupval = getgrgid(gidList[counter]); + BeaconPrintf(CALLBACK_OUTPUT, ",%d(%s)",gidList[counter], groupval?groupval->gr_name:"ERROR"); + } + } + BeaconPrintf(CALLBACK_OUTPUT, "\n"); + if (username){ + free(username); + } + return 0; +} + +int go(char* indata, int inlen){ + (void)run_id(); + return 0; +} + + +#ifdef TEST_ID +int main(void){ + return run_id(); +} +#endif diff --git a/SA/src/ifconfig.c b/SA/src/ifconfig.c new file mode 100644 index 0000000..099d135 --- /dev/null +++ b/SA/src/ifconfig.c @@ -0,0 +1,99 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "beacon_api.h" + +int run_ifconfig(void){ + struct ifaddrs *ifap = NULL; + struct ifaddrs *ifa = NULL; + struct ifaddrs *ifa2 = NULL; + int checkcode = 0; + struct sockaddr_in *sin = NULL; + struct sockaddr_in *sin_netmask = NULL; + struct sockaddr_in *sin_broadcast = NULL; + struct sockaddr_in6 *sin6 = NULL; + char ip6buf[256*2 + 1]; + + checkcode = getifaddrs(&ifap); + if (checkcode != 0){ + return 0; + } + + /* Loop through the entries once, with just AF_PACKET/AF_LINK types + * print the name, then iterate over the rest of the entries ignoring + * the AF_LINK/AF_PACKET case, and print the addresses we want to handle + * and print the unknown types encountered for future reference. */ + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + switch(ifa->ifa_addr->sa_family){ +#ifdef __APPLE__ + case AF_LINK: +#else + case AF_PACKET: +#endif + BeaconPrintf(CALLBACK_OUTPUT, "%s:\n", ifa->ifa_name); + for (ifa2 = ifap; ifa2; ifa2 = ifa2->ifa_next) { + if (strcmp(ifa->ifa_name, ifa2->ifa_name) != 0){ + continue; + } + switch(ifa2->ifa_addr->sa_family){ + case AF_INET: + sin = (struct sockaddr_in*)ifa2->ifa_addr; + sin_netmask = (struct sockaddr_in*)ifa2->ifa_netmask; + sin_broadcast = (struct sockaddr_in*) ifa2->ifa_broadaddr; + BeaconPrintf(CALLBACK_OUTPUT, "\tIP Address: %s\n", inet_ntoa(sin->sin_addr)); + BeaconPrintf(CALLBACK_OUTPUT, "\tNetmask: %s\n", inet_ntoa(sin_netmask->sin_addr)); + BeaconPrintf(CALLBACK_OUTPUT, "\tBroadcast: %s\n", inet_ntoa(sin_broadcast->sin_addr)); + break; + case AF_INET6: + sin6 = (struct sockaddr_in6*)ifa2->ifa_addr; + inet_ntop(AF_INET6, &sin6->sin6_addr, ip6buf, sizeof(ip6buf)); + BeaconPrintf(CALLBACK_OUTPUT, "\tIPv6 Address: %s\n", ip6buf); + break; +#ifdef __APPLE__ + case AF_LINK: +#else + case AF_PACKET: +#endif + break; + default: + BeaconPrintf(CALLBACK_OUTPUT, "Unsupported address family: %d\n", ifa->ifa_addr->sa_family); + break; + } + } + + break; + default: + break; + } + } + if (ifap){ + freeifaddrs(ifap); + } + return 0; +} + +int go(char* indata, int inlen){ + + (void)run_ifconfig(); + return 0; +} + +#ifdef TEST_IFCONFIG +int main(void){ + (void)run_ifconfig(); + return 0; +} +#endif diff --git a/SA/src/pwd.c b/SA/src/pwd.c new file mode 100644 index 0000000..7f75cf0 --- /dev/null +++ b/SA/src/pwd.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +#include "beacon_api.h" + +int run_pwd(void){ + int retcode = 0; + char workingdir[256] = {0}; + char* workdir = NULL; + workdir = getcwd(workingdir, 255); + if (workdir == NULL){ + BeaconPrintf(CALLBACK_OUTPUT, "ERROR\n"); + } + else{ + BeaconPrintf(CALLBACK_OUTPUT, "%s\n", workingdir); + } + return 0; +} + +int go(char* indata, int inlen){ + + (void)run_pwd(); + return 0; +} + +#ifdef TEST_PWD +int main(void){ + return run_pwd(); +} +#endif diff --git a/SA/src/tasklist.c b/SA/src/tasklist.c new file mode 100644 index 0000000..e2f81d8 --- /dev/null +++ b/SA/src/tasklist.c @@ -0,0 +1,238 @@ +#include +#include +#include +#include +#include +#include + +#ifndef DEBUG +#include "beacon_api.h" +#else +#define BeaconOutput(x, y, z) write(1, y, z) +#endif + +char* getContents(unsigned char* filepath, uint32_t* outsize){ + FILE *fin = NULL; + uint32_t fsize = 0; + uint32_t readsize = 0; + unsigned char* buffer = NULL; + unsigned char* tempbuffer = NULL; + + fin = fopen((char*)filepath, "rb"); + if (fin == NULL){ + return NULL; + } + //fseek(fin, 0, SEEK_END); + //fsize = ftell(fin); + fseek(fin, 0, SEEK_SET); + fsize = 0x10000; + tempbuffer = calloc(fsize, 1); + if (tempbuffer == NULL){ + return NULL; + } + memset(tempbuffer, 0, fsize); + readsize = fread(tempbuffer, 1, fsize, fin); + *outsize = readsize; + fclose(fin); + if (readsize == 0){ + free(tempbuffer); + return NULL; + } + buffer = calloc(readsize, 1); + if (buffer == NULL){ + return NULL; + } + memset(buffer, 0, readsize); + memcpy(buffer, tempbuffer, readsize-1); + free(tempbuffer); + return (char*)buffer; +} + + +int go(char* indata, int inlen){ + char* results = NULL; + char* tempresults = NULL; + DIR* procdir = NULL; + struct dirent *proc_entry; + char* filepath = NULL; + char proc_path[320]; + char* statusfile = NULL; + char* cmdline = NULL; + char* ptr = NULL; + char* linename = NULL; + char* linecontents = NULL; + char* uid = NULL; + char* ppid = NULL; + char* state = NULL; + char* fullline = NULL; + int resultslen = 0; + uint32_t filesize = 0; + int i = 0; + filepath = calloc(4096, 1); + linename = calloc(256, 1); + linecontents = calloc(2048, 1); + uid = calloc(50, 1); + ppid = calloc(50, 1); + state = calloc(10, 1); + + if (!filepath || !linename || !linecontents || !uid || !ppid || !state){ + goto cleanup; + } + + procdir = opendir( "/proc/" ); + while( NULL != (proc_entry = readdir(procdir))){ + if (strspn(proc_entry->d_name, "0123456789" ) == strlen(proc_entry->d_name)){ + memset(proc_path, 0, 320); + memset(filepath, 0, 4096); + memset(linecontents, 0, 2048); + sprintf(proc_path, "/proc/%s/exe", proc_entry->d_name); + readlink(proc_path, filepath, 4095); + memset(proc_path, 0, 256); + sprintf(proc_path, "/proc/%s/status", proc_entry->d_name); + statusfile = getContents((unsigned char*)proc_path, &filesize); + if (statusfile == NULL){ + continue; + } + sprintf(proc_path, "/proc/%s/cmdline", proc_entry->d_name); + cmdline = getContents((unsigned char*)proc_path, &filesize); + if (cmdline != NULL){ + for (i=0; id_name)+25, 1); + if (fullline == NULL){ + if (statusfile){ + free(statusfile); + statusfile = NULL; + } + if (cmdline){ + free(cmdline); + cmdline = NULL; + } + break; + } + sprintf(fullline, "%s\t%s\t%s\t%s\t%s\n", uid, proc_entry->d_name, ppid, state, filepath); + tempresults = realloc(results, resultslen+strlen(fullline)+1); + if (tempresults == NULL){ + if (fullline){ + free(fullline); + fullline = NULL; + } + if (statusfile){ + free(statusfile); + statusfile = NULL; + } + if (cmdline){ + free(cmdline); + cmdline = NULL; + } + goto error; + } + results = tempresults; + memset(results+resultslen, 0, strlen(fullline)+1); + memcpy(results+resultslen, fullline, strlen(fullline)); + resultslen += strlen(fullline); + if (cmdline){ + free(cmdline); + cmdline = NULL; + } + if (statusfile){ + free(statusfile); + statusfile = NULL; + } + if (fullline){ + free(fullline); + fullline = NULL; + } + } + } + BeaconOutput(CALLBACK_OUTPUT, results, strlen(results)); + + if (results){ + free(results); + results = NULL; + } + goto cleanup; + +retlab: + return 0; + +error: + +cleanup: + if (procdir){ + closedir(procdir); + procdir = NULL; + } + /* Free all temporary allocated buffers*/ + if (filepath){ + memset(filepath, 0, 4096); + free(filepath); + filepath = NULL; + } + if (linename){ + memset(linename, 0, 256); + free(linename); + linename = NULL; + } + if (linecontents){ + memset(linecontents, 0, 2048); + free(linecontents); + linecontents = NULL; + } + if (uid){ + memset(uid, 0, 50); + free(uid); + uid = NULL; + } + if (ppid){ + memset(ppid, 0, 50); + free(ppid); + ppid = NULL; + } + if (state){ + memset(state, 0, 10); + free(state); + state = NULL; + } + goto retlab; +} + +#ifdef DEBUG + +int main(void){ + (void)go(NULL, 0); + return 0; +} +#endif diff --git a/SA/src/uname.c b/SA/src/uname.c new file mode 100644 index 0000000..4293aba --- /dev/null +++ b/SA/src/uname.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include + +#include "beacon_api.h" + +int run_uname(void){ + struct utsname values; + int retcode = 0; + retcode = uname(&values); + BeaconPrintf(CALLBACK_OUTPUT, "%s %s %s %s %s\n", values.sysname, values.nodename, values.release, values.version, values.machine); + return 0; +} + +int go(char* indata, int inlen){ + + (void)run_uname(); + return 0; +} + +#ifdef TEST_UNAME +int main(void){ + return run_uname(); +} +#endif diff --git a/SA/src/walk.c b/SA/src/walk.c new file mode 100644 index 0000000..99793ba --- /dev/null +++ b/SA/src/walk.c @@ -0,0 +1,145 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "beacon_api.h" + +/* Basic memory search that returns the offset */ +char* memsearch(char* bytes, char* searchTerm, int size){ + int compareval = 0; + int counter = 0; + char* retcode = NULL; + + for (counter=0; counter < size; counter++){ + compareval = memcmp(bytes+counter, searchTerm, strlen(searchTerm)); + if (compareval == 0){ + retcode = bytes+counter; + break; + } + } + return retcode; +} + +/* Read chunks, and then compare the memory to that it has a few problems + * mostly that it will miss anything that happens to be in the overlap + * between readin chunks */ +int search_contents(char* filestr, char* searchTerm){ + FILE* fin = NULL; + char readin[2049]; + size_t readsize = 1; + char* results = 0; + int returncode = 0; + + memset(readin, 0, 2049); + if (filestr == NULL){ + return 0; + } + + fin = fopen(filestr, "r"); + if (fin == NULL){ + //printf("Failed to open file: %s\n", filestr); + return 0; + } + while (readsize != 0){ + readsize = fread(readin, 1, 2048, fin); + results = memsearch(readin, searchTerm, readsize); + if (results != NULL){ + returncode = 1; + break; + } + memset(readin, 0, 2049); + } + (void)fclose(fin); + return returncode; +} + + + +/* Type == 1 == Find + * Type == 2 == Grep + * */ +char* GrepAndFind(int type, int depth, int maxdepth, const char *sDir, char* searchTerm) +{ + char* buffer = NULL; + char *p = NULL; + DIR *dir_ptr; // the directory + struct dirent *direntp; // each entry + struct stat statval; + int foundtext = 0; + char* results = NULL; + + if (maxdepth != -1 && depth > maxdepth){ + return NULL; + } + + if (type != 0 && searchTerm == NULL){ + return NULL; + } + + if((dir_ptr = opendir(sDir)) == NULL){ + #ifdef DEBUG + fprintf(stderr, "ls: cannot open %s\n", sDir); + #endif + } + else + { + while((direntp=readdir(dir_ptr)) != NULL){ + p = (char *)malloc(strlen(sDir) + strlen(direntp->d_name) + 2); + if (p == NULL){ + break; + } + strcpy(p, sDir); + strcat(p, "/"); + strcat(p, direntp->d_name); + __xstat(0, p, &statval); + /* Skip the . or .. files */ + if (strcmp(".", direntp->d_name) != 0 && strcmp("..", direntp->d_name)){ + if ((statval.st_mode & S_IFMT) == S_IFDIR){ + //printf("Its a folder\n"); + GrepAndFind(type, depth+1, maxdepth, p, searchTerm); + } + if (type == 1){ + results = strstr(direntp->d_name, searchTerm); + if (results != NULL){ + BeaconPrintf(CALLBACK_OUTPUT, "Found: %s\n", p); + } + } + else if (type == 2){ + foundtext = search_contents(p, searchTerm); + if (foundtext){ + BeaconPrintf(CALLBACK_OUTPUT, "Found: %s\n", p); + } + } + else{ + BeaconPrintf(CALLBACK_OUTPUT, "%s\n", p); + } + } + free(p); + } + closedir(dir_ptr); + } + return buffer; +} + +int go(char* indata, int inlen){ + datap parser; + char* folderpath = NULL; + int maxdepth = 0; + BeaconDataParse(&parser, indata, inlen); + maxdepth = BeaconDataInt(&parser); + folderpath = BeaconDataExtract(&parser, NULL); + (void)GrepAndFind(0, 0, maxdepth, folderpath, NULL); + return 0; +} + + +#ifdef TEST_WALK +int main(int argc, char* argv[]){ + GrepAndFind(0, 0, 2, argv[1], argv[2]); + return 0; +} +#endif diff --git a/SA/src/whoami.c b/SA/src/whoami.c new file mode 100644 index 0000000..82b1992 --- /dev/null +++ b/SA/src/whoami.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include + +#include "beacon_api.h" + +#define PATH_MAX 2048 + +int test3(void){ + printf("This is the test3 function\n"); + return 0; +} + + +int go(char* indata, int inlen){ + char* pwdOutput = NULL; + char* testptr = NULL; + pwdOutput = calloc(PATH_MAX+1, 1); + + BeaconPrintf(CALLBACK_OUTPUT, "UID: %d EUID: %d\n", getuid(), geteuid()); + if (pwdOutput != NULL){ + testptr = getcwd(pwdOutput, PATH_MAX); + if (testptr != NULL){ + BeaconPrintf(CALLBACK_OUTPUT, "Current Working Directory: %s\n", testptr); + } + } + if (getuid() == 0){ + BeaconPrintf(CALLBACK_OUTPUT, "Running as root!!!!\n"); + } + else{ + BeaconPrintf(CALLBACK_OUTPUT, "Running as a standard user.\n"); + } + if (pwdOutput){ + free(pwdOutput); + } + return 0; +} diff --git a/Scripts/beacon_generate.py b/Scripts/beacon_generate.py new file mode 100644 index 0000000..cb65893 --- /dev/null +++ b/Scripts/beacon_generate.py @@ -0,0 +1,96 @@ +from struct import pack, calcsize +import binascii +import cmd + +class BeaconPack: + def __init__(self): + self.buffer = b'' + self.size = 0 + + def getbuffer(self): + return pack("> 8) +#define SHT_REL_TYPE SHT_REL +#define X86 +#else +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Phdr Elf64_Phdr +#define Elf_Sym Elf64_Sym +#define Elf_Rel Elf64_Rela +#define Elf_Shdr Elf64_Shdr +#define ELF_R_TYPE(i) ((i) & 0xffffffff) +#define ELF_R_SYM(x) ((x) >> 32) +#define SHT_REL_TYPE SHT_RELA +#endif + +typedef struct ELFInfo { + Elf_Ehdr *Header; + Elf_Phdr *progHeader; + int progHeaderSize; + Elf_Shdr *sectHeader; + int sectHeaderSize; + unsigned char* execPtr; + Elf_Sym *symbolTable; + char* stringTable; + char* sectionStringTable; + unsigned char** sectionMappings; + int* sectionMappingProts; + unsigned char* tempOffsetTable; + int tempOffsetCounter; +} ELFInfo_t; +/* x86_64 */ + +#ifdef WIN32 +#define PROT_READ PAGE_EXECUTE_READWRITE +#define PROT_WRITE PAGE_EXECUTE_READWRITE +#define PROT_EXEC PAGE_EXECUTE_READWRITE +#endif + +#if defined(__amd64__) || defined(__x86_64__) +unsigned char* ThunkTrampoline = (unsigned char*)"\x48\xb8\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xff\xe0"; +int ThunkTrampolineSize = 12; +#define THUNKOFFSET 2 +#define COMPILEDMACHINEARCH EM_X86_64 +#endif + +/* x86 */ +#if defined(__i386__) +unsigned char* ThunkTrampoline = (unsigned char*)"\x68\x00\x00\x00\x00\x58\xff\xe0"; +int ThunkTrampolineSize = 8; +#define THUNKOFFSET 1 +#define COMPILEDMACHINEARCH EM_386 +#endif + +int ELFRunner(char* functionName, unsigned char* elfObjectData, unsigned int size, unsigned char* argumentdata, int argumentSize); +#endif diff --git a/includes/beacon_api.h b/includes/beacon_api.h new file mode 100644 index 0000000..f888032 --- /dev/null +++ b/includes/beacon_api.h @@ -0,0 +1,58 @@ +/* + * Cobalt Strike 4.X BOF compatibility layer + * ----------------------------------------- + * The whole point of these files are to allow beacon object files built for CS + * to run fine inside of other tools without recompiling. + * + * Built off of the beacon.h file provided to build for CS. + */ +#ifndef BEACON_API_H_ +#define BEACON_API_H_ + +/* Structures as is in beacon.h */ + +typedef struct { + char * original; /* the original buffer [so we can free it] */ + char * buffer; /* current pointer into our buffer */ + int length; /* remaining length of data */ + int size; /* total size of this buffer */ +} datap; + +typedef struct { + char * original; /* the original buffer [so we can free it] */ + char * buffer; /* current pointer into our buffer */ + int length; /* remaining length of data */ + int size; /* total size of this buffer */ +} formatp; + +void BeaconDataParse(datap * parser, char * buffer, int size); +int BeaconDataInt(datap * parser); +short BeaconDataShort(datap * parser); +int BeaconDataLength(datap * parser); +char * BeaconDataExtract(datap * parser, int * size); + +void BeaconFormatAlloc(formatp * format, int maxsz); +void BeaconFormatReset(formatp * format); +void BeaconFormatFree(formatp * format); +void BeaconFormatAppend(formatp * format, char * text, int len); +void BeaconFormatPrintf(formatp * format, char * fmt, ...); +char * BeaconFormatToString(formatp * format, int * size); +void BeaconFormatInt(formatp * format, int value); + +#define CALLBACK_OUTPUT 0x0 +#define CALLBACK_OUTPUT_OEM 0x1e +#define CALLBACK_ERROR 0x0d +#define CALLBACK_OUTPUT_UTF8 0x20 + + +void BeaconPrintf(int type, char * fmt, ...); +void BeaconOutput(int type, char * data, int len); + +/* Token Functions */ +int BeaconIsAdmin(); + +uint32_t swap_endianess(uint32_t indata); + +char* BeaconGetOutputData(int *outsize); +char** getEnviron(void); +#endif diff --git a/includes/beacon_compatibility.h b/includes/beacon_compatibility.h new file mode 100644 index 0000000..c147c8d --- /dev/null +++ b/includes/beacon_compatibility.h @@ -0,0 +1,66 @@ +/* + * Cobalt Strike 4.X BOF compatibility layer + * ----------------------------------------- + * The whole point of these files are to allow beacon object files built for CS + * to run fine inside of other tools without recompiling. + * + * Built off of the beacon.h file provided to build for CS. + */ +#ifndef BEACON_COMPATIBILITY_H_ +#define BEACON_COMPATIBILITY_H_ +typedef struct beacon_function{ + char* functionName; + void* function; +} beacon_function_t; + +extern beacon_function_t BeaconInternalMapping[17]; +#define BEACONINTERNALMAPPINGCOUNT 16 + +void* internalFunctionLookup(char* symbolName); +/* Structures as is in beacon.h */ + +typedef struct { + char * original; /* the original buffer [so we can free it] */ + char * buffer; /* current pointer into our buffer */ + int length; /* remaining length of data */ + int size; /* total size of this buffer */ +} datap; + +typedef struct { + char * original; /* the original buffer [so we can free it] */ + char * buffer; /* current pointer into our buffer */ + int length; /* remaining length of data */ + int size; /* total size of this buffer */ +} formatp; + +void BeaconDataParse(datap * parser, char * buffer, int size); +int BeaconDataInt(datap * parser); +short BeaconDataShort(datap * parser); +int BeaconDataLength(datap * parser); +char * BeaconDataExtract(datap * parser, int * size); + +void BeaconFormatAlloc(formatp * format, int maxsz); +void BeaconFormatReset(formatp * format); +void BeaconFormatFree(formatp * format); +void BeaconFormatAppend(formatp * format, char * text, int len); +void BeaconFormatPrintf(formatp * format, char * fmt, ...); +char * BeaconFormatToString(formatp * format, int * size); +void BeaconFormatInt(formatp * format, int value); + +#define CALLBACK_OUTPUT 0x0 +#define CALLBACK_OUTPUT_OEM 0x1e +#define CALLBACK_ERROR 0x0d +#define CALLBACK_OUTPUT_UTF8 0x20 + + +void BeaconPrintf(int type, char * fmt, ...); +void BeaconOutput(int type, char * data, int len); + +/* Token Functions */ +int BeaconIsAdmin(); + +uint32_t swap_endianess(uint32_t indata); + +char* BeaconGetOutputData(int *outsize); +char** getEnviron(void); +#endif diff --git a/includes/debug.h b/includes/debug.h new file mode 100644 index 0000000..a9a7eec --- /dev/null +++ b/includes/debug.h @@ -0,0 +1,9 @@ +#ifndef _DEBUG_H_ +#define _DEBUG_H_ + +#if defined( DEBUG ) + #define DEBUG_PRINT(x, ...) printf(x, ##__VA_ARGS__) + #else + #define DEBUG_PRINT(x, ...) + #endif +#endif diff --git a/includes/minimal_elf.h b/includes/minimal_elf.h new file mode 100644 index 0000000..c3ae406 --- /dev/null +++ b/includes/minimal_elf.h @@ -0,0 +1,205 @@ +#ifndef MINIMAL_ELF_H_ +#define MINIMAL_ELF_H_ + +/* Minimal elf definitions stripped from FreeBSD's headers + * and included so that there's no external dependencies + * for the mac version of the Loader. + * */ + +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 1996-1998 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#define EI_NIDENT 16 +#define EM_386 3 +#define EM_X86_64 62 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_REL 9 +#define R_386_32 1 +#define R_386_PC32 2 + +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; +typedef uint64_t Elf32_Lword; + +typedef Elf32_Word Elf32_Hashelt; + +typedef Elf32_Word Elf32_Size; +typedef Elf32_Sword Elf32_Ssize; + +typedef uint64_t Elf64_Addr; +typedef uint16_t Elf64_Half; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Sword; +typedef int64_t Elf64_Sxword; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Lword; +typedef uint64_t Elf64_Xword; +typedef Elf64_Word Elf64_Hashelt; + +/* Non-standard class-dependent datatype used for abstraction. */ +typedef Elf64_Xword Elf64_Size; +typedef Elf64_Sxword Elf64_Ssize; + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* File identification. */ + Elf64_Half e_type; /* File type. */ + Elf64_Half e_machine; /* Machine architecture. */ + Elf64_Word e_version; /* ELF format version. */ + Elf64_Addr e_entry; /* Entry point. */ + Elf64_Off e_phoff; /* Program header file offset. */ + Elf64_Off e_shoff; /* Section header file offset. */ + Elf64_Word e_flags; /* Architecture-specific flags. */ + Elf64_Half e_ehsize; /* Size of ELF header in bytes. */ + Elf64_Half e_phentsize; /* Size of program header entry. */ + Elf64_Half e_phnum; /* Number of program header entries. */ + Elf64_Half e_shentsize; /* Size of section header entry. */ + Elf64_Half e_shnum; /* Number of section header entries. */ + Elf64_Half e_shstrndx; /* Section name strings section. */ +} Elf64_Ehdr; + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* File identification. */ + Elf32_Half e_type; /* File type. */ + Elf32_Half e_machine; /* Machine architecture. */ + Elf32_Word e_version; /* ELF format version. */ + Elf32_Addr e_entry; /* Entry point. */ + Elf32_Off e_phoff; /* Program header file offset. */ + Elf32_Off e_shoff; /* Section header file offset. */ + Elf32_Word e_flags; /* Architecture-specific flags. */ + Elf32_Half e_ehsize; /* Size of ELF header in bytes. */ + Elf32_Half e_phentsize; /* Size of program header entry. */ + Elf32_Half e_phnum; /* Number of program header entries. */ + Elf32_Half e_shentsize; /* Size of section header entry. */ + Elf32_Half e_shnum; /* Number of section header entries. */ + Elf32_Half e_shstrndx; /* Section name strings section. */ +} Elf32_Ehdr; + +typedef struct { + Elf32_Word sh_name; /* Section name (index into the + section header string table). */ + Elf32_Word sh_type; /* Section type. */ + Elf32_Word sh_flags; /* Section flags. */ + Elf32_Addr sh_addr; /* Address in memory image. */ + Elf32_Off sh_offset; /* Offset in file. */ + Elf32_Word sh_size; /* Size in bytes. */ + Elf32_Word sh_link; /* Index of a related section. */ + Elf32_Word sh_info; /* Depends on section type. */ + Elf32_Word sh_addralign; /* Alignment in bytes. */ + Elf32_Word sh_entsize; /* Size of each entry in section. */ +} Elf32_Shdr; + +typedef struct { + Elf64_Word sh_name; /* Section name (index into the + section header string table). */ + Elf64_Word sh_type; /* Section type. */ + Elf64_Xword sh_flags; /* Section flags. */ + Elf64_Addr sh_addr; /* Address in memory image. */ + Elf64_Off sh_offset; /* Offset in file. */ + Elf64_Xword sh_size; /* Size in bytes. */ + Elf64_Word sh_link; /* Index of a related section. */ + Elf64_Word sh_info; /* Depends on section type. */ + Elf64_Xword sh_addralign; /* Alignment in bytes. */ + Elf64_Xword sh_entsize; /* Size of each entry in section. */ +} Elf64_Shdr; + +typedef struct { + Elf64_Word p_type; /* Entry type. */ + Elf64_Word p_flags; /* Access permission flags. */ + Elf64_Off p_offset; /* File offset of contents. */ + Elf64_Addr p_vaddr; /* Virtual address in memory image. */ + Elf64_Addr p_paddr; /* Physical address (not used). */ + Elf64_Xword p_filesz; /* Size of contents in file. */ + Elf64_Xword p_memsz; /* Size of contents in memory. */ + Elf64_Xword p_align; /* Alignment in memory and file. */ +} Elf64_Phdr; + +typedef struct { + Elf32_Word p_type; /* Entry type. */ + Elf32_Off p_offset; /* File offset of contents. */ + Elf32_Addr p_vaddr; /* Virtual address in memory image. */ + Elf32_Addr p_paddr; /* Physical address (not used). */ + Elf32_Word p_filesz; /* Size of contents in file. */ + Elf32_Word p_memsz; /* Size of contents in memory. */ + Elf32_Word p_flags; /* Access permission flags. */ + Elf32_Word p_align; /* Alignment in memory and file. */ +} Elf32_Phdr; + +/* Relocations that don't need an addend field. */ +typedef struct { + Elf32_Addr r_offset; /* Location to be relocated. */ + Elf32_Word r_info; /* Relocation type and symbol index. */ +} Elf32_Rel; + +/* Relocations that need an addend field. */ +typedef struct { + Elf32_Addr r_offset; /* Location to be relocated. */ + Elf32_Word r_info; /* Relocation type and symbol index. */ + Elf32_Sword r_addend; /* Addend. */ +} Elf32_Rela; + +typedef struct { + Elf32_Word st_name; /* String table index of name. */ + Elf32_Addr st_value; /* Symbol value. */ + Elf32_Word st_size; /* Size of associated object. */ + unsigned char st_info; /* Type and binding information. */ + unsigned char st_other; /* Reserved (not used). */ + Elf32_Half st_shndx; /* Section index of symbol. */ +} Elf32_Sym; + +typedef struct { + Elf64_Word st_name; /* String table index of name. */ + unsigned char st_info; /* Type and binding information. */ + unsigned char st_other; /* Reserved (not used). */ + Elf64_Half st_shndx; /* Section index of symbol. */ + Elf64_Addr st_value; /* Symbol value. */ + Elf64_Xword st_size; /* Size of associated object. */ +} Elf64_Sym; + +/* Relocations that don't need an addend field. */ +typedef struct { + Elf64_Addr r_offset; /* Location to be relocated. */ + Elf64_Xword r_info; /* Relocation type and symbol index. */ +} Elf64_Rel; + +/* Relocations that need an addend field. */ +typedef struct { + Elf64_Addr r_offset; /* Location to be relocated. */ + Elf64_Xword r_info; /* Relocation type and symbol index. */ + Elf64_Sxword r_addend; /* Addend. */ +} Elf64_Rela; + + +#endif diff --git a/src/ELFLoader.c b/src/ELFLoader.c new file mode 100644 index 0000000..67453cf --- /dev/null +++ b/src/ELFLoader.c @@ -0,0 +1,431 @@ +#include +#include +#include +#include +#ifndef WIN32 +#include +#include +#else +#include +#endif + +#include "debug.h" +#include "minimal_elf.h" +#include "ELFLoader.h" +#include "beacon_compatibility.h" + + +unsigned char* unhexlify(unsigned char* value, int *outlen){ + unsigned char* retval = NULL; + char byteval[3] = {0}; + int counter = 0; + int counter2 = 0; + char character = 0; + if (value == NULL){ + return NULL; + } + DEBUG_PRINT("Unhexlify Strlen: %lu\n", (long unsigned int)strlen((char*)value)); + if (value == NULL || strlen((char*)value)%2 != 0){ + DEBUG_PRINT("Either value is NULL, or the hexlified string isn't valid\n"); + goto errcase; + } + + retval = calloc(strlen((char*)value)+1, 1); + if (retval == NULL){ + goto errcase; + } + + counter2 = 0; + for (counter = 0; counter < strlen((char*)value); counter += 2){ + memcpy(byteval, value+counter, 2); + character = strtol(byteval, NULL, 16); + memcpy(retval+counter2, &character, 1); + counter2++; + } + *outlen = counter2; + +errcase: + return retval; +} + + +int ELFRunner(char* functionName, unsigned char* elfObjectData, unsigned int size, unsigned char* argumentdata, int argumentSize){ +#if defined(__amd64__) || defined(__x86_64__) || defined(__i386__) || (defined(DEBUG) && defined(ELFRUNNERTEST)) + ELFInfo_t elfinfo; + int counter = 0; + int c2 = 0; + int (*ptr)(unsigned char*, int); + int retcode = 0; + + memset(&elfinfo, 0, sizeof(ELFInfo_t)); + + elfinfo.Header = (Elf_Ehdr*) elfObjectData; + /* Verify that the data is an ELF file. */ + if (elfObjectData[0] != '\x7f' || elfObjectData[1] != 'E' || elfObjectData[2] != 'L' || elfObjectData[3] != 'F'){ + DEBUG_PRINT("Not an elf file\n"); + retcode = 1; + goto errorcase; + } + /* Verify that the ELF file is a relocatable file, and not a shared object or binary */ + if (elfinfo.Header->e_type != 1){ + DEBUG_PRINT("ELF Type isn't relocatable type, bailing...\n"); + retcode = 2; + goto errorcase; + } + if (elfinfo.Header->e_machine != COMPILEDMACHINEARCH){ + DEBUG_PRINT("ERROR, not the machine type your running on\n"); + retcode = -1; + goto errorcase; + } + DEBUG_PRINT("ELF Object Data: %p\n", elfObjectData); + DEBUG_PRINT("ELF Type: %d\n", elfinfo.Header->e_type); + DEBUG_PRINT("ELF Machine: %d\n", elfinfo.Header->e_machine); + DEBUG_PRINT("ELF Version: %d\n", elfinfo.Header->e_version); + DEBUG_PRINT("ELF Entry: 0x%lx\n", elfinfo.Header->e_entry); + DEBUG_PRINT("ELF ProgramHeaderOffset: 0x%lx\n", elfinfo.Header->e_phoff); + DEBUG_PRINT("ELF SectionHeaderOffset: 0x%lx\n", elfinfo.Header->e_shoff); + DEBUG_PRINT("ELF Flags: 0x%x\n", elfinfo.Header->e_flags); + DEBUG_PRINT("ELF Header Size: %d\n", elfinfo.Header->e_ehsize); + DEBUG_PRINT("ELF Program Header Entry Size: %d\n", elfinfo.Header->e_phentsize); + DEBUG_PRINT("ELF Program Header Entry Count: %d\n", elfinfo.Header->e_phnum); + DEBUG_PRINT("ELF Section Header Entry Size: %d\n", elfinfo.Header->e_shentsize); + DEBUG_PRINT("ELF Section Header Entry Count: %d\n", elfinfo.Header->e_shnum); + DEBUG_PRINT("ELF Section Header Table Index Entry: %d\n", elfinfo.Header->e_shstrndx); + + /* Set all the headers and sizes */ + elfinfo.progHeader = (Elf_Phdr*)(elfObjectData + elfinfo.Header->e_phoff); + elfinfo.sectHeader = (Elf_Shdr*)(elfObjectData + elfinfo.Header->e_shoff); + elfinfo.progHeaderSize = elfinfo.Header->e_phnum; + elfinfo.sectHeaderSize = elfinfo.Header->e_shnum; + + /* This is usually whats important for standard in memory loaders, but since this is loading + * object files, this isn't actually used. Leaving in the loader so I can extend later on.*/ + DEBUG_PRINT("Working with program headers, Count: %d\n", elfinfo.progHeaderSize); + for (counter = 0; counter < elfinfo.progHeaderSize; counter++){ + DEBUG_PRINT("Program Header Entry Counter: %d\n", counter); + DEBUG_PRINT("\tOffset: 0x%lx\n", elfinfo.progHeader[counter].p_offset); + } + /* End the program header loop */ + + elfinfo.sectionMappings = calloc(elfinfo.sectHeaderSize*sizeof(char*), 1); + elfinfo.sectionMappingProts = calloc(elfinfo.sectHeaderSize*sizeof(int), 1); + /* Make sure that the section mappings and protections array is allocated, if not then error out. */ + if (elfinfo.sectionMappings == NULL || elfinfo.sectionMappingProts == NULL){ + DEBUG_PRINT("Failed to setup sectionMappings\n"); + retcode = 3; + goto errorcase; + } + #ifdef WIN32 + elfinfo.tempOffsetTable = VirtualAlloc(NULL, 255*ThunkTrampolineSize, MEM_COMMIT|MEM_RESERVE|MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE); + #else + elfinfo.tempOffsetTable = mmap(NULL, 255*ThunkTrampolineSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + #endif + elfinfo.tempOffsetCounter = 0; + if (elfinfo.tempOffsetTable == NULL){ + DEBUG_PRINT("Failed to allocate the hacky GOT/Thunk function table.\n"); + retcode = 4; + goto errorcase; + } + + DEBUG_PRINT("Working over section headers, Count: %d\n", elfinfo.sectHeaderSize); + for (counter = 0; counter < elfinfo.sectHeaderSize; counter++){ + int sectionProts = PROT_READ | PROT_WRITE; + DEBUG_PRINT("Section Header Entry Counter: %d\n", counter); + DEBUG_PRINT("\tName is %d\n", elfinfo.sectHeader[counter].sh_name); + DEBUG_PRINT("\tType is 0x%x\n", elfinfo.sectHeader[counter].sh_type); + DEBUG_PRINT("\tFlags are 0x%lx\n", elfinfo.sectHeader[counter].sh_flags); + /* Identify the memory permissions here */ + if (elfinfo.sectHeader[counter].sh_flags & 0x1){ + DEBUG_PRINT("\t\tWriteable Section\n"); + sectionProts = PROT_READ | PROT_WRITE; + } + if (elfinfo.sectHeader[counter].sh_flags & 0x4){ + DEBUG_PRINT("\t\tExecutable Section\n"); + sectionProts = PROT_READ | PROT_EXEC; + } + if (elfinfo.sectHeader[counter].sh_size > 0 && elfinfo.sectHeader[counter].sh_type == SHT_PROGBITS){ + #ifdef WIN32 + elfinfo.sectionMappings[counter] = VirtualAlloc(NULL, elfinfo.sectHeader[counter].sh_size, MEM_COMMIT|MEM_RESERVE|MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE); + #else + elfinfo.sectionMappings[counter] = mmap(NULL, elfinfo.sectHeader[counter].sh_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + #endif + if (elfinfo.sectionMappings[counter] == NULL){ + DEBUG_PRINT("\t\t\tFailed to allocate memory for section\n"); + retcode = 5; + goto errorcase; + } + memcpy(elfinfo.sectionMappings[counter], elfObjectData+elfinfo.sectHeader[counter].sh_offset, elfinfo.sectHeader[counter].sh_size); + } + else{ + /* Not allocating memory because the section isn't needed for the program to run, just used to link. */ + DEBUG_PRINT("\t\t\tNot allocating memory for section\n"); + elfinfo.sectionMappings[counter] = NULL; + } + elfinfo.sectionMappingProts[counter] = sectionProts; + + DEBUG_PRINT("\tAddr is 0x%lx\n", elfinfo.sectHeader[counter].sh_addr); + DEBUG_PRINT("\tOffset is 0x%lx\n", elfinfo.sectHeader[counter].sh_offset); + DEBUG_PRINT("\tSize is %ld\n", elfinfo.sectHeader[counter].sh_size); + DEBUG_PRINT("\tLink is %d\n", elfinfo.sectHeader[counter].sh_link); + DEBUG_PRINT("\tInfo is %d\n", elfinfo.sectHeader[counter].sh_info); + DEBUG_PRINT("\tAddrAlign is %ld\n", elfinfo.sectHeader[counter].sh_addralign); + DEBUG_PRINT("\tEntSize is %ld\n", elfinfo.sectHeader[counter].sh_entsize); + /* Locate the sections that we want to keep track to */ + switch (elfinfo.sectHeader[counter].sh_type){ + case SHT_SYMTAB: + DEBUG_PRINT("\t\tSymbol Table\n"); + elfinfo.symbolTable = (Elf_Sym*)(elfObjectData + elfinfo.sectHeader[counter].sh_offset); + elfinfo.stringTable = (char*)(elfObjectData + elfinfo.sectHeader[elfinfo.sectHeader[counter].sh_link].sh_offset); + DEBUG_PRINT("\t\tSymbolTable: %p\n", elfinfo.symbolTable); + DEBUG_PRINT("\t\tStringTable: %p\n", elfinfo.stringTable); + break; + case SHT_STRTAB: + DEBUG_PRINT("\t\tString Table\n"); + elfinfo.sectionStringTable = (char*)(elfObjectData + elfinfo.sectHeader[counter].sh_offset); + break; + default: + DEBUG_PRINT("\t\tCase Not Handled\n"); + break; + } + } + + DEBUG_PRINT("\nWorking over section headers, Round 2, Count: %d\n", elfinfo.sectHeaderSize); + for (counter = 0; counter < elfinfo.sectHeaderSize; counter++){ + DEBUG_PRINT("Section Header Entry Counter: %d\n", counter); + #ifdef DEBUG + char* sym = elfinfo.sectionStringTable + elfinfo.sectHeader[counter].sh_name; + DEBUG_PRINT("\tName is %s\n", sym); + #endif + Elf_Rel* rel = (Elf_Rel*)(elfObjectData + elfinfo.sectHeader[counter].sh_offset); + DEBUG_PRINT("\tType is 0x%x\n", elfinfo.sectHeader[counter].sh_type); + DEBUG_PRINT("\tFlags are 0x%lx\n", elfinfo.sectHeader[counter].sh_flags); + DEBUG_PRINT("\tAddr is 0x%lx\n", elfinfo.sectHeader[counter].sh_addr); + DEBUG_PRINT("\tOffset is 0x%lx\n", elfinfo.sectHeader[counter].sh_offset); + DEBUG_PRINT("\tSize is %ld\n", elfinfo.sectHeader[counter].sh_size); + DEBUG_PRINT("\tLink is %d\n", elfinfo.sectHeader[counter].sh_link); + DEBUG_PRINT("\tInfo is %d\n", elfinfo.sectHeader[counter].sh_info); + DEBUG_PRINT("\tAddrAlign is %ld\n", elfinfo.sectHeader[counter].sh_addralign); + DEBUG_PRINT("\tEntSize is %ld\n", elfinfo.sectHeader[counter].sh_entsize); + /* Handle the relocations here */ + if (elfinfo.sectHeader[counter].sh_type == SHT_REL_TYPE){ + DEBUG_PRINT("\tRelocation Entries:\n"); + for (c2 = 0; c2 < elfinfo.sectHeader[counter].sh_size / sizeof(Elf_Rel); c2++){ + char* relocStr = elfinfo.stringTable + elfinfo.symbolTable[ELF_R_SYM(rel[c2].r_info)].st_name; + char WorkingTrampoline[ThunkTrampolineSize]; + memcpy(WorkingTrampoline, ThunkTrampoline, ThunkTrampolineSize); + DEBUG_PRINT("\t\tSymbol: %s\n", relocStr); + DEBUG_PRINT("\t\tType: 0x%lx\n", ELF_R_TYPE(rel[c2].r_info)); + DEBUG_PRINT("\t\tSymbolValue: 0x%lx\n", elfinfo.symbolTable[ELF_R_SYM(rel[c2].r_info)].st_value); + /* This is the section number where the relocation lives in at x + offset, if its 0 then its a symbol to get + * so get the address, store the address, increase the symbol count, and then continue */ + DEBUG_PRINT("\t\tShndx: 0x%x\n", elfinfo.symbolTable[ELF_R_SYM(rel[c2].r_info)].st_shndx); + if (elfinfo.symbolTable[ELF_R_SYM(rel[c2].r_info)].st_shndx == 0){ + /* This function is a function not defined in the object file, so if we can't resolve it then bail. */ + void* symaddress = NULL; + int32_t relativeOffsetFunc = 0; + symaddress = internalFunctionLookup(relocStr); + /* TODO: Add an in process function lookup here too */ + if (symaddress == NULL){ + DEBUG_PRINT("Failed to find a function!!!!!\n"); + retcode = 6; + goto errorcase; + } + DEBUG_PRINT("\t\tFound Function Address: %p\n", symaddress); + /* Copy over the symaddress to the location of the trampoline */ + memcpy(WorkingTrampoline+THUNKOFFSET, &symaddress, sizeof(void*)); + /* Copy the trampoline bytes over to the tempOffsetTable so relocations work */ + DEBUG_PRINT("TempOffsetCounter: %d\n", elfinfo.tempOffsetCounter); + memcpy(elfinfo.tempOffsetTable+(elfinfo.tempOffsetCounter*ThunkTrampolineSize), WorkingTrampoline, ThunkTrampolineSize); + /* Calculate the relative offset of the function trampoline */ + /* The logic to handle x86_64 is different then x86, so ifdef'ing these out for now */ + #if defined(__amd64__) || defined(__x86_64__) + relativeOffsetFunc = (elfinfo.tempOffsetTable + (elfinfo.tempOffsetCounter *ThunkTrampolineSize))-(elfinfo.sectionMappings[elfinfo.sectHeader[counter].sh_info]+rel[c2].r_offset)+rel[c2].r_addend; + DEBUG_PRINT("\t\tRelativeOffsetFunc: 0x%x\n", relativeOffsetFunc); + /* Copy over the relative offset to the trampoline table */ + memcpy(elfinfo.sectionMappings[elfinfo.sectHeader[counter].sh_info]+rel[c2].r_offset, &relativeOffsetFunc, 4); + #elif defined(__i386__) + /* Need to correct this for x86 and 32 bit arm targets, think its good now. */ + memcpy(&relativeOffsetFunc, elfinfo.sectionMappings[elfinfo.sectHeader[counter].sh_info]+rel[c2].r_offset, 4); + relativeOffsetFunc += (elfinfo.tempOffsetTable + (elfinfo.tempOffsetCounter *ThunkTrampolineSize))-(elfinfo.sectionMappings[elfinfo.sectHeader[counter].sh_info]+rel[c2].r_offset); + memcpy(elfinfo.sectionMappings[elfinfo.sectHeader[counter].sh_info]+rel[c2].r_offset, &relativeOffsetFunc, 4); + #else + DEBUG_PRINT("ERROR: Not configured for this architecture\n"); + #endif + /* Once set increment the Thunk Trampoline counter to the next one */ + elfinfo.tempOffsetCounter+=1; + + } + else if (elfinfo.sectHeader[counter].sh_flags== 0x40){ + /* Handle the relocations for values and functions included in the object file */ + /* NOTE: If sh_flags == 0x40, then sh_info contains the section the relocation applies too */ + #if defined(__amd64__) || defined(__x86_64__) + int32_t relativeOffset = (elfinfo.sectionMappings[elfinfo.symbolTable[ELF_R_SYM(rel[c2].r_info)].st_shndx])-(elfinfo.sectionMappings[elfinfo.sectHeader[counter].sh_info]+rel[c2].r_offset)+rel[c2].r_addend + elfinfo.symbolTable[ELF_R_SYM(rel[c2].r_info)].st_value; + #elif defined(__i386__) + int32_t relativeOffset = 0; + if (ELF_R_TYPE(rel[c2].r_info) == R_386_32){ + DEBUG_PRINT("\t\t32bit Direct\n"); + memcpy(&relativeOffset, elfinfo.sectionMappings[elfinfo.sectHeader[counter].sh_info]+rel[c2].r_offset, 4); + //relativeOffset = (elfinfo.sectionMappings[elfinfo.symbolTable[ELF_R_SYM(rel[c2].r_info)].st_shndx])-(elfinfo.sectionMappings[elfinfo.sectHeader[counter].sh_info]+rel[c2].r_offset)+relativeOffset + elfinfo.symbolTable[ELF_R_SYM(rel[c2].r_info)].st_value; + relativeOffset += elfinfo.symbolTable[ELF_R_SYM(rel[c2].r_info)].st_value; + relativeOffset += (int32_t)(elfinfo.sectionMappings[elfinfo.symbolTable[ELF_R_SYM(rel[c2].r_info)].st_shndx]); + } + else if (ELF_R_TYPE(rel[c2].r_info) == R_386_PC32){ + DEBUG_PRINT("\t\tPC relative Address\n"); + memcpy(&relativeOffset, elfinfo.sectionMappings[elfinfo.sectHeader[counter].sh_info]+rel[c2].r_offset, 4); + relativeOffset = (elfinfo.sectionMappings[elfinfo.symbolTable[ELF_R_SYM(rel[c2].r_info)].st_shndx])-(elfinfo.sectionMappings[elfinfo.sectHeader[counter].sh_info]+rel[c2].r_offset)+relativeOffset + elfinfo.symbolTable[ELF_R_SYM(rel[c2].r_info)].st_value; + } + #else + int32_t relativeOffset = 0; + #endif + DEBUG_PRINT("\t\tFirstAddress(NoAddend): %p\n", (elfinfo.sectionMappings[elfinfo.symbolTable[ELF_R_SYM(rel[c2].r_info)].st_shndx])); + + #if defined(__amd64__) || defined(__x86_64__) + DEBUG_PRINT("\t\tFirstAddress: %p\n", (elfinfo.sectionMappings[elfinfo.symbolTable[ELF_R_SYM(rel[c2].r_info)].st_shndx]+rel[c2].r_addend)); + #endif + DEBUG_PRINT("\t\tSecondAddress(NoOffset): %p\n", (elfinfo.sectionMappings[elfinfo.sectHeader[counter].sh_info])); + DEBUG_PRINT("\t\tSecondAddress: %p\n", (elfinfo.sectionMappings[elfinfo.sectHeader[counter].sh_info]+rel[c2].r_offset)); + DEBUG_PRINT("\t\tRelativeOffset: 0x%x\n", relativeOffset); + /* Copy over the relative offset of the value to the section+offset */ + memcpy(elfinfo.sectionMappings[elfinfo.sectHeader[counter].sh_info]+rel[c2].r_offset, &relativeOffset, 4); + } + DEBUG_PRINT("\t\tInfo: 0x%lx\n", rel[c2].r_info); + DEBUG_PRINT("\t\tOffset: 0x%lx\n", rel[c2].r_offset); + #if defined(__amd64__) || defined(__x86_64__) + DEBUG_PRINT("\t\tAddend: 0x%lx\n", rel[c2].r_addend); + #endif + DEBUG_PRINT("\t\t----------------------------------------------------------\n"); + } + } + + /* Handle the symbols here, get the entry points and all that */ + if (elfinfo.sectHeader[counter].sh_type == SHT_SYMTAB){ + for (c2 = 0; c2 < elfinfo.sectHeader[counter].sh_size / sizeof(Elf_Sym); c2 += 1){ + Elf_Sym* syms = (Elf_Sym*)(elfObjectData + elfinfo.sectHeader[counter].sh_offset); + //DEBUG_PRINT("\t\t0x%x\n", syms[c2].st_name); + DEBUG_PRINT("\t\tSymbolName: %s\n", elfinfo.stringTable + syms[c2].st_name); + if (strcmp(functionName, elfinfo.stringTable + syms[c2].st_name) == 0){ + DEBUG_PRINT("\t\t\tFOUND GO!\n"); + ptr = (int (*)(unsigned char *, int))elfinfo.sectionMappings[syms[c2].st_shndx] + syms[c2].st_value; + } + DEBUG_PRINT("\t\tSymbolSectionIndex: %d\n", syms[c2].st_shndx); + if (elfinfo.sectionMappings != NULL && syms[c2].st_shndx < elfinfo.sectHeaderSize && syms[c2].st_shndx != 0){ + DEBUG_PRINT("\t\tSymbolAddress(real): %p\n", elfinfo.sectionMappings[syms[c2].st_shndx] + syms[c2].st_value); + } + } + } + } + + DEBUG_PRINT("TempOffsetTable: %p\n", elfinfo.tempOffsetTable); + #ifdef WIN32 + DEBUG_PRINT("Skipping mprotect code for windows, already executable.\n"); + #else + if (mprotect(elfinfo.tempOffsetTable, 255*ThunkTrampolineSize, PROT_READ | PROT_EXEC) != 0){ + DEBUG_PRINT("Failed to mprotect the thunk table\n"); + } + #endif + /* TODO: Set all the permissions of the sectionMappings, sectionMappingProts, and tempOffsetTable */ + for (counter = 0; counter < elfinfo.sectHeaderSize; counter++){ + DEBUG_PRINT("Section #%d mapped at %p\n", counter, elfinfo.sectionMappings[counter]); + if (elfinfo.sectionMappings[counter] != NULL){ + #ifdef WIN32 + DEBUG_PRINT("Not doing mprotect for windows, already executable.\n"); + #else + if (mprotect(elfinfo.sectionMappings[counter], elfinfo.sectHeader[counter].sh_size, elfinfo.sectionMappingProts[counter]) != 0){ + DEBUG_PRINT("Failed to protect memory\n"); + } + #endif + } + } + DEBUG_PRINT("Trying to run ptr......\n"); + /* NOTE: Change this to pass in arguments for ones that use it */ + (void)ptr(argumentdata, argumentSize); + DEBUG_PRINT("Returned from ptr\n"); + +cleanup: + DEBUG_PRINT("Cleaning up...\n"); + for (counter = 0; counter < elfinfo.sectHeaderSize; counter++){ + DEBUG_PRINT("Freeing Section #%d\n", counter); + if (elfinfo.sectionMappings != NULL){ + if (elfinfo.sectionMappings[counter] != NULL){ + #ifdef WIN32 + VirtualFree(elfinfo.sectionMappings[counter], 0, MEM_RELEASE); + #else + if (munmap(elfinfo.sectionMappings[counter], elfinfo.sectHeader[counter].sh_size) != 0){ + DEBUG_PRINT("Failed to unmap memory\n"); + } + #endif + } + } + } + if (elfinfo.tempOffsetTable){ + #ifdef WIN32 + VirtualFree(elfinfo.tempOffsetTable, 0, MEM_RELEASE); + #else + munmap(elfinfo.tempOffsetTable, 255*ThunkTrampolineSize); + #endif + } + if (elfinfo.sectionMappings){ + free(elfinfo.sectionMappings); + } + if (elfinfo.sectionMappingProts){ + free(elfinfo.sectionMappingProts); + } + + goto retlab; + +retlab: + DEBUG_PRINT("Returning\n"); + return retcode; + +errorcase: + DEBUG_PRINT("ERRORCASE!!!!\n"); + goto cleanup; +#else + return -1; +#endif /* Wrapper ifdef for supported arch's */ +} + +#ifdef TESTING_MAIN +int main(int argc, char** argv, char** envp) +{ + //int (*ptr)(char*, int*); + unsigned char* buf = NULL; + int size = 0; + FILE* elf = NULL; + int checkcode = 0; + char* outputdata = NULL; + char* argumentdata = NULL; + int argumentdatalen = 0; + int outputdataLen = 0; + + if (argc < 2){ + printf("%s ./path/to/objectfile.o\n", argv[0]); + return 0; + } + elf = fopen(argv[1], "rb"); + if (elf == NULL){ + printf("ERROR: File doesn't exist\n"); + return 0; + } + fseek(elf, 0, SEEK_END); + size = ftell(elf); + fseek(elf, 0, SEEK_SET); + buf = calloc(size, 1); + if (buf == NULL){ + return 0; + } + (void)fread(buf, 1, size, elf); + argumentdata = (char*)unhexlify((unsigned char*)argv[2], &argumentdatalen); + checkcode = ELFRunner("go", buf, size, (unsigned char*)argumentdata, argumentdatalen ); + if (checkcode == 0){ + outputdata = BeaconGetOutputData(&outputdataLen); + printf("Output data : %s\n", outputdata); + free(outputdata); + } + + + free(buf); + fclose(elf); + return 0; +} +#endif diff --git a/src/beacon_compatibility.c b/src/beacon_compatibility.c new file mode 100644 index 0000000..ca84e19 --- /dev/null +++ b/src/beacon_compatibility.c @@ -0,0 +1,314 @@ +/* + * Cobalt Strike 4.X BOF compatibility layer + * ----------------------------------------- + * The whole point of these files are to allow beacon object files built for CS + * to run fine inside of other tools without recompiling. + * + * Built off of the beacon.h file provided to build for CS. + */ +#include +#include +#include +#include +#include +#ifndef WIN32 +#include +#include +#else +#include +#endif + + +#include "beacon_compatibility.h" + +#define X86PATH "System32" +#define X64PATH "sysnative" +#ifdef __APPLE__ +#define INTERNAL_DEFAULT_LIBRARY ((void*) -2) +#else +#define INTERNAL_DEFAULT_LIBRARY NULL +#endif + +extern char** environ; + +/* Data Parsing */ + +beacon_function_t BeaconInternalMapping[17] = { + {"BeaconDataParse", (void*)BeaconDataParse}, + {"BeaconDataInt", (void*)BeaconDataInt}, + {"BeaconDataShort", (void*)BeaconDataShort}, + {"BeaconDataLength", (void*)BeaconDataLength}, + {"BeaconDataExtract", (void*)BeaconDataExtract}, + {"BeaconFormatAlloc", (void*)BeaconFormatAlloc}, + {"BeaconFormatReset", (void*)BeaconFormatReset}, + {"BeaconFormatFree", (void*)BeaconFormatFree}, + {"BeaconFormatAppend", (void*)BeaconFormatAppend}, + {"BeaconFormatPrintf", (void*)BeaconFormatPrintf}, + {"BeaconFormatToString", (void*)BeaconFormatToString}, + {"BeaconFormatInt", (void*)BeaconFormatInt}, + {"BeaconPrintf", (void*)BeaconPrintf}, + {"BeaconOutput", (void*)BeaconOutput}, + {"BeaconIsAdmin", (void*)BeaconIsAdmin}, + {"getEnviron", (void*)getEnviron} +}; + + +char** getEnviron(void){ + return environ; +} + +#ifdef _WIN32 +/* A hacky compatible dlsym function for use on windows systems. + * TODO: Implement a internal function lookup function for all OS's that + * will lookup internal functions, and global functions.*/ +void *dlsym(void *handle, const char *symbol){ + static HMODULE DefaultHandle = NULL; + void* PointerValue = NULL; + if (handle == INTERNAL_DEFAULT_LIBRARY && DefaultHandle == NULL){ + DefaultHandle = LoadLibraryA("msvcrt.dll"); + } + if (DefaultHandle != NULL){ + PointerValue = GetProcAddress(DefaultHandle, symbol); + } + return PointerValue; +} +#endif + + +void* internalFunctionLookup(char* symbolName){ + void* functionaddress = NULL; + int tempcounter = 0; + for (tempcounter = 0; tempcounter < BEACONINTERNALMAPPINGCOUNT; tempcounter++){ + if (strcmp(symbolName, BeaconInternalMapping[tempcounter].functionName) == 0){ + #ifdef DEBUG + printf("\t\tInternalFunction: %s\n", symbolName); + #endif + functionaddress = BeaconInternalMapping[tempcounter].function; + return functionaddress; + } + } + /* If not an internal function, then its an external one */ + if (functionaddress == NULL){ + functionaddress = dlsym(INTERNAL_DEFAULT_LIBRARY, symbolName); + } + return functionaddress; +} + + +uint32_t swap_endianess(uint32_t indata){ + uint32_t testint = 0xaabbccdd; + uint32_t outint = indata; + if (((unsigned char*)&testint)[0] == 0xdd){ + ((unsigned char*)&outint)[0] = ((unsigned char*)&indata)[3]; + ((unsigned char*)&outint)[1] = ((unsigned char*)&indata)[2]; + ((unsigned char*)&outint)[2] = ((unsigned char*)&indata)[1]; + ((unsigned char*)&outint)[3] = ((unsigned char*)&indata)[0]; + } + return outint; +} + +char* beacon_compatibility_output = NULL; +int beacon_compatibility_size = 0; +int beacon_compatibility_offset = 0; + +void BeaconDataParse(datap* parser, char* buffer, int size){ + if (parser == NULL){ + return; + } + parser->original = buffer; + parser->buffer = buffer; + parser->length = size-4; + parser->size = size-4; + parser->buffer += 4; + return; +} + +int BeaconDataInt(datap* parser){ + int32_t fourbyteint = 0; + if (parser->length < 4){ + return 0; + } + memcpy(&fourbyteint, parser->buffer, 4); + parser->buffer += 4; + parser->length -= 4; + return (int)fourbyteint; +} + +short BeaconDataShort(datap* parser){ + int16_t retvalue = 0; + if (parser->length < 2){ + return 0; + } + memcpy(&retvalue, parser->buffer, 2); + parser->buffer += 2; + parser->length -= 2; + return (short)retvalue; +} + +int BeaconDataLength(datap* parser){ + return parser->length; +} + +char* BeaconDataExtract(datap* parser, int* size){ + uint32_t length = 0; + char* outdata = NULL; + /*Length prefixed binary blob, going to assume uint32_t for this.*/ + if (parser->length < 4){ + return NULL; + } + memcpy(&length, parser->buffer, 4); + parser->buffer += 4; + + outdata = parser->buffer; + if (outdata == NULL){ + return NULL; + } + parser->length -=4; + parser->length -= length; + parser->buffer += length; + if (size != NULL && outdata != NULL){ + *size = length; + } + return outdata; +} + +/* format API */ + +void BeaconFormatAlloc(formatp* format, int maxsz){ + if (format == NULL){ + return; + } + format->original = calloc(maxsz, 1); + format->buffer = format->original; + format->length = 0; + format->size = maxsz; + return; +} + +void BeaconFormatReset(formatp* format){ + memset(format->original, 0, format->size); + format->buffer = format->original; + format->length = format->size; + return; +} + +void BeaconFormatFree(formatp* format){ + if (format == NULL){ + return; + } + if (format->original){ + free(format->original); + format->original = NULL; + } + format->buffer = NULL; + format->length = 0; + format->size = 0; + return; +} + +void BeaconFormatAppend(formatp* format, char* text, int len){ + memcpy(format->buffer, text, len); + format->buffer+= len; + format->length+= len; + return; +} + +void BeaconFormatPrintf(formatp* format, char* fmt, ...){ + /*Take format string, and sprintf it into here*/ + va_list args; + int length = 0; + + va_start (args, fmt); + length = vsnprintf(NULL, 0, fmt, args); + va_end(args); + if (format->length + length > format->size){ + return; + } + + va_start (args, fmt); + (void)vsnprintf(format->buffer, length, fmt, args); + va_end(args); + format->length += length; + format->buffer+= length; + return; +} + + +char* BeaconFormatToString(formatp* format, int* size){ + *size = format->length; + return format->original; +} + +void BeaconFormatInt(formatp* format, int value){ + uint32_t indata = value; + uint32_t outdata = 0; + if (format->length + 4 > format->size){ + return; + } + outdata = swap_endianess(indata); + memcpy(format->buffer, &outdata, 4); + format->length += 4; + format->buffer += 4; + return; +} +/* Main output functions */ + +void BeaconPrintf(int type, char* fmt, ...){ + /* Change to maintain internal buffer, and return after done running. */ + int length = 0; + char* tempptr = NULL; + va_list args; + #ifdef DEBUG + va_start (args, fmt); + vprintf(fmt, args); + va_end(args); + #endif + + va_start (args, fmt); + length = vsnprintf(NULL, 0, fmt, args)+1; + va_end(args); + tempptr = realloc(beacon_compatibility_output, beacon_compatibility_size+length+1); + if (tempptr == NULL){ + return; + } + beacon_compatibility_output = tempptr; + memset(beacon_compatibility_output+beacon_compatibility_offset, 0, length+1); + va_start (args, fmt); + length = vsnprintf(beacon_compatibility_output+beacon_compatibility_offset, length, fmt, args); + beacon_compatibility_size+=length; + beacon_compatibility_offset+=length; + va_end(args); + return; +} + +void BeaconOutput(int type, char* data, int len){ + char* tempptr = NULL; + tempptr = realloc(beacon_compatibility_output, beacon_compatibility_size+len+1); + beacon_compatibility_output = tempptr; + if (tempptr == NULL){ + return; + } + memset(beacon_compatibility_output+beacon_compatibility_offset, 0, len+1); + memcpy(beacon_compatibility_output+beacon_compatibility_offset, data, len); + beacon_compatibility_size+=len; + beacon_compatibility_offset+=len; + return; +} + +int BeaconIsAdmin(void){ + /* Leaving this to be implemented by people needing it */ + #ifdef DEBUG + printf("BeaconIsAdmin Called\n"); + #endif + return 0; +} + +char* BeaconGetOutputData(int *outsize){ + char* outdata = beacon_compatibility_output; + *outsize = beacon_compatibility_size; + beacon_compatibility_output = NULL; + beacon_compatibility_size = 0; + beacon_compatibility_offset = 0; + return outdata; +} + diff --git a/testobjects/getuid.c b/testobjects/getuid.c new file mode 100644 index 0000000..0aeaa3c --- /dev/null +++ b/testobjects/getuid.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include + +#include "beacon_api.h" + +#define PATH_MAX 2048 + +int test3(void){ + printf("This is the test3 function\n"); + return 0; +} + + +int go(char* indata, int* outlen){ + char* pwdOutput = NULL; + char* testptr = NULL; + pwdOutput = calloc(PATH_MAX+1, 1); + + BeaconPrintf(CALLBACK_OUTPUT, "UID: %d EUID: %d\n", getuid(), geteuid()); + if (pwdOutput != NULL){ + testptr = getcwd(pwdOutput, PATH_MAX); + if (testptr != NULL){ + BeaconPrintf(CALLBACK_OUTPUT, "Current Working Directory: %s\n", testptr); + } + } + if (getuid() == 0){ + BeaconPrintf(CALLBACK_OUTPUT, "Running as root!!!!\n"); + } + else{ + BeaconPrintf(CALLBACK_OUTPUT, "Running as a standard user.\n"); + } + if (pwdOutput){ + free(pwdOutput); + } + return 0; +} diff --git a/testobjects/test.c b/testobjects/test.c new file mode 100644 index 0000000..1c5e22d --- /dev/null +++ b/testobjects/test.c @@ -0,0 +1,16 @@ +#include +#include +#include +#include "beacon_api.h" + +int test1(void){ + printf("This is a test2\n"); + return 0; +} + +int go(char* indata, int* outlen){ + BeaconPrintf(CALLBACK_OUTPUT, "This is a test BeaconPrintf output\n"); + printf("This is a test\n"); + + return 0; +} diff --git a/testobjects/test2.c b/testobjects/test2.c new file mode 100644 index 0000000..35e64d2 --- /dev/null +++ b/testobjects/test2.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include + + +int go(char* indata, int* outlen){ + printf("This is a test\n"); + printf("UID is: %d\n", getuid()); + printf("This is another test\n"); + if (getuid() > 500){ + printf("Yep its greater than 500\n"); + } + else{ + printf("Nope it isn't\n"); + } + return 0; +} diff --git a/testobjects/test2_duplicatetext.c b/testobjects/test2_duplicatetext.c new file mode 100644 index 0000000..70f33a2 --- /dev/null +++ b/testobjects/test2_duplicatetext.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include + +int test1(void){ + printf("This is the test1 function\n"); + return 0; +} + +int test2(void){ + printf("This is the test2 function\n"); + return 0; +} + +int test3(void){ + printf("This is the test3 function\n"); + return 0; +} + + +int go(char* indata, int* outlen){ + (void)test1(); + (void)test2(); + (void)test3(); + printf("This is a test\n"); + printf("UID is: %d\n", getuid()); + printf("This is another test\n"); + if (getuid() > 500){ + printf("Yep its greater than 500\n"); + } + else{ + printf("Nope it isn't\n"); + } + return 0; +}