Skip to content

Commit

Permalink
Again, multiple changes to improve overall code quality:
Browse files Browse the repository at this point in the history
	- Instead of checking whether a path is relative or absolute,
	  try to interpret the actual type in a separate fuction.
	- A new module state, MSTATE_INITIALIZE, has been added. This
	  state is for code that is only supposed to run once, instead
	  of every run. This replaces the moduleData->initialised flag
	  that i put in earlier.
	- the connect() method (medusaConnect or medusaConnectSSL) is
	  chosen only once, instead of every cycle.
	- Fixed an error in the default switch(nState) case where the
	  state was not set to MSTATE_EXITING after encountering an
	  unknown module state.
  • Loading branch information
Martijn Fleuren committed Oct 4, 2024
1 parent 36f8fee commit 786fd46
Showing 1 changed file with 114 additions and 80 deletions.
194 changes: 114 additions & 80 deletions src/modsrc/web-form.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@

#include "module.h"

#include <sys/socket.h>

#define MODULE_NAME "web-form.mod"
#define MODULE_AUTHOR "Luciano Bello <luciano@linux.org.ar>"
#define MODULE_SUMMARY_USAGE "Brute force module for web forms"
Expand Down Expand Up @@ -97,7 +95,6 @@ typedef struct ModuleData {
char * customHeaders; // Custom headers
int nCustomHeaders; // Number of custom headers
int changedRequestType;
int initialised;
} ModuleDataT;

ModuleDataT * newModuleData() {
Expand All @@ -122,6 +119,7 @@ void freeModuleData(ModuleDataT * moduleData) {

// Tells us whether we are to continue processing or not
typedef enum ModuleState {
MSTATE_INITIALIZE,
MSTATE_NEW,
MSTATE_RUNNING,
MSTATE_EXITING,
Expand Down Expand Up @@ -433,7 +431,7 @@ int initModule(ModuleDataT * _moduleData, sLogin * _psLogin) {
, * pTemp = NULL
;

ModuleStateT nState = MSTATE_NEW;
ModuleStateT nState = MSTATE_INITIALIZE;

sConnectParams params;
memset(&params, 0, sizeof(sConnectParams));
Expand Down Expand Up @@ -461,35 +459,18 @@ int initModule(ModuleDataT * _moduleData, sLogin * _psLogin) {

initConnectionParams(_psLogin, &params);

// Choose which connect function to use based SSL/plain.
int (*_connect)(sConnectParams *) =
(_psLogin->psServer->psHost->iUseSSL > 0)
? &medusaConnectSSL : &medusaConnect;

while (nState != MSTATE_COMPLETE) {

switch (nState) {

case MSTATE_NEW:
// Already have an open socket - close it
if (hSocket > 0)
medusaDisconnect(hSocket);

// Reset from GET to POST if we had to follow a redirect on the previous
// cycle
if (_moduleData->changedRequestType) {
_moduleData->changedRequestType = 0;
_moduleData->formType = FORM_POST;
}

if (_psLogin->psServer->psHost->iUseSSL > 0)
hSocket = medusaConnectSSL(&params);
else
hSocket = medusaConnect(&params);

if (hSocket < 0) {
writeError(ERR_NOTICE, "%s: failed to connect, port %d was not open on %s", MODULE_NAME, params.nPort, _psLogin->psServer->pHostIP);
_psLogin->iResult = LOGIN_RESULT_UNKNOWN;
setPassResult(_psLogin, psCredSet->pPass);
return FAILURE;
}

if (!_moduleData->initialised) {
// Initialise _moduleData with user provided arguments, or with their
// defaults.
case MSTATE_INITIALIZE:

/* Set request parameters */
if (!_moduleData->resourcePath) {
Expand All @@ -515,7 +496,6 @@ int initModule(ModuleDataT * _moduleData, sLogin * _psLogin) {
// Otherwise, set the values to the user specified values.
} else {

/* Only set user-supplied form data on first pass */
if (!_moduleData->formUserKey) {
pTemp = strtok_r(_moduleData->formData, "?", &pStrtokSavePtr);
writeError(ERR_DEBUG_MODULE, "[%s] User-supplied Form Action Method: %s", MODULE_NAME, pTemp);
Expand Down Expand Up @@ -575,7 +555,30 @@ int initModule(ModuleDataT * _moduleData, sLogin * _psLogin) {
_moduleData->customHeaders = charcalloc(1);
}

_moduleData->initialised = 1;
nState = MSTATE_NEW;
break;

// Create a new connection and close the old one if there is still one
// open.
case MSTATE_NEW:

if (hSocket > 0)
medusaDisconnect(hSocket);

// Reset from GET to POST if we had to follow a redirect on the previous
// cycle
if (_moduleData->changedRequestType) {
_moduleData->changedRequestType = 0;
_moduleData->formType = FORM_POST;
}

hSocket = _connect(&params);

if (hSocket < 0) {
writeError(ERR_NOTICE, "%s: failed to connect, port %d was not open on %s", MODULE_NAME, params.nPort, _psLogin->psServer->pHostIP);
_psLogin->iResult = LOGIN_RESULT_UNKNOWN;
setPassResult(_psLogin, psCredSet->pPass);
return FAILURE;
}

nState = MSTATE_RUNNING;
Expand Down Expand Up @@ -620,6 +623,7 @@ int initModule(ModuleDataT * _moduleData, sLogin * _psLogin) {
default:
writeError(ERR_CRITICAL, "Unknown HTTP module state (%d). Exiting...", nState);
_psLogin->iResult = LOGIN_RESULT_UNKNOWN;
nState = MSTATE_EXITING;
break;
}
}
Expand Down Expand Up @@ -859,23 +863,62 @@ static ModuleStateT _request(int hSocket, ModuleDataT * _moduleData, sLogin ** l
}

/**
* Test whether the returned Location header value is a relative path. This is
* a flaky method of testing but for the first version it'll do.
* Collection of values that reflect the different kinds of path we can deal
* with.
*/
typedef enum PathType {
PATHTYPE_UNKNOWN,
PATHTYPE_URI,
PATHTYPE_RELATIVE,
PATHTYPE_ABSOLUTE
} PathTypeT;

/**
* Guess the path type of the Location header value. If it starts with 'http',
* case insensitive, then it is a URI. If it is not a URI, and it starts with a
* '/', then it is absolute. In all other cases it is assumed to be relative.
*/
static uint8_t _isRelativePath(char * path) {
static PathTypeT _pathType(char * path) {

PathTypeT ret = PATHTYPE_UNKNOWN;

char tmp;
char * isURI;

if (path) {

// Absolute paths based on the website root:
// starting with /
// URI's
if (strlen(path) > 4) {
tmp = path[4];
path[4] = '\0';
isURI = strcasestr(path, "http");
path[4] = tmp;

if (isURI) return PATHTYPE_URI;
}

// Definitely not a URI at this point, either ABS or REL
switch (*path) {

// absolute paths start with '/'
case '/':
ret = PATHTYPE_ABSOLUTE;
break;

// relative by default
default:
ret = PATHTYPE_RELATIVE;
break;
}
}

return path[0] == '/';
return ret;
}

/**
* Resolve the path from the Location header with the old path and strip
* request parameters.
*/
static void _resolveLocationPath(char * newLocation, ModuleDataT * _moduleData) {
void _resolveLocationPath(char * newLocation, ModuleDataT * _moduleData) {

char * hasParameters = strchr(newLocation, '?');

Expand All @@ -884,51 +927,38 @@ static void _resolveLocationPath(char * newLocation, ModuleDataT * _moduleData)
if (hasParameters)
*hasParameters = '\0';

// we have to rewrite the Host header if the location specifies a URI, just in
// case. Also works for https.
char * isURI = NULL;
char tmp;
char * buf = NULL
, * end = NULL
;

switch(_pathType(newLocation)) {
case PATHTYPE_RELATIVE:
// Yes, strings are hard. whatever.
buf = charcalloc(2 * (strlen(newLocation) + strlen(_moduleData->resourcePath)));

int overwrite = 0;
// concatenate the strings and let the server figure out the path
// resolution
end = stpcpy(buf, _moduleData->resourcePath);
*(end++) = '/';
strcpy(end, newLocation);

// Check if the value starts with 'http', case insensitive. to do this we
// first check that the length of the string is at least 5 and then we
// temporarily shorten the string to 4 characters and perform the test.
if (strlen(newLocation) > 4) {
tmp = newLocation[4];
newLocation[4] = '\0';
isURI = strcasestr(newLocation, "http");
newLocation[4] = tmp;
free(_moduleData->resourcePath);
_moduleData->resourcePath = buf;
break;

if (isURI) {
// break omitted on purpose!
case PATHTYPE_URI:
free(_moduleData->hostHeader);
_moduleData->hostHeader = strdup(newLocation);

overwrite = 1;
}
}

if (_isRelativePath(newLocation)) {
// Yes, strings are hard. whatever.
char * buf = charcalloc(2 * (strlen(newLocation) + strlen(_moduleData->resourcePath)));
char * end;

// concatenate the strings and let the server figure out the path
// resolution
end = stpcpy(buf, _moduleData->resourcePath);
*(end++) = '/';
strcpy(end, newLocation);

free(_moduleData->resourcePath);
_moduleData->resourcePath = buf;
} else {
overwrite = 1;
}

// for URI and absolute paths, we just overwrite
if (overwrite) {
free(_moduleData->resourcePath);
_moduleData->resourcePath = strdup(newLocation);
case PATHTYPE_ABSOLUTE:
free(_moduleData->resourcePath);
_moduleData->resourcePath = strdup(newLocation);
break;

case PATHTYPE_UNKNOWN:
default:
writeError(ERR_ERROR, "[%s] Path type of \"%s\" is unknown", MODULE_NAME, newLocation);
break;
}
}

Expand Down Expand Up @@ -995,6 +1025,9 @@ int tryLogin(int hSocket, ModuleDataT* _moduleData, sLogin** login, char* szLogi
_moduleData->formType = FORM_GET;
}

// The redirect has now been resolved, we simply do not update the
// username:password pair so that in the next iteration the combination
// will be automatically tried again.
return MSTATE_NEW;
break;

Expand All @@ -1006,7 +1039,7 @@ int tryLogin(int hSocket, ModuleDataT* _moduleData, sLogin** login, char* szLogi
_setPasswordHelper(login, szPassword, LOGIN_RESULT_UNKNOWN);
return MSTATE_EXITING;
break;

// The default error case from the old code
default:
writeError(ERR_ERROR, "The answer was NOT successfully received, understood, and accepted while trying: user: \"%s\", pass: \"%s\", HTTP status code: %3d", szLogin, szPassword, statusCode);
Expand All @@ -1015,6 +1048,7 @@ int tryLogin(int hSocket, ModuleDataT* _moduleData, sLogin** login, char* szLogi
break;
}

// Search for the deny signal.
uint8_t denySignalFound = 0;

while (pReceiveBuffer && *pReceiveBuffer) {
Expand Down

0 comments on commit 786fd46

Please sign in to comment.