Nmap Development mailing list archives
Re: Ncrack postgres + redis modules
From: Fotis Hantzis <ithilgore.ryu.l () gmail com>
Date: Tue, 15 Mar 2016 16:48:00 -0500
Thanks Deirme! They will be integrated in the upcoming Ncrack 0.5 release. Cheers, ithilgore On Tue, Mar 15, 2016 at 4:44 PM, Evangel Deirme <edeirme () gmail com> wrote:
Hey all,
I'm attaching two modules for ncrack that you might find interesting,
postgres and redis. The postgres module is designed to support MD5
authentication and has been tested for versions 9.3.x and 9.4.x. If you
find any bugs please let me know.
======== Postgres ==============
#include "ncrack.h"
#include "nsock.h"
#include "NcrackOps.h"
#include "Service.h"
#include "modules.h"
#include <openssl/md5.h>
#define PSQL_TIMEOUT 20000
#define PSQL_DIGITS 1
#define PSQL_PACKET_LENGTH 4
#define PSQL_AUTH_TYPE 4
#define PSQL_SALT 4
extern void ncrack_read_handler(nsock_pool nsp, nsock_event nse, void
*mydata);
extern void ncrack_write_handler(nsock_pool nsp, nsock_event nse, void
*mydata);
extern void ncrack_module_end(nsock_pool nsp, void *mydata);
static int psql_loop_read(nsock_pool nsp, Connection *con);
unsigned char charToHexDigit(char c);
enum states { PSQL_INIT, PSQL_AUTH, PSQL_FINI };
/* n is the size of src. dest must have at least n * 2 + 1 allocated
bytes. */
static char *enhex(char *dest, const unsigned char *src, size_t n)
{
unsigned int i;
for (i = 0; i < n; i++)
Snprintf(dest + i * 2, 3, "%02x", src[i]);
return dest;
}
/* Arguments are assumed to be non-NULL, with the exception of nc and
cnonce,
which may be garbage only if qop == QOP_NONE. */
static void make_response(char buf[MD5_DIGEST_LENGTH * 2 + 3 + 1],
const char *username, const char *password, const char *salt)
{
char HA1_hex[MD5_DIGEST_LENGTH * 2 + 1], HA2_hex[MD5_DIGEST_LENGTH * 2
+ 1];
unsigned char hashbuf[MD5_DIGEST_LENGTH];
char finalhash[MD5_DIGEST_LENGTH * 2 + 3];
MD5_CTX md5;
/* Calculate MD5(Password + Username) */
MD5_Init(&md5);
MD5_Update(&md5, password, strlen(password));
MD5_Update(&md5, username, strlen(username));
MD5_Final(hashbuf, &md5);
enhex(HA1_hex, hashbuf, sizeof(hashbuf));
/* Calculate response MD5(above + Salt). */
MD5_Init(&md5);
MD5_Update(&md5, HA1_hex, strlen(HA1_hex));
MD5_Update(&md5, salt, strlen(salt));
MD5_Final(hashbuf, &md5);
enhex(buf, hashbuf, sizeof(hashbuf));
/* Add the string md5 at the beggining. */
strncpy(finalhash,"md5", sizeof("md5"));
strncat(finalhash, buf, sizeof(finalhash));
buf[0] = '\0';
strncpy(buf, finalhash, MD5_DIGEST_LENGTH * 2 + 3);
buf[MD5_DIGEST_LENGTH * 2 + 3] = '\0';
}
static int
psql_loop_read(nsock_pool nsp, Connection *con, char *psql_code_ret, char
*psql_salt_ret)
{
int i,j = 0;
char psql_code[PSQL_DIGITS + 1]; /* 1 char + '\0' */
char psql_salt[PSQL_SALT + 1]; /* 4 + '\0' */
char dig[2]; /* temporary digit string */
char *p;
int packet_length;
int authentication_type;
if (con->inbuf == NULL || con->inbuf->get_len() < PSQL_DIGITS + 1) {
nsock_read(nsp, con->niod, ncrack_read_handler, PSQL_TIMEOUT, con);
return -1;
}
/* Get the first character */
p = (char *)con->inbuf->get_dataptr();
dig[1] = '\0';
for (i = 0; i < PSQL_DIGITS; i++) {
psql_code[i] = *p++;
}
psql_code[1] = '\0';
strncpy(psql_code_ret, psql_code, PSQL_DIGITS);
if (!strncmp(psql_code_ret, "R", PSQL_DIGITS)) {
/* Read packet length only if it is of type R */
/* Currently we care only for the last byte.
The packet length will always be small enough
to fit in one byte */
for (i = 0; i < PSQL_PACKET_LENGTH; i++) {
snprintf(dig, 3, "\n%x", *p++);
packet_length = (int)strtol(dig, NULL, 16);
}
if (con->inbuf->get_len() < packet_length + 1) {
nsock_read(nsp, con->niod, ncrack_read_handler, PSQL_TIMEOUT, con);
return -1;
}
/* At this point we will need to know the authentication type.
Possible values are 5 and 0. 5 stands for MD5 and 0 stands for
successful
authentication. If it is 5 we are at the second stage of the process
PSQL_AUTH
while if it is 0 we are at the third stage PSQL_FINI.
This value consists of 4 bytes but only the fourth will have a value
e.g. 00 00 00 05 for MD5 or 00 00 00 00 for successful
authentication. */
for (i = 0; i < PSQL_AUTH_TYPE; i++) {
snprintf(dig, 3, "\n%x", *p++);
authentication_type = (int)strtol(dig, NULL, 16);
}
/* If authentication type is 'MD5 password' (carries Salt) read salt */
if (authentication_type == 5) {
for (i = 0; i < 4; i++){
psql_salt[i] = *p++;
}
psql_salt[4] = '\0';
strncpy(psql_salt_ret, psql_salt, PSQL_SALT);
return 0;
}
else if (authentication_type == 0)
/* Successful authentication */
return 1;
} else if (!strncmp(psql_code_ret, "E", PSQL_DIGITS)) {
/* Error packet. The login attempt has failed.
Perhaps we could do some more validation on the packet.
Currently any kind of packet with E as the first byte will
be interpreted as a Error package. It is only a matter
of concerns if the service is not a Postgres service. */
return 0;
}
/* Malformed packet. Exit safely. */
return -2;
}
void
ncrack_psql(nsock_pool nsp, Connection *con)
{
nsock_iod nsi = con->niod;
Service *serv = con->service;
const char *hostinfo = serv->HostInfo();
char packet_length;
char psql_code[PSQL_DIGITS + 1];
char psql_salt[PSQL_SALT + 1];
memset(psql_code, 0, sizeof(psql_code));
memset(psql_salt, 0, sizeof(psql_salt));
char response_hex[MD5_DIGEST_LENGTH *2 + 3];
switch (con->state)
{
case PSQL_INIT:
con->state = PSQL_AUTH;
delete con->inbuf;
con->inbuf = NULL;
if (con->outbuf)
delete con->outbuf;
con->outbuf = new Buf();
packet_length = strlen(con->user) + 7 +
strlen("\x03user database postgres application_name psql
client_encoding UTF8 ");
con->outbuf->snprintf(packet_length,
"%c%c%c%c%c\x03%c%cuser%c%s%cdatabase%cpostgres%capplication_name%cpsql%cclient_encoding%cUTF8%c%c",
0,0,0,packet_length,0,0,0,0,con->user,0,0,0,0,0,0,0,0);
nsock_write(nsp, nsi, ncrack_write_handler, PSQL_TIMEOUT, con,
(const char *)con->outbuf->get_dataptr(), con->outbuf->get_len());
break;
case PSQL_AUTH:
if (psql_loop_read(nsp, con, psql_code, psql_salt) < 0)
break;
if (!strncmp(psql_code, "E", PSQL_DIGITS))
return ncrack_module_end(nsp, con);
make_response(response_hex, con->user , con->pass, psql_salt);
response_hex[MD5_DIGEST_LENGTH * 2 + 3] = '\0';
con->state = PSQL_FINI;
delete con->inbuf;
con->inbuf = NULL;
if (con->outbuf)
delete con->outbuf;
con->outbuf = new Buf();
packet_length = strlen(response_hex) + 5 + strlen("p");
/* This packet will not count the last null byte in packet length
byte,
that is why we remove one from snprintf. */
con->outbuf->snprintf(packet_length,
"p%c%c%c%c%s%c",0,0,0,packet_length - 1,response_hex,0
);
nsock_write(nsp, nsi, ncrack_write_handler, PSQL_TIMEOUT, con,
(const char *)con->outbuf->get_dataptr(), con->outbuf->get_len());
break;
case PSQL_FINI:
if (psql_loop_read(nsp, con, psql_code, psql_salt) < 0)
break;
else if (psql_loop_read(nsp, con , psql_code, psql_salt) == 1)
con->auth_success = true;
con->state = PSQL_INIT;
delete con->inbuf;
con->inbuf = NULL;
return ncrack_module_end(nsp, con);
}
/* make sure that ncrack_module_end() is always called last or returned
to
* have tail recursion or else stack space overflow might occur */
}
============ Redis ================
#include "ncrack.h"
#include "nsock.h"
#include "NcrackOps.h"
#include "Service.h"
#include "modules.h"
#define REDIS_TIMEOUT 20000
extern void ncrack_read_handler(nsock_pool nsp, nsock_event nse, void
*mydata);
extern void ncrack_write_handler(nsock_pool nsp, nsock_event nse, void
*mydata);
extern void ncrack_module_end(nsock_pool nsp, void *mydata);
static int redis_loop_read(nsock_pool nsp, Connection *con);
enum states { REDIS_INIT, REDIS_FINI };
static int
redis_loop_read(nsock_pool nsp, Connection *con)
{
char *p;
if (con->inbuf == NULL) {
nsock_read(nsp, con->niod, ncrack_read_handler, REDIS_TIMEOUT, con);
return -1;
}
p = (char *)con->inbuf->get_dataptr();
if (!memsearch((const char *)p, "\r\n", con->inbuf->get_len())) {
nsock_read(nsp, con->niod, ncrack_read_handler, REDIS_TIMEOUT, con);
return -1;
}
if (memsearch((const char *)p, "OK", con->inbuf->get_len()))
return 0;
else if (memsearch((const char *)p, "ERR invalid password",
con->inbuf->get_len()))
return -2;
return -1;
}
void
ncrack_redis(nsock_pool nsp, Connection *con)
{
nsock_iod nsi = con->niod;
Service *serv = con->service;
const char *hostinfo = serv->HostInfo();
switch (con->state)
{
case REDIS_INIT:
con->state = REDIS_FINI;
delete con->inbuf;
con->inbuf = NULL;
if (con->outbuf)
delete con->outbuf;
con->outbuf = new Buf();
con->outbuf->snprintf(7 + strlen(con->pass), "AUTH %s\r\n",
con->pass);
nsock_write(nsp, nsi, ncrack_write_handler, REDIS_TIMEOUT, con,
(const char *)con->outbuf->get_dataptr(), con->outbuf->get_len());
break;
case REDIS_FINI:
if (redis_loop_read(nsp, con) == -1)
break;
else if(redis_loop_read(nsp, con) == 0)
con->auth_success = true;
con->state = REDIS_INIT;
delete con->inbuf;
con->inbuf = NULL;
con->force_close = true;
return ncrack_module_end(nsp, con);
}
}
================================
Thanks,
Deirme
_______________________________________________
Sent through the dev mailing list
https://nmap.org/mailman/listinfo/dev
Archived at http://seclists.org/nmap-dev/
_______________________________________________ Sent through the dev mailing list https://nmap.org/mailman/listinfo/dev Archived at http://seclists.org/nmap-dev/
Current thread:
- Ncrack postgres + redis modules Evangel Deirme (Mar 15)
- Re: Ncrack postgres + redis modules Fotis Hantzis (Mar 15)
