|
Packit |
16808d |
|
|
Packit |
16808d |
/*
|
|
Packit |
16808d |
Login-parsing Faux Server
|
|
Packit |
16808d |
The Meanwhile Project
|
|
Packit |
16808d |
|
|
Packit |
16808d |
This is a tool to aide in reverse engineering different types of
|
|
Packit |
16808d |
authentication schemes.
|
|
Packit |
16808d |
|
|
Packit |
16808d |
Christopher O'Brien <siege@preoccupied.net>
|
|
Packit |
16808d |
*/
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
#include <stdio.h>
|
|
Packit |
16808d |
#include <stdlib.h>
|
|
Packit |
16808d |
#include <string.h>
|
|
Packit |
16808d |
#include <sys/socket.h>
|
|
Packit |
16808d |
#include <netdb.h>
|
|
Packit |
16808d |
#include <netinet/in.h>
|
|
Packit |
16808d |
#include <unistd.h>
|
|
Packit |
16808d |
|
|
Packit |
16808d |
#include <glib.h>
|
|
Packit |
16808d |
|
|
Packit |
16808d |
#include <mw_cipher.h>
|
|
Packit |
16808d |
#include <mw_common.h>
|
|
Packit |
16808d |
#include <mw_message.h>
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/** the server socket or the connected socket */
|
|
Packit |
16808d |
static int sock;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/** the io channel */
|
|
Packit |
16808d |
static GIOChannel *chan;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/** the listening event on the io channel */
|
|
Packit |
16808d |
static int chan_io;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static guchar *sbuf;
|
|
Packit |
16808d |
static gsize sbuf_size;
|
|
Packit |
16808d |
static gsize sbuf_recv;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwMpi *private, *public;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static void hexout(const char *txt, const guchar *buf, gsize len) {
|
|
Packit |
16808d |
FILE *fp;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(txt) fprintf(stdout, "\n%s\n", txt);
|
|
Packit |
16808d |
fflush(stdout);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
fp = popen("hexdump -C", "w");
|
|
Packit |
16808d |
fwrite(buf, len, 1, fp);
|
|
Packit |
16808d |
fflush(fp);
|
|
Packit |
16808d |
pclose(fp);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static void send_msg(struct mwMessage *msg) {
|
|
Packit |
16808d |
struct mwPutBuffer *b;
|
|
Packit |
16808d |
struct mwOpaque o = { 0, 0 };
|
|
Packit |
16808d |
|
|
Packit |
16808d |
b = mwPutBuffer_new();
|
|
Packit |
16808d |
mwMessage_put(b, msg);
|
|
Packit |
16808d |
mwPutBuffer_finalize(&o, b);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
b = mwPutBuffer_new();
|
|
Packit |
16808d |
mwOpaque_put(b, &o);
|
|
Packit |
16808d |
mwOpaque_clear(&o);
|
|
Packit |
16808d |
mwPutBuffer_finalize(&o, b);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(sock) write(sock, o.data, o.len);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
hexout("sent:", o.data, o.len);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
mwOpaque_clear(&o);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static void handshake_ack() {
|
|
Packit |
16808d |
struct mwMsgHandshakeAck *msg;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
msg = (struct mwMsgHandshakeAck *)
|
|
Packit |
16808d |
mwMessage_new(mwMessage_HANDSHAKE_ACK);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
msg->major = 0x1e;
|
|
Packit |
16808d |
msg->minor = 0x1d;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
mwMpi_randDHKeypair(private, public);
|
|
Packit |
16808d |
mwMpi_export(public, &msg->data);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
msg->magic = 0x01234567;
|
|
Packit |
16808d |
hexout("sending pubkey:", msg->data.data, msg->data.len);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
send_msg(MW_MESSAGE(msg));
|
|
Packit |
16808d |
mwMessage_free(MW_MESSAGE(msg));
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static void handle_login(struct mwMsgLogin *msg) {
|
|
Packit |
16808d |
struct mwGetBuffer *gb;
|
|
Packit |
16808d |
struct mwOpaque a, b, c;
|
|
Packit |
16808d |
guint16 z;
|
|
Packit |
16808d |
struct mwMpi *remote, *shared;
|
|
Packit |
16808d |
guchar iv[8];
|
|
Packit |
16808d |
|
|
Packit |
16808d |
remote = mwMpi_new();
|
|
Packit |
16808d |
shared = mwMpi_new();
|
|
Packit |
16808d |
|
|
Packit |
16808d |
mwIV_init(iv);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
gb = mwGetBuffer_wrap(&msg->auth_data);
|
|
Packit |
16808d |
guint16_get(gb, &z);
|
|
Packit |
16808d |
mwOpaque_get(gb, &a);
|
|
Packit |
16808d |
mwOpaque_get(gb, &b);
|
|
Packit |
16808d |
mwGetBuffer_free(gb);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
mwMpi_import(remote, &a);
|
|
Packit |
16808d |
mwOpaque_clear(&a);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
mwMpi_calculateDHShared(shared, remote, private);
|
|
Packit |
16808d |
mwMpi_export(shared, &a);
|
|
Packit |
16808d |
hexout("shared key:", a.data, a.len);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
mwDecrypt(a.data+(a.len-16), 16, iv, &b, &c);
|
|
Packit |
16808d |
hexout("decrypted to:", c.data, c.len);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
mwOpaque_clear(&a);
|
|
Packit |
16808d |
mwOpaque_clear(&b);
|
|
Packit |
16808d |
mwOpaque_clear(&c);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
mwMpi_free(remote);
|
|
Packit |
16808d |
mwMpi_free(shared);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static void done() {
|
|
Packit |
16808d |
close(sock);
|
|
Packit |
16808d |
exit(0);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static void side_process(const guchar *buf, gsize len) {
|
|
Packit |
16808d |
struct mwOpaque o = { .len = len, .data = (guchar *) buf };
|
|
Packit |
16808d |
struct mwGetBuffer *b;
|
|
Packit |
16808d |
guint16 type;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(! len) return;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
b = mwGetBuffer_wrap(&o);
|
|
Packit |
16808d |
type = guint16_peek(b);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
hexout("received:", buf, len);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
switch(type) {
|
|
Packit |
16808d |
case mwMessage_HANDSHAKE:
|
|
Packit |
16808d |
printf("got handshake, sending handshake_ack\n");
|
|
Packit |
16808d |
handshake_ack();
|
|
Packit |
16808d |
break;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
case mwMessage_LOGIN:
|
|
Packit |
16808d |
printf("got login, attempting to decipher\n");
|
|
Packit |
16808d |
{
|
|
Packit |
16808d |
struct mwMsgLogin *msg = (struct mwMsgLogin *) mwMessage_get(b);
|
|
Packit |
16808d |
handle_login(msg);
|
|
Packit |
16808d |
mwMessage_free(MW_MESSAGE(msg));
|
|
Packit |
16808d |
done();
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
break;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
case mwMessage_CHANNEL_DESTROY:
|
|
Packit |
16808d |
printf("channel destroy\n");
|
|
Packit |
16808d |
done();
|
|
Packit |
16808d |
break;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
default:
|
|
Packit |
16808d |
;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
mwGetBuffer_free(b);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static void sbuf_free() {
|
|
Packit |
16808d |
g_free(sbuf);
|
|
Packit |
16808d |
sbuf = NULL;
|
|
Packit |
16808d |
sbuf_size = 0;
|
|
Packit |
16808d |
sbuf_recv = 0;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
#define ADVANCE(b, n, count) { b += count; n -= count; }
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/* handle input to complete an existing buffer */
|
|
Packit |
16808d |
static gsize side_recv_cont(const guchar *b, gsize n) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
gsize x = sbuf_size - sbuf_recv;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(n < x) {
|
|
Packit |
16808d |
memcpy(sbuf + sbuf_recv, b, n);
|
|
Packit |
16808d |
sbuf_recv += n;
|
|
Packit |
16808d |
return 0;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
} else {
|
|
Packit |
16808d |
memcpy(sbuf + sbuf_recv, b, x);
|
|
Packit |
16808d |
ADVANCE(b, n, x);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(sbuf_size == 4) {
|
|
Packit |
16808d |
struct mwOpaque o = { .len = 4, .data = sbuf };
|
|
Packit |
16808d |
struct mwGetBuffer *gb = mwGetBuffer_wrap(&o);
|
|
Packit |
16808d |
x = guint32_peek(gb);
|
|
Packit |
16808d |
mwGetBuffer_free(gb);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(n < x) {
|
|
Packit |
16808d |
guchar *t;
|
|
Packit |
16808d |
x += 4;
|
|
Packit |
16808d |
t = (guchar *) g_malloc(x);
|
|
Packit |
16808d |
memcpy(t, sbuf, 4);
|
|
Packit |
16808d |
memcpy(t+4, b, n);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
sbuf_free();
|
|
Packit |
16808d |
|
|
Packit |
16808d |
sbuf = t;
|
|
Packit |
16808d |
sbuf_size = x;
|
|
Packit |
16808d |
sbuf_recv = n + 4;
|
|
Packit |
16808d |
return 0;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
} else {
|
|
Packit |
16808d |
sbuf_free();
|
|
Packit |
16808d |
side_process(b, x);
|
|
Packit |
16808d |
ADVANCE(b, n, x);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
} else {
|
|
Packit |
16808d |
side_process(sbuf+4, sbuf_size-4);
|
|
Packit |
16808d |
sbuf_free();
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
return n;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/* handle input when there's nothing previously buffered */
|
|
Packit |
16808d |
static gsize side_recv_empty(const guchar *b, gsize n) {
|
|
Packit |
16808d |
struct mwOpaque o = { .len = n, .data = (guchar *) b };
|
|
Packit |
16808d |
struct mwGetBuffer *gb;
|
|
Packit |
16808d |
gsize x;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(n < 4) {
|
|
Packit |
16808d |
sbuf = (guchar *) g_malloc0(4);
|
|
Packit |
16808d |
memcpy(sbuf, b, n);
|
|
Packit |
16808d |
sbuf_size = 4;
|
|
Packit |
16808d |
sbuf_recv = n;
|
|
Packit |
16808d |
return 0;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
gb = mwGetBuffer_wrap(&o);
|
|
Packit |
16808d |
x = guint32_peek(gb);
|
|
Packit |
16808d |
mwGetBuffer_free(gb);
|
|
Packit |
16808d |
if(! x) return n - 4;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(n < (x + 4)) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
x += 4;
|
|
Packit |
16808d |
sbuf = (guchar *) g_malloc(x);
|
|
Packit |
16808d |
memcpy(sbuf, b, n);
|
|
Packit |
16808d |
sbuf_size = x;
|
|
Packit |
16808d |
sbuf_recv = n;
|
|
Packit |
16808d |
return 0;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
} else {
|
|
Packit |
16808d |
ADVANCE(b, n, 4);
|
|
Packit |
16808d |
side_process(b, x);
|
|
Packit |
16808d |
ADVANCE(b, n, x);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
return n;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static gsize side_recv(const guchar *b, gsize n) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(n && (sbuf_size == 0) && (*b & 0x80)) {
|
|
Packit |
16808d |
ADVANCE(b, n, 1);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(n == 0) {
|
|
Packit |
16808d |
return 0;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
} else if(sbuf_size > 0) {
|
|
Packit |
16808d |
return side_recv_cont(b, n);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
} else {
|
|
Packit |
16808d |
return side_recv_empty(b, n);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static void feed_buf(const guchar *buf, gsize n) {
|
|
Packit |
16808d |
guchar *b = (guchar *) buf;
|
|
Packit |
16808d |
gsize remain = 0;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
while(n > 0) {
|
|
Packit |
16808d |
remain = side_recv(b, n);
|
|
Packit |
16808d |
b += (n - remain);
|
|
Packit |
16808d |
n = remain;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static int read_recv() {
|
|
Packit |
16808d |
guchar buf[2048];
|
|
Packit |
16808d |
int len;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
len = read(sock, buf, 2048);
|
|
Packit |
16808d |
if(len > 0) feed_buf(buf, (gsize) len);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
return len;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static gboolean read_cb(GIOChannel *chan,
|
|
Packit |
16808d |
GIOCondition cond,
|
|
Packit |
16808d |
gpointer data) {
|
|
Packit |
16808d |
int ret = 0;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(cond & G_IO_IN) {
|
|
Packit |
16808d |
ret = read_recv();
|
|
Packit |
16808d |
if(ret > 0) return TRUE;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(sock) {
|
|
Packit |
16808d |
g_source_remove(chan_io);
|
|
Packit |
16808d |
close(sock);
|
|
Packit |
16808d |
sock = 0;
|
|
Packit |
16808d |
chan = NULL;
|
|
Packit |
16808d |
chan_io = 0;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
done();
|
|
Packit |
16808d |
|
|
Packit |
16808d |
return FALSE;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static gboolean listen_cb(GIOChannel *chan,
|
|
Packit |
16808d |
GIOCondition cond,
|
|
Packit |
16808d |
gpointer data) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct sockaddr_in rem;
|
|
Packit |
16808d |
guint len = sizeof(rem);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
printf("accepting connection\n");
|
|
Packit |
16808d |
|
|
Packit |
16808d |
sock = accept(sock, (struct sockaddr *) &rem, &len;;
|
|
Packit |
16808d |
g_assert(sock > 0);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_source_remove(chan_io);
|
|
Packit |
16808d |
chan = g_io_channel_unix_new(sock);
|
|
Packit |
16808d |
chan_io = g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
|
|
Packit |
16808d |
read_cb, NULL);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
return FALSE;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static void init_socket(int port) {
|
|
Packit |
16808d |
/* start listening on the local port specifier */
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct sockaddr_in sin;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
sock = socket(PF_INET, SOCK_STREAM, 0);
|
|
Packit |
16808d |
g_assert(sock >= 0);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
memset(&sin, 0, sizeof(struct sockaddr_in));
|
|
Packit |
16808d |
sin.sin_family = PF_INET;
|
|
Packit |
16808d |
sin.sin_port = htons(port);
|
|
Packit |
16808d |
sin.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
|
|
Packit |
16808d |
g_assert_not_reached();
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(listen(sock, 1) < 0)
|
|
Packit |
16808d |
g_assert_not_reached();
|
|
Packit |
16808d |
|
|
Packit |
16808d |
chan = g_io_channel_unix_new(sock);
|
|
Packit |
16808d |
chan_io = g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
|
|
Packit |
16808d |
listen_cb, NULL);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
int main(int argc, char *argv[]) {
|
|
Packit |
16808d |
int port = 0;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
private = mwMpi_new();
|
|
Packit |
16808d |
public = mwMpi_new();
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(argc > 1) {
|
|
Packit |
16808d |
port = atoi(argv[1]);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(!port) {
|
|
Packit |
16808d |
fprintf(stderr,
|
|
Packit |
16808d |
( " Usage: %s local_port\n"
|
|
Packit |
16808d |
" Creates a locally-running sametime server which prints"
|
|
Packit |
16808d |
" login information to stdout\n" ),
|
|
Packit |
16808d |
argv[0]);
|
|
Packit |
16808d |
exit(1);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/* @todo create signal handlers to cleanup socket */
|
|
Packit |
16808d |
|
|
Packit |
16808d |
init_socket(port);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_main_loop_run(g_main_loop_new(NULL, FALSE));
|
|
Packit |
16808d |
return 0;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|