From f93b799384bd91e3f6d35cb84aec3482aabf423d Mon Sep 17 00:00:00 2001 From: Tuan Date: Tue, 23 Apr 2019 18:32:22 +0700 Subject: [PATCH] replace rdesktop with freerdp for rdp module --- configure | 93 +- hydra-rdp.c | 3174 +-------------------------------------------------- hydra.c | 40 +- 3 files changed, 156 insertions(+), 3151 deletions(-) diff --git a/configure b/configure index 0945974..d09ac9d 100755 --- a/configure +++ b/configure @@ -69,6 +69,8 @@ NSL_PATH="" SOCKET_PATH="" MANDIR="" XHYDRA_SUPPORT="" +FREERDP2_PATH="" +WINPR2_PATH="" if [ '!' "X" = "X$*" ]; then while [ $# -gt 0 ] ; do @@ -997,6 +999,78 @@ fi fi +echo "Checking for Freerdp2 (libfreerdp2.so, freerdp/*.h, libwinpr2.so, winpr/*.h) ..." + + for i in $LIBDIRS ; do + if [ "X" = "X$FREERDP2_PATH" ]; then + if [ -f "$i/libfreerdp2.so" -o -f "$i/libfreerdp2.dylib" -o -f "$i/libfreerdp2.a" ]; then + FREERDP2_PATH="$i" + fi + fi + if [ "X" = "X$FREERDP2_PATH" ]; then + TMP_LIB=`/bin/ls $i/libfreerdp2*.so* 2> /dev/null | grep libfreerdp2` + if [ -n "$TMP_LIB" ]; then + FREERDP2_PATH="$i" + fi + fi + done + + FREERDP2_IPATH= + for i in $INCDIRS ; do + if [ "X" = "X$FREERDP2_IPATH" ]; then + if [ -f "$i/freerdp/freerdp.h" ]; then + FREERDP2_IPATH="$i/freerdp2" + fi + if [ -f "$i/freerdp2/freerdp/freerdp.h" ]; then + FREERDP2_IPATH="$i/freerdp2" + fi + fi + done + + for i in $LIBDIRS ; do + if [ "X" = "X$WINPR2_PATH" ]; then + if [ -f "$i/libwinpr2.so" -o -f "$i/libwinpr2.dylib" -o -f "$i/libwinpr2.a" ]; then + WINPR2_PATH="$i" + fi + fi + if [ "X" = "X$WINPR2_PATH" ]; then + TMP_LIB=`/bin/ls $i/winpr.dll* 2> /dev/null | grep winpr` + if [ -n "$TMP_LIB" ]; then + WINPR2_PATH="$i" + fi + fi + done + + WINPR2_IPATH= + for i in $INCDIRS ; do + if [ "X" = "X$WINPR2_IPATH" ]; then + if [ -f "$i/winpr.h" ]; then + WINPR2_IPATH="$i" + fi + if [ -f "$i/winpr2/winpr/winpr.h" ]; then + WINPR2_IPATH="$i/winpr2" + fi + fi + done + +if [ "X" != "X$DEBUG" ]; then + echo DEBUG: FREERDP2_PATH=$FREERDP2_PATH/ + echo DEBUG: FREERDP2_IPATH=$FREERDP2_IPATH/ + echo DEBUG: WINPR2_PATH=$WINPR2_PATH/ + echo DEBUG: WINPR2_IPATH=$WINPR2_IPATH/ +fi + + if [ -n "$FREERDP2_PATH" -a -n "$FREERDP2_IPATH" -a -n "$WINPR2_PATH" -a -n "$WINPR2_IPATH" ]; then + echo " ... found" + fi + if [ "X" = "X$FREERDP2_PATH" -o "X" = "X$FREERDP2_IPATH" -o "X" = "X$WINPR2_PATH" -o "X" = "X$WINPR2_IPATH" ]; then + echo " ... NOT found, module rdp disabled" + FREERDP2_PATH="" + FREERDP2_IPATH="" + WINPR2_PATH="" + WINPR2_IPATH="" + fi + echo "Checking for Mongodb (libmongoc-1.0.so, mongoc.h, libbson-1.0.so, bson.h) ..." for i in $LIBDIRS ; do @@ -1180,7 +1254,7 @@ XLIBS="" XLIBPATHS="" XIPATHS="" -if [ -n "$FIREBIRD_PATH" -o -n "$PCRE_PATH" -o -n "$IDN_PATH" -o -n "$SSL_PATH" -o -n "$CRYPTO_PATH" -o -n "$NSL_PATH" -o -n "$SOCKET_PATH" -o -n "$RESOLV_PATH" -o -n "$SAPR3_PATH" -o -n "$SSH_PATH" -o -n "$POSTGRES_PATH" -o -n "$SVN_PATH" -o -n "$NCP_PATH" -o -n "$CURSES_PATH" -o -n "$ORACLE_PATH" -o -n "$AFP_PATH" -o -n "$MYSQL_PATH" -o -n "$MCACHED_PATH" -o -n "$MONGOD_PATH" ]; then +if [ -n "$FIREBIRD_PATH" -o -n "$PCRE_PATH" -o -n "$IDN_PATH" -o -n "$SSL_PATH" -o -n "$CRYPTO_PATH" -o -n "$NSL_PATH" -o -n "$SOCKET_PATH" -o -n "$RESOLV_PATH" -o -n "$SAPR3_PATH" -o -n "$SSH_PATH" -o -n "$POSTGRES_PATH" -o -n "$SVN_PATH" -o -n "$NCP_PATH" -o -n "$CURSES_PATH" -o -n "$ORACLE_PATH" -o -n "$AFP_PATH" -o -n "$MYSQL_PATH" -o -n "$MCACHED_PATH" -o -n "$MONGOD_PATH" -o -n "$FREERDP2_PATH" -o -n "$WINPR2_PATH" ]; then XLIBPATHS="-L/usr/lib -L/usr/local/lib -L/lib" fi if [ -n "$MYSQL_IPATH" ]; then @@ -1253,9 +1327,15 @@ fi if [ -n "$BSON_PATH" ]; then XDEFINES="$XDEFINES -DLIBBSON" fi +if [ -n "$FREERDP2_PATH" ]; then + XDEFINES="$XDEFINES -DLIBFREERDP2" +fi +if [ -n "$WINPR2_PATH" ]; then + XDEFINES="$XDEFINES -DLIBWINPR2" +fi OLDPATH="" -for i in $SSL_PATH $FIREBIRD_PATH $WORACLE_LIB_PATH $PCRE_PATH $IDN_PATH $CRYPTO_PATH $SSH_PATH $NSL_PATH $SOCKET_PATH $RESOLV_PATH $SAPR3_PATH $POSTGRES_PATH $SVN_PATH $NCP_PATH $CURSES_PATH $ORACLE_PATH $AFP_PATH $MYSQL_PATH $MCACHED_PATH $MONGODB_PATH $BSON_PATH; do +for i in $SSL_PATH $FIREBIRD_PATH $WORACLE_LIB_PATH $PCRE_PATH $IDN_PATH $CRYPTO_PATH $SSH_PATH $NSL_PATH $SOCKET_PATH $RESOLV_PATH $SAPR3_PATH $POSTGRES_PATH $SVN_PATH $NCP_PATH $CURSES_PATH $ORACLE_PATH $AFP_PATH $MYSQL_PATH $MCACHED_PATH $MONGODB_PATH $BSON_PATH $FREERDP2_PATH $WINPR2_PATH; do if [ "$OLDPATH" = "$i" ]; then OLDPATH="$i" else @@ -1314,6 +1394,9 @@ fi if [ -n "$MONGODB_IPATH" ]; then XIPATHS="$XIPATHS -I$MONGODB_IPATH -I$BSON_IPATH" fi +if [ -n "$FREERDP2_IPATH" ]; then + XIPATHS="$XIPATHS -I$FREERDP2_IPATH -I$WINPR2_IPATH" +fi if [ -n "$HAVE_GCRYPT" ]; then XLIBS="$XLIBS -lgcrypt" fi @@ -1386,6 +1469,12 @@ fi if [ -n "$BSON_PATH" ]; then XLIBS="$XLIBS -lbson-1.0" fi +if [ -n "$FREERDP2_PATH" ]; then + XLIBS="$XLIBS -lfreerdp2" +fi +if [ -n "$WINPR2_PATH" ]; then + XLIBS="$XLIBS -lwinpr2" +fi if [ -d /usr/kerberos/include ]; then XIPATHS="$XIPATHS -I/usr/kerberos/include" fi diff --git a/hydra-rdp.c b/hydra-rdp.c index 8b9394c..cfa2e12 100644 --- a/hydra-rdp.c +++ b/hydra-rdp.c @@ -36,2421 +36,36 @@ It's particularly true on windows XP #include "hydra-mod.h" -#ifndef LIBOPENSSL -#include +extern char *HYDRA_EXIT; +#ifndef LIBFREERDP2 void dummy_rdp() { printf("\n"); } #else -#include "rdp.h" -extern char *HYDRA_EXIT; - -BOOL g_encryption = True; -BOOL g_use_rdp5 = True; -BOOL g_console_session = False; -BOOL g_bitmap_cache = True; -BOOL g_bitmap_cache_persist_enable = False; -BOOL g_bitmap_compression = True; -BOOL g_desktop_save = True; -int32_t g_server_depth = -1; -int32_t os_version = 0; //2000 - -uint32 g_rdp5_performanceflags = RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS; - -/* Session Directory redirection */ -BOOL g_redirect = False; -uint32 g_redirect_flags = 0; - -uint32 g_reconnect_logonid = 0; -char g_reconnect_random[16]; -BOOL g_has_reconnect_random = False; -uint8 g_client_random[SEC_RANDOM_SIZE]; - -/* - 0 unknown - 1 success - 2 failed -*/ -#define LOGIN_UNKN 0 -#define LOGIN_SUCC 1 -#define LOGIN_FAIL 2 -int32_t login_result = LOGIN_UNKN; - -uint8 *g_next_packet; -uint32 g_rdp_shareid; - -/* Called during redirection to reset the state to support redirection */ -void rdp_reset_state(void) { - g_next_packet = NULL; /* reset the packet information */ - g_rdp_shareid = 0; - sec_reset_state(); -} - -static void rdesktop_reset_state(void) { - rdp_reset_state(); -} - -static RDP_ORDER_STATE g_order_state; - -#define TCP_STRERROR strerror(errno) -#define TCP_BLOCKS (errno == EWOULDBLOCK) - - -#ifndef INADDR_NONE -#define INADDR_NONE ((unsigned long) -1) -#endif - -#define STREAM_COUNT 1 - - -int32_t g_sock; -static struct stream g_in; -static struct stream g_out[STREAM_COUNT]; - -/* wait till socket is ready to write or timeout */ -static BOOL tcp_can_send(int32_t sck, int32_t millis) { - fd_set wfds; - struct timeval time; - int32_t sel_count; - - time.tv_sec = millis / 1000; - time.tv_usec = (millis * 1000) % 1000000; - FD_ZERO(&wfds); - FD_SET(sck, &wfds); - sel_count = select(sck + 1, 0, &wfds, 0, &time); - if (sel_count > 0) { - return True; - } - return False; -} - -/* Initialise TCP transport data packet */ -STREAM tcp_init(uint32 maxlen) { - static int32_t cur_stream_id = 0; - STREAM result = NULL; - - result = &g_out[cur_stream_id]; - cur_stream_id = (cur_stream_id + 1) % STREAM_COUNT; - - - if (maxlen > result->size) { - result->data = (uint8 *) xrealloc(result->data, maxlen); - result->size = maxlen; - } - - result->p = result->data; - result->end = result->data; // + result->size; - return result; -} - -/* Send TCP transport data packet */ -void tcp_send(STREAM s) { - int32_t length = s->end - s->data; - int32_t sent, total = 0; - - - while (total < length) { - sent = hydra_send(g_sock, (char *) (s->data + total), length - total, 0); - if (sent <= 0) { - if (sent == -1 && TCP_BLOCKS) { - tcp_can_send(g_sock, 100); - sent = 0; - } else { - if (g_sock && !login_result) - error("send: %s\n", TCP_STRERROR); - return; - } - } - total += sent; - } -} - -/* Receive a message on the TCP layer */ -STREAM tcp_recv(STREAM s, uint32 length) { - uint32 new_length, end_offset, p_offset; - int32_t rcvd = 0; - - if (s == NULL) { - /* read into "new" stream */ - g_in.data = (uint8 *) xmalloc(length); - g_in.size = length; - g_in.end = g_in.p = g_in.data; - s = &g_in; - } else { - /* append to existing stream */ - new_length = (s->end - s->data) + length; - if (new_length > s->size) { - p_offset = s->p - s->data; - end_offset = s->end - s->data; -//printf("length: %d, %p s->data, %p +%d s->p, %p +%d s->end, end-data %d, size %d\n", length, s->data, s->p, s->p - s->data, s->end, s->end - s->p, s->end - s->data, s->size); - s->data = (uint8 *) xrealloc(s->data, new_length); - s->size = new_length; - s->p = s->data + p_offset; - s->end = s->data + end_offset; - } - } - - - while (length > 0) { - rcvd = hydra_recv(g_sock, (char *) s->end, length); - if (rcvd < 0) { - if (rcvd == -1 && TCP_BLOCKS) { - rcvd = 0; - } else { - //error("recv: %s\n", TCP_STRERROR); - return NULL; - } - } else if (rcvd == 0) { - error("Connection closed\n"); - return NULL; - } - s->end += rcvd; - length -= rcvd; - } - - - return s; -} - -char *tcp_get_address() { - static char ipaddr[32]; - struct sockaddr_in sockaddr; - socklen_t len = sizeof(sockaddr); - - if (getsockname(g_sock, (struct sockaddr *) &sockaddr, &len) == 0) { - uint8 *ip = (uint8 *) & sockaddr.sin_addr; - - sprintf(ipaddr, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); - } else - strcpy(ipaddr, "127.0.0.1"); - return ipaddr; -} - -/* reset the state of the tcp layer */ -void tcp_reset_state(void) { - int32_t i; - - g_sock = -1; /* reset socket */ - - /* Clear the incoming stream */ - if (g_in.data != NULL) - free(g_in.data); - g_in.p = NULL; - g_in.end = NULL; - g_in.data = NULL; - g_in.size = 0; - g_in.iso_hdr = NULL; - g_in.mcs_hdr = NULL; - g_in.sec_hdr = NULL; - g_in.rdp_hdr = NULL; - g_in.channel_hdr = NULL; - - /* Clear the outgoing stream(s) */ - for (i = 0; i < STREAM_COUNT; i++) { - if (g_out[i].data != NULL) - free(g_out[i].data); - g_out[i].p = NULL; - g_out[i].end = NULL; - g_out[i].data = NULL; - g_out[i].size = 0; - g_out[i].iso_hdr = NULL; - g_out[i].mcs_hdr = NULL; - g_out[i].sec_hdr = NULL; - g_out[i].rdp_hdr = NULL; - g_out[i].channel_hdr = NULL; - } -} - -uint16 g_mcs_userid; - -/* Parse an ASN.1 BER header */ -static BOOL ber_parse_header(STREAM s, int32_t tagval, int32_t *length) { - int32_t tag, len; - - - if (tagval > 0xff) { - in_uint16_be(s, tag); - } else { - in_uint8(s, tag); - } - - if (tag != tagval) { - error("expected tag %d, got %d\n", tagval, tag); - return False; - } - - in_uint8(s, len); - - if (len & 0x80) { - len &= ~0x80; - *length = 0; - while (len--) - next_be(s, *length); - } else - *length = len; - - return s_check(s); -} - -/* Output an ASN.1 BER header */ -static void ber_out_header(STREAM s, int32_t tagval, int32_t length) { - - - if (tagval > 0xff) { - out_uint16_be(s, tagval); - } else { - out_uint8(s, tagval); - } - - if (length >= 0x80) { - out_uint8(s, 0x82); - out_uint16_be(s, length); - } else - out_uint8(s, length); -} - -/* Output an ASN.1 BER integer */ -static void ber_out_integer(STREAM s, int32_t value) { - ber_out_header(s, BER_TAG_INTEGER, 2); - out_uint16_be(s, value); -} - -/* Output a DOMAIN_PARAMS structure (ASN.1 BER) */ -static void mcs_out_domain_params(STREAM s, int32_t max_channels, int32_t max_users, int32_t max_tokens, int32_t max_pdusize) { - ber_out_header(s, MCS_TAG_DOMAIN_PARAMS, 32); - ber_out_integer(s, max_channels); - ber_out_integer(s, max_users); - ber_out_integer(s, max_tokens); - ber_out_integer(s, 1); /* num_priorities */ - ber_out_integer(s, 0); /* min_throughput */ - ber_out_integer(s, 1); /* max_height */ - ber_out_integer(s, max_pdusize); - ber_out_integer(s, 2); /* ver_protocol */ -} - -/* Parse a DOMAIN_PARAMS structure (ASN.1 BER) */ -static BOOL mcs_parse_domain_params(STREAM s) { - int32_t length = 0; - - ber_parse_header(s, MCS_TAG_DOMAIN_PARAMS, &length); - in_uint8s(s, length); - - return s_check(s); -} - -/* Send an MCS_CONNECT_INITIAL message (ASN.1 BER) */ -static void mcs_send_connect_initial(STREAM mcs_data) { - int32_t datalen = mcs_data->end - mcs_data->data; - int32_t length = 9 + 3 * 34 + 4 + datalen; - STREAM s; - - s = iso_init(length + 5); - - ber_out_header(s, MCS_CONNECT_INITIAL, length); - ber_out_header(s, BER_TAG_OCTET_STRING, 1); /* calling domain */ - out_uint8(s, 1); - ber_out_header(s, BER_TAG_OCTET_STRING, 1); /* called domain */ - out_uint8(s, 1); - - ber_out_header(s, BER_TAG_BOOLEAN, 1); - out_uint8(s, 0xff); /* upward flag */ - - mcs_out_domain_params(s, 34, 2, 0, 0xffff); /* target params */ - mcs_out_domain_params(s, 1, 1, 1, 0x420); /* min params */ - mcs_out_domain_params(s, 0xffff, 0xfc17, 0xffff, 0xffff); /* max params */ - - ber_out_header(s, BER_TAG_OCTET_STRING, datalen); - out_uint8p(s, mcs_data->data, datalen); - - s_mark_end(s); - iso_send(s); -} - -/* Expect a MCS_CONNECT_RESPONSE message (ASN.1 BER) */ -static BOOL mcs_recv_connect_response(STREAM mcs_data) { - uint8 result; - int32_t length = 0; - STREAM s; - - s = iso_recv(NULL); - if (s == NULL) - return False; - - ber_parse_header(s, MCS_CONNECT_RESPONSE, &length); - - ber_parse_header(s, BER_TAG_RESULT, &length); - in_uint8(s, result); - if (result != 0) { - error("MCS connect: %d\n", result); - return False; - } - - ber_parse_header(s, BER_TAG_INTEGER, &length); - in_uint8s(s, length); /* connect id */ - mcs_parse_domain_params(s); - - ber_parse_header(s, BER_TAG_OCTET_STRING, &length); - - sec_process_mcs_data(s); - /* - if (length > mcs_data->size) - { - error("MCS data length %d, expected %d\n", length, - mcs_data->size); - length = mcs_data->size; - } - - in_uint8a(s, mcs_data->data, length); - mcs_data->p = mcs_data->data; - mcs_data->end = mcs_data->data + length; - */ - return s_check_end(s); -} - -/* Send an EDrq message (ASN.1 PER) */ -static void mcs_send_edrq(void) { - STREAM s; - - s = iso_init(5); - - out_uint8(s, (MCS_EDRQ << 2)); - out_uint16_be(s, 1); /* height */ - out_uint16_be(s, 1); /* interval */ - - s_mark_end(s); - iso_send(s); -} - -/* Send an AUrq message (ASN.1 PER) */ -static void mcs_send_aurq(void) { - STREAM s; - - s = iso_init(1); - - out_uint8(s, (MCS_AURQ << 2)); - - s_mark_end(s); - iso_send(s); -} - -/* Expect a AUcf message (ASN.1 PER) */ -static BOOL mcs_recv_aucf(uint16 * mcs_userid) { - uint8 opcode, result; - STREAM s; - - s = iso_recv(NULL); - if (s == NULL) - return False; - - in_uint8(s, opcode); - if ((opcode >> 2) != MCS_AUCF) { - error("expected AUcf, got %d\n", opcode); - return False; - } - - in_uint8(s, result); - if (result != 0) { - error("AUrq: %d\n", result); - return False; - } - - if (opcode & 2) - in_uint16_be(s, *mcs_userid); - - return s_check_end(s); -} - -/* Send a CJrq message (ASN.1 PER) */ -static void mcs_send_cjrq(uint16 chanid) { - STREAM s; - - DEBUG_RDP5(("Sending CJRQ for channel #%d\n", chanid)); - - s = iso_init(5); - - out_uint8(s, (MCS_CJRQ << 2)); - out_uint16_be(s, g_mcs_userid); - out_uint16_be(s, chanid); - - s_mark_end(s); - iso_send(s); -} - -/* Expect a CJcf message (ASN.1 PER) */ -static BOOL mcs_recv_cjcf(void) { - uint8 opcode, result; - STREAM s; - - s = iso_recv(NULL); - if (s == NULL) - return False; - - in_uint8(s, opcode); - if ((opcode >> 2) != MCS_CJCF) { - error("expected CJcf, got %d\n", opcode); - return False; - } - - in_uint8(s, result); - if (result != 0) { - error("CJrq: %d\n", result); - return False; - } - - in_uint8s(s, 4); /* mcs_userid, req_chanid */ - if (opcode & 2) - in_uint8s(s, 2); /* join_chanid */ - - return s_check_end(s); -} - -/* Initialise an MCS transport data packet */ -STREAM mcs_init(int32_t length) { - STREAM s; - - s = iso_init(length + 8); - s_push_layer(s, mcs_hdr, 8); - - return s; -} - -/* Send an MCS transport data packet to a specific channel */ -void mcs_send_to_channel(STREAM s, uint16 channel) { - uint16 length; - - s_pop_layer(s, mcs_hdr); - length = s->end - s->p - 8; - length |= 0x8000; - - out_uint8(s, (MCS_SDRQ << 2)); - out_uint16_be(s, g_mcs_userid); - out_uint16_be(s, channel); - out_uint8(s, 0x70); /* flags */ - out_uint16_be(s, length); - - iso_send(s); -} - -/* Send an MCS transport data packet to the global channel */ -void mcs_send(STREAM s) { - mcs_send_to_channel(s, MCS_GLOBAL_CHANNEL); -} - -/* Receive an MCS transport data packet */ -STREAM mcs_recv(uint16 * channel, uint8 * rdpver) { - uint8 opcode, appid, length; - STREAM s; - - s = iso_recv(rdpver); - if (s == NULL) - return NULL; - if (rdpver != NULL) - if (*rdpver != 3) - return s; - in_uint8(s, opcode); - appid = opcode >> 2; - if (appid != MCS_SDIN) { - if (appid != MCS_DPUM) { - error("expected data, got %d\n", opcode); - } - return NULL; - } - in_uint8s(s, 2); /* userid */ - in_uint16_be(s, *channel); - in_uint8s(s, 1); /* flags */ - in_uint8(s, length); - if (length & 0x80) - in_uint8s(s, 1); /* second byte of length */ - return s; -} - -BOOL mcs_connect(char *server, STREAM mcs_data, char *username, BOOL reconnect) { - if (!iso_connect(server, username, reconnect)) - return False; - mcs_send_connect_initial(mcs_data); - if (!mcs_recv_connect_response(mcs_data)) - goto error; - mcs_send_edrq(); - mcs_send_aurq(); - if (!mcs_recv_aucf(&g_mcs_userid)) - goto error; - mcs_send_cjrq(g_mcs_userid + MCS_USERCHANNEL_BASE); - if (!mcs_recv_cjcf()) - goto error; - mcs_send_cjrq(MCS_GLOBAL_CHANNEL); - if (!mcs_recv_cjcf()) - goto error; - return True; -error: - iso_disconnect(); - return False; -} - -/* Disconnect from the MCS layer */ -void mcs_disconnect(void) { - iso_disconnect(); -} - -/* reset the state of the mcs layer */ -void mcs_reset_state(void) { - g_mcs_userid = 0; - iso_reset_state(); -} - -/* Send a self-contained ISO PDU */ -static void iso_send_msg(uint8 code) { - STREAM s; - - s = tcp_init(11); - - out_uint8(s, 3); /* version */ - out_uint8(s, 0); /* reserved */ - out_uint16_be(s, 11); /* length */ - - out_uint8(s, 6); /* hdrlen */ - out_uint8(s, code); - out_uint16(s, 0); /* dst_ref */ - out_uint16(s, 0); /* src_ref */ - out_uint8(s, 0); /* class */ - - s_mark_end(s); - tcp_send(s); -} - -static void iso_send_connection_request(char *username) { - STREAM s; - int32_t length = 30 + strlen(username); - - s = tcp_init(length); - - out_uint8(s, 3); /* version */ - out_uint8(s, 0); /* reserved */ - out_uint16_be(s, length); /* length */ - - out_uint8(s, length - 5); /* hdrlen */ - out_uint8(s, ISO_PDU_CR); - out_uint16(s, 0); /* dst_ref */ - out_uint16(s, 0); /* src_ref */ - out_uint8(s, 0); /* class */ - - out_uint8p(s, "Cookie: mstshash=", strlen("Cookie: mstshash=")); - out_uint8p(s, username, strlen(username)); - - out_uint8(s, 0x0d); /* Unknown */ - out_uint8(s, 0x0a); /* Unknown */ - - s_mark_end(s); - tcp_send(s); -} - -/* Send a single input event fast JL, this is required for win8 */ -void rdp_send_fast_input_kbd(uint32 time, uint16 flags, uint16 param1) { - STREAM s; - uint8 fast_flags = 0; - uint8 len = 4; - - fast_flags |= (flags & RDP_KEYRELEASE) ? FASTPATH_INPUT_KBDFLAGS_RELEASE : 0; - s = tcp_init(len); - out_uint8(s, (1 << 2)); //one event - out_uint8(s, len); - out_uint8(s, fast_flags | (FASTPATH_INPUT_EVENT_SCANCODE << 5)); - out_uint8(s, param1); - s_mark_end(s); - tcp_send(s); -} - -/* Send a single input event fast JL, this is required for win8 */ -void rdp_send_fast_input_mouse(uint32 time, uint16 flags, uint16 param1, uint16 param2) { - STREAM s; - uint8 len = 9; - - s = tcp_init(len); - out_uint8(s, (1 << 2)); //one event - out_uint8(s, len); - out_uint8(s, (FASTPATH_INPUT_EVENT_MOUSE << 5)); - out_uint16(s, flags); - out_uint16(s, param1); - out_uint16(s, param2); - s_mark_end(s); - tcp_send(s); -} - - -/* Receive a message on the ISO layer, return code */ -static STREAM iso_recv_msg(uint8 * code, uint8 * rdpver) { - STREAM s; - uint16 length; - uint8 version; - - s = tcp_recv(NULL, 4); - if (s == NULL) - return NULL; - in_uint8(s, version); - if (rdpver != NULL) - *rdpver = version; - if (version == 3) { - in_uint8s(s, 1); /* pad */ - in_uint16_be(s, length); - } else { - in_uint8(s, length); - if (length & 0x80) { - length &= ~0x80; - next_be(s, length); - } - } - if (length < 5) { - error("Bad packet header\n"); - return NULL; - } - s = tcp_recv(s, length - 4); - if (s == NULL) - return NULL; - if (version != 3) - return s; - in_uint8s(s, 1); /* hdrlen */ - in_uint8(s, *code); - if (*code == ISO_PDU_DT) { - in_uint8s(s, 1); /* eot */ - return s; - } - in_uint8s(s, 5); /* dst_ref, src_ref, class */ - return s; -} - -/* Initialise ISO transport data packet */ -STREAM iso_init(int32_t length) { - STREAM s; - - s = tcp_init(length + 7); - s_push_layer(s, iso_hdr, 7); - - return s; -} - -/* Send an ISO data PDU */ -void iso_send(STREAM s) { - uint16 length; - - s_pop_layer(s, iso_hdr); - length = s->end - s->p; - - out_uint8(s, 3); /* version */ - out_uint8(s, 0); /* reserved */ - out_uint16_be(s, length); - - out_uint8(s, 2); /* hdrlen */ - out_uint8(s, ISO_PDU_DT); /* code */ - out_uint8(s, 0x80); /* eot */ - - tcp_send(s); -} - -/* Receive ISO transport data packet */ -STREAM iso_recv(uint8 * rdpver) { - STREAM s; - uint8 code = 0; - - s = iso_recv_msg(&code, rdpver); - if (s == NULL) - return NULL; - if (rdpver != NULL) - if (*rdpver != 3) - return s; - if (code != ISO_PDU_DT) { - error("expected DT, got 0x%x\n", code); - return NULL; - } - return s; -} - -/* Establish a connection up to the ISO layer */ -BOOL iso_connect(char *server, char *username, BOOL reconnect) { - uint8 code = 0; - - if (reconnect) { - iso_send_msg(ISO_PDU_CR); - } else { - iso_send_connection_request(username); - } - if (iso_recv_msg(&code, NULL) == NULL) { - return False; - } - if (code != ISO_PDU_CC) { - error("expected CC, got 0x%x\n", code); - hydra_disconnect(g_sock); - return False; - } - - return True; -} - -/* Disconnect from the ISO layer */ -void iso_disconnect(void) { - iso_send_msg(ISO_PDU_DR); - g_sock = hydra_disconnect(g_sock); -} - -/* reset the state to support reconnecting */ -void iso_reset_state(void) { - tcp_reset_state(); -} - -static int32_t g_rc4_key_len; -static SSL_RC4 g_rc4_decrypt_key; -static SSL_RC4 g_rc4_encrypt_key; -static uint32 g_server_public_key_len; - -static uint8 g_sec_sign_key[16]; -static uint8 g_sec_decrypt_key[16]; -static uint8 g_sec_encrypt_key[16]; -static uint8 g_sec_decrypt_update_key[16]; -static uint8 g_sec_encrypt_update_key[16]; -static uint8 g_sec_crypted_random[SEC_MAX_MODULUS_SIZE]; - -uint16 g_server_rdp_version = 0; - -/* These values must be available to reset state - Session Directory */ -static int32_t g_sec_encrypt_use_count = 0; -static int32_t g_sec_decrypt_use_count = 0; - - -void ssl_sha1_init(SSL_SHA1 * sha1) { - SHA1_Init(sha1); -} - -void ssl_sha1_update(SSL_SHA1 * sha1, uint8 * data, uint32 len) { - SHA1_Update(sha1, data, len); -} - -void ssl_sha1_final(SSL_SHA1 * sha1, uint8 * out_data) { - SHA1_Final(out_data, sha1); -} - -void ssl_md5_init(SSL_MD5 * md5) { - MD5_Init(md5); -} - -void ssl_md5_update(SSL_MD5 * md5, uint8 * data, uint32 len) { - MD5_Update(md5, data, len); -} - -void ssl_md5_final(SSL_MD5 * md5, uint8 * out_data) { - MD5_Final(out_data, md5); -} - -void ssl_rc4_set_key(SSL_RC4 * rc4, uint8 * key, uint32 len) { - RC4_set_key(rc4, len, key); -} - -void ssl_rc4_crypt(SSL_RC4 * rc4, uint8 * in_data, uint8 * out_data, uint32 len) { - RC4(rc4, len, in_data, out_data); -} - -static void reverse(uint8 * p, int32_t len) { - int32_t i, j; - uint8 temp; - - for (i = 0, j = len - 1; i < j; i++, j--) { - temp = p[i]; - p[i] = p[j]; - p[j] = temp; - } -} - -void ssl_rsa_encrypt(uint8 * out, uint8 * in, int32_t len, uint32 modulus_size, uint8 * modulus, uint8 * exponent) { - BN_CTX *ctx; - BIGNUM *mod, *exp, *x, *y; - uint8 inr[SEC_MAX_MODULUS_SIZE]; - int32_t outlen; - - reverse(modulus, modulus_size); - reverse(exponent, SEC_EXPONENT_SIZE); - memcpy(inr, in, len); - reverse(inr, len); - - ctx = BN_CTX_new(); - mod = BN_new(); - exp = BN_new(); - x = BN_new(); - y = BN_new(); - - BN_bin2bn(modulus, modulus_size, mod); - BN_bin2bn(exponent, SEC_EXPONENT_SIZE, exp); - BN_bin2bn(inr, len, x); - BN_mod_exp(y, x, exp, mod, ctx); - outlen = BN_bn2bin(y, out); - reverse(out, outlen); - if (outlen < (int32_t) modulus_size) - memset(out + outlen, 0, modulus_size - outlen); - - BN_free(y); - BN_free(x); - BN_free(exp); - BN_free(mod); - BN_CTX_free(ctx); -} - -/* returns newly allocated X509 or NULL */ -X509 *ssl_cert_read(uint8 * data, uint32 len) { - /* this will move the data pointer but we don't care, we don't use it again */ - return d2i_X509(NULL, (D2I_X509_CONST unsigned char **) &data, len); -} - -static void ssl_cert_free(X509 * cert) { - X509_free(cert); -} - -/* returns newly allocated SSL_RKEY or NULL */ -SSL_RKEY *ssl_cert_to_rkey(X509 * cert, uint32 * key_len) { - EVP_PKEY *epk = NULL; - SSL_RKEY *lkey; - int32_t nid; - - /* By some reason, Microsoft sets the OID of the Public RSA key to - the oid for "MD5 with RSA Encryption" instead of "RSA Encryption" - - Kudos to Richard Levitte for the following (. intuitive .) - lines of code that resets the OID and let's us extract the key. */ -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) - nid = X509_get_signature_nid(cert); -#else - nid = OBJ_obj2nid(cert->cert_info->key->algor->algorithm); -#endif - if ((nid == NID_md5WithRSAEncryption) || (nid == NID_shaWithRSAEncryption)) { -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) -// fprintf(stderr, "[ERROR] the current experimental openssl-1.1 support in hydra does not support RDP :( \n"); -// hydra_child_exit(2); - X509_ALGOR *algor = X509_get0_tbs_sigalg(cert); - DEBUG_RDP5(("Re-setting algorithm type to RSA in server certificate\n")); - ASN1_OBJECT_free(algor->algorithm); - algor->algorithm = OBJ_nid2obj(NID_rsaEncryption); - //X509_ALGOR_set0(algor, OBJ_nid2obj(NID_rsaEncryption), V_ASN1_SEQUENCE, NULL /*pbe_str*/); -#else - DEBUG_RDP5(("Re-setting algorithm type to RSA in server certificate\n")); - ASN1_OBJECT_free(cert->cert_info->key->algor->algorithm); - cert->cert_info->key->algor->algorithm = OBJ_nid2obj(NID_rsaEncryption); -#endif - } - epk = X509_get_pubkey(cert); - if (NULL == epk) { - error("Failed to extract public key from certificate\n"); - return NULL; - } - - lkey = RSAPublicKey_dup(EVP_PKEY_get1_RSA(epk)); - EVP_PKEY_free(epk); - *key_len = RSA_size(lkey); - return lkey; -} - -int32_t ssl_cert_print_fp(FILE * fp, X509 * cert) { - return X509_print_fp(fp, cert); -} - -void ssl_rkey_free(SSL_RKEY * rkey) { - RSA_free(rkey); -} - -/* returns error */ -int32_t ssl_rkey_get_exp_mod(SSL_RKEY * rkey, uint8 * exponent, uint32 max_exp_len, uint8 * modulus, uint32 max_mod_len) { - int32_t len; - -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) - BIGNUM *n, *e, *d; - - n = BN_new(); - e = BN_new(); - RSA_get0_key(rkey, &n, &e, NULL); - if ((BN_num_bytes(e) > (int32_t) max_exp_len) || (BN_num_bytes(n) > (int32_t) max_mod_len)) { - return 1; - } - len = BN_bn2bin(e, exponent); - reverse(exponent, len); - len = BN_bn2bin(n, modulus); - reverse(modulus, len); - BN_free(n); - BN_free(e); -#else - if ((BN_num_bytes(rkey->e) > (int32_t) max_exp_len) || (BN_num_bytes(rkey->n) > (int32_t) max_mod_len)) - return 1; - len = BN_bn2bin(rkey->e, exponent); - reverse(exponent, len); - len = BN_bn2bin(rkey->n, modulus); - reverse(modulus, len); -#endif - return 0; -} - -/* returns boolean */ -BOOL ssl_sig_ok(uint8 * exponent, uint32 exp_len, uint8 * modulus, uint32 mod_len, uint8 * signature, uint32 sig_len) { - return True; -} - - -void ssl_hmac_md5(const void *key, int32_t key_len, const unsigned char *msg, int32_t msg_len, unsigned char *md) { -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) - HMAC_CTX *ctx; - ctx = HMAC_CTX_new(); - HMAC(EVP_md5(), key, key_len, msg, msg_len, md, NULL); - HMAC_CTX_free(ctx); -#else - HMAC_CTX ctx; - HMAC_CTX_init(&ctx); - HMAC(EVP_md5(), key, key_len, msg, msg_len, md, NULL); - HMAC_CTX_cleanup(&ctx); -#endif -} - - -/* - * I believe this is based on SSLv3 with the following differences: - * MAC algorithm (5.2.3.1) uses only 32-bit length in place of seq_num/type/length fields - * MAC algorithm uses SHA1 and MD5 for the two hash functions instead of one or other - * key_block algorithm (6.2.2) uses 'X', 'YY', 'ZZZ' instead of 'A', 'BB', 'CCC' - * key_block partitioning is different (16 bytes each: MAC secret, decrypt key, encrypt key) - * encryption/decryption keys updated every 4096 packets - * See http://wp.netscape.com/eng/ssl3/draft302.txt - */ - -/* - * 48-byte transformation used to generate master secret (6.1) and key material (6.2.2). - * Both SHA1 and MD5 algorithms are used. - */ -void sec_hash_48(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2, uint8 salt) { - uint8 shasig[20]; - uint8 pad[4]; - SSL_SHA1 sha1; - SSL_MD5 md5; - int32_t i; - - for (i = 0; i < 3; i++) { - memset(pad, salt + i, i + 1); - - ssl_sha1_init(&sha1); - ssl_sha1_update(&sha1, pad, i + 1); - ssl_sha1_update(&sha1, in, 48); - ssl_sha1_update(&sha1, salt1, 32); - ssl_sha1_update(&sha1, salt2, 32); - ssl_sha1_final(&sha1, shasig); - - ssl_md5_init(&md5); - ssl_md5_update(&md5, in, 48); - ssl_md5_update(&md5, shasig, 20); - ssl_md5_final(&md5, &out[i * 16]); - } -} - -/* - * 16-byte transformation used to generate export keys (6.2.2). - */ -void sec_hash_16(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2) { - SSL_MD5 md5; - - ssl_md5_init(&md5); - ssl_md5_update(&md5, in, 16); - ssl_md5_update(&md5, salt1, 32); - ssl_md5_update(&md5, salt2, 32); - ssl_md5_final(&md5, out); -} - -/* Reduce key entropy from 64 to 40 bits */ -static void sec_make_40bit(uint8 * key) { - key[0] = 0xd1; - key[1] = 0x26; - key[2] = 0x9e; -} - -/* Generate encryption keys given client and server randoms */ -static void sec_generate_keys(uint8 * client_random, uint8 * server_random, int32_t rc4_key_size) { - uint8 pre_master_secret[48]; - uint8 master_secret[48]; - uint8 key_block[48]; - - /* Construct pre-master secret */ - memcpy(pre_master_secret, client_random, 24); - memcpy(pre_master_secret + 24, server_random, 24); - - /* Generate master secret and then key material */ - sec_hash_48(master_secret, pre_master_secret, client_random, server_random, 'A'); - sec_hash_48(key_block, master_secret, client_random, server_random, 'X'); - - /* First 16 bytes of key material is MAC secret */ - memcpy(g_sec_sign_key, key_block, 16); - - /* Generate export keys from next two blocks of 16 bytes */ - sec_hash_16(g_sec_decrypt_key, &key_block[16], client_random, server_random); - sec_hash_16(g_sec_encrypt_key, &key_block[32], client_random, server_random); - - if (rc4_key_size == 1) { - DEBUG(("40-bit encryption enabled\n")); - sec_make_40bit(g_sec_sign_key); - sec_make_40bit(g_sec_decrypt_key); - sec_make_40bit(g_sec_encrypt_key); - g_rc4_key_len = 8; - } else { - DEBUG(("rc_4_key_size == %d, 128-bit encryption enabled\n", rc4_key_size)); - g_rc4_key_len = 16; - } - - /* Save initial RC4 keys as update keys */ - memcpy(g_sec_decrypt_update_key, g_sec_decrypt_key, 16); - memcpy(g_sec_encrypt_update_key, g_sec_encrypt_key, 16); - - /* Initialise RC4 state arrays */ - ssl_rc4_set_key(&g_rc4_decrypt_key, g_sec_decrypt_key, g_rc4_key_len); - ssl_rc4_set_key(&g_rc4_encrypt_key, g_sec_encrypt_key, g_rc4_key_len); -} - -static uint8 pad_54[40] = { - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54 -}; - -static uint8 pad_92[48] = { - 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, - 92, 92, 92, 92, 92, 92, 92, - 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, - 92, 92, 92, 92, 92, 92, 92 -}; - -/* Output a uint32 into a buffer (little-endian) */ -void buf_out_uint32(uint8 * buffer, uint32 value) { - buffer[0] = (value) & 0xff; - buffer[1] = (value >> 8) & 0xff; - buffer[2] = (value >> 16) & 0xff; - buffer[3] = (value >> 24) & 0xff; -} - -/* Generate a MAC hash (5.2.3.1), using a combination of SHA1 and MD5 */ -void sec_sign(uint8 * signature, int32_t siglen, uint8 * session_key, int32_t keylen, uint8 * data, int32_t datalen) { - uint8 shasig[20]; - uint8 md5sig[16]; - uint8 lenhdr[4]; - SSL_SHA1 sha1; - SSL_MD5 md5; - - buf_out_uint32(lenhdr, datalen); - - ssl_sha1_init(&sha1); - ssl_sha1_update(&sha1, session_key, keylen); - ssl_sha1_update(&sha1, pad_54, 40); - ssl_sha1_update(&sha1, lenhdr, 4); - ssl_sha1_update(&sha1, data, datalen); - ssl_sha1_final(&sha1, shasig); - - ssl_md5_init(&md5); - ssl_md5_update(&md5, session_key, keylen); - ssl_md5_update(&md5, pad_92, 48); - ssl_md5_update(&md5, shasig, 20); - ssl_md5_final(&md5, md5sig); - - memcpy(signature, md5sig, siglen); -} - -/* Update an encryption key */ -static void sec_update(uint8 * key, uint8 * update_key) { - uint8 shasig[20]; - SSL_SHA1 sha1; - SSL_MD5 md5; - SSL_RC4 update; - - ssl_sha1_init(&sha1); - ssl_sha1_update(&sha1, update_key, g_rc4_key_len); - ssl_sha1_update(&sha1, pad_54, 40); - ssl_sha1_update(&sha1, key, g_rc4_key_len); - ssl_sha1_final(&sha1, shasig); - - ssl_md5_init(&md5); - ssl_md5_update(&md5, update_key, g_rc4_key_len); - ssl_md5_update(&md5, pad_92, 48); - ssl_md5_update(&md5, shasig, 20); - ssl_md5_final(&md5, key); - - ssl_rc4_set_key(&update, key, g_rc4_key_len); - ssl_rc4_crypt(&update, key, key, g_rc4_key_len); - - if (g_rc4_key_len == 8) - sec_make_40bit(key); -} - -/* Encrypt data using RC4 */ -static void sec_encrypt(uint8 * data, int32_t length) { - if (g_sec_encrypt_use_count == 4096) { - sec_update(g_sec_encrypt_key, g_sec_encrypt_update_key); - ssl_rc4_set_key(&g_rc4_encrypt_key, g_sec_encrypt_key, g_rc4_key_len); - g_sec_encrypt_use_count = 0; - } - - ssl_rc4_crypt(&g_rc4_encrypt_key, data, data, length); - g_sec_encrypt_use_count++; -} - -/* Decrypt data using RC4 */ -void sec_decrypt(uint8 * data, int32_t length) { - if (g_sec_decrypt_use_count == 4096) { - sec_update(g_sec_decrypt_key, g_sec_decrypt_update_key); - ssl_rc4_set_key(&g_rc4_decrypt_key, g_sec_decrypt_key, g_rc4_key_len); - g_sec_decrypt_use_count = 0; - } - - ssl_rc4_crypt(&g_rc4_decrypt_key, data, data, length); - g_sec_decrypt_use_count++; -} - -/* Perform an RSA public key encryption operation */ -static void sec_rsa_encrypt(uint8 * out, uint8 * in, int32_t len, uint32 modulus_size, uint8 * modulus, uint8 * exponent) { - ssl_rsa_encrypt(out, in, len, modulus_size, modulus, exponent); -} - -/* Initialise secure transport packet */ -STREAM sec_init(uint32 flags, int32_t maxlen) { - int32_t hdrlen; - STREAM s; - -// if (!g_licence_issued) - hdrlen = (flags & SEC_ENCRYPT) ? 12 : 4; -// else - -// hdrlen = (flags & SEC_ENCRYPT) ? 12 : 0; - s = mcs_init(maxlen + hdrlen); - s_push_layer(s, sec_hdr, hdrlen); - - return s; -} - -/* Transmit secure transport packet over specified channel */ -void sec_send_to_channel(STREAM s, uint32 flags, uint16 channel) { - int32_t datalen; - - s_pop_layer(s, sec_hdr); - out_uint32_le(s, flags); - - if (flags & SEC_ENCRYPT) { - flags &= ~SEC_ENCRYPT; - datalen = s->end - s->p - 8; - - sec_sign(s->p, 8, g_sec_sign_key, g_rc4_key_len, s->p + 8, datalen); - sec_encrypt(s->p + 8, datalen); - } - - mcs_send_to_channel(s, channel); -} - -/* Transmit secure transport packet */ - -void sec_send(STREAM s, uint32 flags) { - sec_send_to_channel(s, flags, MCS_GLOBAL_CHANNEL); -} - - -/* Transfer the client random to the server */ -static void sec_establish_key(void) { - uint32 length = g_server_public_key_len + SEC_PADDING_SIZE; - uint32 flags = SEC_CLIENT_RANDOM; - STREAM s; - - s = sec_init(flags, length + 4); - - out_uint32_le(s, length); - out_uint8p(s, g_sec_crypted_random, g_server_public_key_len); - out_uint8s(s, SEC_PADDING_SIZE); - - s_mark_end(s); - sec_send(s, flags); -} - -/* Output a string in Unicode */ -void rdp_out_unistr(STREAM s, char *string, int32_t len) { - int32_t i = 0, j = 0; - - len += 2; - while (i < len) { - s->p[i++] = string[j++]; - s->p[i++] = 0; - } - s->p += len; -} - -/* Output connect initial data blob */ -static void sec_out_mcs_data(STREAM s) { - char *g_hostname = "hydra"; - int32_t hostlen = 2 * strlen(g_hostname); - int32_t length = 158 + 76 + 12 + 4; - -/* - if (g_num_channels > 0) - length += g_num_channels * 12 + 8; -*/ - if (hostlen > 30) - hostlen = 30; - - /* Generic Conference Control (T.124) ConferenceCreateRequest */ - out_uint16_be(s, 5); - out_uint16_be(s, 0x14); - out_uint8(s, 0x7c); - out_uint16_be(s, 1); - - out_uint16_be(s, (length | 0x8000)); /* remaining length */ - - out_uint16_be(s, 8); /* length? */ - out_uint16_be(s, 16); - out_uint8(s, 0); - out_uint16_le(s, 0xc001); - out_uint8(s, 0); - - out_uint32_le(s, 0x61637544); /* OEM ID: "Duca", as in Ducati. */ - out_uint16_be(s, ((length - 14) | 0x8000)); /* remaining length */ - - /* Client information */ - out_uint16_le(s, SEC_TAG_CLI_INFO); - out_uint16_le(s, 212); /* length */ - out_uint16_le(s, g_use_rdp5 ? 4 : 1); /* RDP version. 1 == RDP4, 4 == RDP5. */ - out_uint16_le(s, 8); - out_uint16_le(s, 800); - out_uint16_le(s, 600); - out_uint16_le(s, 0xca01); - out_uint16_le(s, 0xaa03); - out_uint32_le(s, 0x409); - out_uint32_le(s, 2600); /* Client build. We are now 2600 compatible :-) */ - - /* Unicode name of client, padded to 32 bytes */ - rdp_out_unistr(s, g_hostname, hostlen); - out_uint8s(s, 30 - hostlen); - - /* See - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wceddk40/html/cxtsksupportingremotedesktopprotocol.asp */ - out_uint32_le(s, 0x4); - out_uint32_le(s, 0x0); - out_uint32_le(s, 0xc); - out_uint8s(s, 64); /* reserved? 4 + 12 doublewords */ - out_uint16_le(s, 0xca01); /* colour depth? */ - out_uint16_le(s, 1); - - out_uint32(s, 0); - out_uint8(s, g_server_depth); - out_uint16_le(s, 0x0700); - out_uint8(s, 0); - out_uint32_le(s, 1); - out_uint8s(s, 64); /* End of client info */ - - out_uint16_le(s, SEC_TAG_CLI_4); - out_uint16_le(s, 12); - out_uint32_le(s, g_console_session ? 0xb : 9); - out_uint32(s, 0); - - /* Client encryption settings */ - out_uint16_le(s, SEC_TAG_CLI_CRYPT); - out_uint16_le(s, 12); /* length */ - out_uint32_le(s, g_encryption ? 0x3 : 0); /* encryption supported, 128-bit supported */ - out_uint32(s, 0); /* Unknown */ - -/* - DEBUG_RDP5(("g_num_channels is %d\n", g_num_channels)); - if (g_num_channels > 0) - { - out_uint16_le(s, SEC_TAG_CLI_CHANNELS); - out_uint16_le(s, g_num_channels * 12 + 8); // length - out_uint32_le(s, g_num_channels); // number of virtual channels - for (i = 0; i < g_num_channels; i++) - { - DEBUG_RDP5(("Requesting channel %s\n", g_channels[i].name)); - out_uint8a(s, g_channels[i].name, 8); - out_uint32_be(s, g_channels[i].flags); - } - } -*/ - s_mark_end(s); -} - -/* Parse a public key structure */ -static BOOL sec_parse_public_key(STREAM s, uint8 * modulus, uint8 * exponent) { - uint32 magic, modulus_len; - - in_uint32_le(s, magic); - - if (magic != SEC_RSA_MAGIC) { - error("RSA magic 0x%x\n", magic); - return False; - } - - in_uint32_le(s, modulus_len); - modulus_len -= SEC_PADDING_SIZE; - if ((modulus_len < SEC_MODULUS_SIZE) || (modulus_len > SEC_MAX_MODULUS_SIZE)) { - error("Bad server public key size (%u bits)\n", modulus_len * 8); - return False; - } - - in_uint8s(s, 8); /* modulus_bits, unknown */ - in_uint8a(s, exponent, SEC_EXPONENT_SIZE); - in_uint8a(s, modulus, modulus_len); - in_uint8s(s, SEC_PADDING_SIZE); - g_server_public_key_len = modulus_len; - - return s_check(s); -} - -/* Parse a public signature structure */ -static BOOL sec_parse_public_sig(STREAM s, uint32 len, uint8 * modulus, uint8 * exponent) { - uint8 signature[SEC_MAX_MODULUS_SIZE]; - uint32 sig_len; - - if (len != 72) { - return True; - } - memset(signature, 0, sizeof(signature)); - sig_len = len - 8; - in_uint8a(s, signature, sig_len); - return ssl_sig_ok(exponent, SEC_EXPONENT_SIZE, modulus, g_server_public_key_len, signature, sig_len); -} - -/* Parse a crypto information structure */ -static BOOL sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size, uint8 ** server_random, uint8 * modulus, uint8 * exponent) { - uint32 crypt_level, random_len, rsa_info_len; - uint32 cacert_len, cert_len, flags; - X509 *cacert, *server_cert; - SSL_RKEY *server_public_key; - uint16 tag, length; - uint8 *next_tag, *end; - - in_uint32_le(s, *rc4_key_size); /* 1 = 40-bit, 2 = 128-bit */ - in_uint32_le(s, crypt_level); /* 1 = low, 2 = medium, 3 = high */ - if (crypt_level == 0) /* no encryption */ - return False; - in_uint32_le(s, random_len); - in_uint32_le(s, rsa_info_len); - - if (random_len != SEC_RANDOM_SIZE) { - error("random len %d, expected %d\n", random_len, SEC_RANDOM_SIZE); - return False; - } - - in_uint8p(s, *server_random, random_len); - - /* RSA info */ - end = s->p + rsa_info_len; - if (end > s->end) - return False; - - in_uint32_le(s, flags); /* 1 = RDP4-style, 0x80000002 = X.509 */ - if (flags & 1) { - DEBUG_RDP5(("We're going for the RDP4-style encryption\n")); - in_uint8s(s, 8); /* unknown */ - - while (s->p < end) { - in_uint16_le(s, tag); - in_uint16_le(s, length); - - next_tag = s->p + length; - - switch (tag) { - case SEC_TAG_PUBKEY: - if (!sec_parse_public_key(s, modulus, exponent)) - return False; - DEBUG_RDP5(("Got Public key, RDP4-style\n")); - - break; - - case SEC_TAG_KEYSIG: - if (!sec_parse_public_sig(s, length, modulus, exponent)) - return False; - break; - - default: - unimpl("crypt tag 0x%x\n", tag); - } - - s->p = next_tag; - } - } else { - uint32 certcount; - - DEBUG_RDP5(("We're going for the RDP5-style encryption\n")); - in_uint32_le(s, certcount); /* Number of certificates */ - if (certcount < 2) { - error("Server didn't send enough X509 certificates\n"); - return False; - } - for (; certcount > 2; certcount--) { /* ignore all the certificates between the root and the signing CA */ - uint32 ignorelen; - X509 *ignorecert; - - DEBUG_RDP5(("Ignored certs left: %d\n", certcount)); - in_uint32_le(s, ignorelen); - DEBUG_RDP5(("Ignored Certificate length is %d\n", ignorelen)); - ignorecert = ssl_cert_read(s->p, ignorelen); - in_uint8s(s, ignorelen); - if (ignorecert == NULL) { /* XXX: error out? */ - DEBUG_RDP5(("got a bad cert: this will probably screw up the rest of the communication\n")); - } -#ifdef WITH_DEBUG_RDP5 - DEBUG_RDP5(("cert #%d (ignored):\n", certcount)); - ssl_cert_print_fp(stdout, ignorecert); -#endif - } - /* Do da funky X.509 stuffy - - "How did I find out about this? I looked up and saw a - bright light and when I came to I had a scar on my forehead - and knew about X.500" - - Peter Gutman in a early version of - http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt - */ - in_uint32_le(s, cacert_len); - DEBUG_RDP5(("CA Certificate length is %d\n", cacert_len)); - cacert = ssl_cert_read(s->p, cacert_len); - in_uint8s(s, cacert_len); - if (NULL == cacert) { - error("Couldn't load CA Certificate from server\n"); - return False; - } - in_uint32_le(s, cert_len); - DEBUG_RDP5(("Certificate length is %d\n", cert_len)); - server_cert = ssl_cert_read(s->p, cert_len); - in_uint8s(s, cert_len); - if (NULL == server_cert) { - ssl_cert_free(cacert); - error("Couldn't load Certificate from server\n"); - return False; - } - ssl_cert_free(cacert); - in_uint8s(s, 16); /* Padding */ - server_public_key = ssl_cert_to_rkey(server_cert, &g_server_public_key_len); - if (NULL == server_public_key) { - DEBUG_RDP5(("Didn't parse X509 correctly\n")); - ssl_cert_free(server_cert); - return False; - } - ssl_cert_free(server_cert); - if ((g_server_public_key_len < SEC_MODULUS_SIZE) || (g_server_public_key_len > SEC_MAX_MODULUS_SIZE)) { - error("Bad server public key size (%u bits)\n", g_server_public_key_len * 8); - ssl_rkey_free(server_public_key); - return False; - } - if (ssl_rkey_get_exp_mod(server_public_key, exponent, SEC_EXPONENT_SIZE, modulus, SEC_MAX_MODULUS_SIZE) != 0) { - error("Problem extracting RSA exponent, modulus"); - ssl_rkey_free(server_public_key); - return False; - } - ssl_rkey_free(server_public_key); - return True; /* There's some garbage here we don't care about */ - } - return s_check_end(s); -} - -/* Process crypto information blob */ -static void sec_process_crypt_info(STREAM s) { - uint8 *server_random = NULL; - uint8 modulus[SEC_MAX_MODULUS_SIZE]; - uint8 exponent[SEC_EXPONENT_SIZE]; - uint32 rc4_key_size; - - memset(modulus, 0, sizeof(modulus)); - memset(exponent, 0, sizeof(exponent)); - if (!sec_parse_crypt_info(s, &rc4_key_size, &server_random, modulus, exponent)) { - DEBUG(("Failed to parse crypt info\n")); - return; - } - DEBUG(("Generating client random\n")); - generate_random(g_client_random); - sec_rsa_encrypt(g_sec_crypted_random, g_client_random, SEC_RANDOM_SIZE, g_server_public_key_len, modulus, exponent); - sec_generate_keys(g_client_random, server_random, rc4_key_size); -} - - -/* Process SRV_INFO, find RDP version supported by server */ -static void sec_process_srv_info(STREAM s) { - in_uint16_le(s, g_server_rdp_version); - if (verbose) - hydra_report(stderr, "[VERBOSE] Server RDP version is %d\n", g_server_rdp_version); - if (1 == g_server_rdp_version) { - g_use_rdp5 = 0; - g_server_depth = 8; - } -} - - -/* Process connect response data blob */ -void sec_process_mcs_data(STREAM s) { - uint16 tag, length; - uint8 *next_tag; - uint8 len; - - in_uint8s(s, 21); /* header (T.124 ConferenceCreateResponse) */ - in_uint8(s, len); - if (len & 0x80) - in_uint8(s, len); - - while (s->p < s->end) { - in_uint16_le(s, tag); - in_uint16_le(s, length); - - if (length <= 4) - return; - - next_tag = s->p + length - 4; - - switch (tag) { - case SEC_TAG_SRV_INFO: - sec_process_srv_info(s); - break; - - case SEC_TAG_SRV_CRYPT: - sec_process_crypt_info(s); - break; - - case SEC_TAG_SRV_CHANNELS: - break; - - default: - unimpl("response tag 0x%x\n", tag); - } - - s->p = next_tag; - } -} - -/* Receive secure transport packet */ -STREAM sec_recv(uint8 * rdpver) { - uint32 sec_flags; - uint16 channel = 0; - STREAM s; - - while ((s = mcs_recv(&channel, rdpver)) != NULL) { - if (rdpver != NULL) { - if (*rdpver != 3) { - if (*rdpver & 0x80) { - in_uint8s(s, 8); /* signature */ - sec_decrypt(s->p, s->end - s->p); - } - return s; - } - } - //if (g_encryption || !g_licence_issued) - if (g_encryption) { - in_uint32_le(s, sec_flags); - - if (sec_flags & SEC_ENCRYPT) { - in_uint8s(s, 8); /* signature */ - sec_decrypt(s->p, s->end - s->p); - } - - if (sec_flags & SEC_LICENCE_NEG) { - //licence_process(s); - continue; - } - - if (sec_flags & 0x0400) { /* SEC_REDIRECT_ENCRYPT */ - uint8 swapbyte; - - in_uint8s(s, 8); /* signature */ - sec_decrypt(s->p, s->end - s->p); - - /* Check for a redirect packet, starts with 00 04 */ - if (s->p[0] == 0 && s->p[1] == 4) { - /* for some reason the PDU and the length seem to be swapped. - This isn't good, but we're going to do a byte for byte - swap. So the first foure value appear as: 00 04 XX YY, - where XX YY is the little endian length. We're going to - use 04 00 as the PDU type, so after our swap this will look - like: XX YY 04 00 */ - swapbyte = s->p[0]; - s->p[0] = s->p[2]; - s->p[2] = swapbyte; - - swapbyte = s->p[1]; - s->p[1] = s->p[3]; - s->p[3] = swapbyte; - - swapbyte = s->p[2]; - s->p[2] = s->p[3]; - s->p[3] = swapbyte; - } -#ifdef WITH_DEBUG - /* warning! this debug statement will show passwords in the clear! */ - hexdump(s->p, s->end - s->p); -#endif - } - - } - - if (channel != MCS_GLOBAL_CHANNEL) { - if (rdpver != NULL) - *rdpver = 0xff; - return s; - } - - return s; - } - - return NULL; -} - -/* Establish a secure connection */ -BOOL sec_connect(char *server, char *username, BOOL reconnect) { - struct stream mcs_data; - - /* We exchange some RDP data during the MCS-Connect */ - mcs_data.size = 512; - mcs_data.end = mcs_data.p = mcs_data.data = (uint8 *) xmalloc(mcs_data.size); - sec_out_mcs_data(&mcs_data); - - if (!mcs_connect(server, &mcs_data, username, reconnect)) - return False; - if (g_encryption) - sec_establish_key(); - free(mcs_data.data); - mcs_data.data = NULL; - return True; -} - -/* Disconnect a connection */ -void sec_disconnect(void) { - mcs_disconnect(); -} - -/* reset the state of the sec layer */ -void sec_reset_state(void) { - g_server_rdp_version = 0; - g_sec_encrypt_use_count = 0; - g_sec_decrypt_use_count = 0; - mcs_reset_state(); -} - - - -/* Read field indicating which parameters are present */ -static void rdp_in_present(STREAM s, uint32 * present, uint8 flags, int32_t size) { - uint8 bits; - int32_t i; - - if (flags & RDP_ORDER_SMALL) { - size--; - } - - if (flags & RDP_ORDER_TINY) { - if (size < 2) - size = 0; - else - size -= 2; - } - - *present = 0; - for (i = 0; i < size; i++) { - in_uint8(s, bits); - *present |= bits << (i * 8); - } -} - -/* Read a co-ordinate (16-bit, or 8-bit delta) */ -static void rdp_in_coord(STREAM s, sint16 * coord, BOOL delta) { - sint8 change; - - if (delta) { - in_uint8(s, change); - *coord += change; - } else { - in_uint16_le(s, *coord); - } -} - -/* Read a colour entry */ -static void rdp_in_colour(STREAM s, uint32 * colour) { - uint32 i; - - in_uint8(s, i); - *colour = i; - in_uint8(s, i); - *colour |= i << 8; - in_uint8(s, i); - *colour |= i << 16; -} - -/* Parse bounds information */ -static BOOL rdp_parse_bounds(STREAM s, BOUNDS * bounds) { - uint8 present; - - in_uint8(s, present); - - if (present & 1) - rdp_in_coord(s, &bounds->left, False); - else if (present & 16) - rdp_in_coord(s, &bounds->left, True); - - if (present & 2) - rdp_in_coord(s, &bounds->top, False); - else if (present & 32) - rdp_in_coord(s, &bounds->top, True); - - if (present & 4) - rdp_in_coord(s, &bounds->right, False); - else if (present & 64) - rdp_in_coord(s, &bounds->right, True); - - if (present & 8) - rdp_in_coord(s, &bounds->bottom, False); - else if (present & 128) - rdp_in_coord(s, &bounds->bottom, True); - - return s_check(s); -} - -/* Process an opaque rectangle order */ -static void process_rect(STREAM s, RECT_ORDER * os, uint32 present, BOOL delta) { - uint32 i; - - if (present & 0x01) - rdp_in_coord(s, &os->x, delta); - - if (present & 0x02) - rdp_in_coord(s, &os->y, delta); - - if (present & 0x04) - rdp_in_coord(s, &os->cx, delta); - - if (present & 0x08) - rdp_in_coord(s, &os->cy, delta); - - if (present & 0x10) { - in_uint8(s, i); - os->colour = (os->colour & 0xffffff00) | i; - } - - if (present & 0x20) { - in_uint8(s, i); - os->colour = (os->colour & 0xffff00ff) | (i << 8); - } - - if (present & 0x40) { - in_uint8(s, i); - os->colour = (os->colour & 0xff00ffff) | (i << 16); - } - - DEBUG(("RECT(x=%d,y=%d,cx=%d,cy=%d,fg=0x%x)\n", os->x, os->y, os->cx, os->cy, os->colour)); -} - -/* Process a desktop save order */ -static void process_desksave(STREAM s, DESKSAVE_ORDER * os, uint32 present, BOOL delta) { - //int32_t width, height; - - if (present & 0x01) - in_uint32_le(s, os->offset); - - if (present & 0x02) - rdp_in_coord(s, &os->left, delta); - - if (present & 0x04) - rdp_in_coord(s, &os->top, delta); - - if (present & 0x08) - rdp_in_coord(s, &os->right, delta); - - if (present & 0x10) - rdp_in_coord(s, &os->bottom, delta); - - if (present & 0x20) - in_uint8(s, os->action); - - DEBUG(("DESKSAVE(l=%d,t=%d,r=%d,b=%d,off=%d,op=%d)\n", os->left, os->top, os->right, os->bottom, os->offset, os->action)); - - //width = os->right - os->left + 1; - //height = os->bottom - os->top + 1; -} - -/* Process a memory blt order */ -static void process_memblt(STREAM s, MEMBLT_ORDER * os, uint32 present, BOOL delta) { - //on win 7, vista, 2008, the login failed has to be catched here - if (present & 0x0001) { - in_uint8(s, os->cache_id); - in_uint8(s, os->colour_table); - } - - if (present & 0x0002) - rdp_in_coord(s, &os->x, delta); - - if (present & 0x0004) - rdp_in_coord(s, &os->y, delta); - - if (present & 0x0008) - rdp_in_coord(s, &os->cx, delta); - - if (present & 0x0010) - rdp_in_coord(s, &os->cy, delta); - - if (present & 0x0020) - in_uint8(s, os->opcode); - - if (present & 0x0040) - rdp_in_coord(s, &os->srcx, delta); - - if (present & 0x0080) - rdp_in_coord(s, &os->srcy, delta); - - if (present & 0x0100) - in_uint16_le(s, os->cache_idx); - - DEBUG(("MEMBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,id=%d,idx=%d)\n", os->opcode, os->x, os->y, os->cx, os->cy, os->cache_id, os->cache_idx)); - //MEMBLT(op=0xcc,x=640,y=128,cx=64,cy=64,id=2,idx=117) => win8 failed - - if ((os->opcode == 0xcc && os->x == 740 && os->y == 448 && os->cx == 60 && os->cy == 56 && os->cache_id == 2) || - (os->opcode == 0xcc && os->x == 640 && os->y == 128 && os->cx == 64 && os->cy == 64 && os->cache_id == 2 && os->cache_idx > 100)) { - if (debug) - hydra_report(stderr, "[DEBUG] Login failed from process_memblt\n"); - login_result = LOGIN_FAIL; - } -} - -/* Process a text order */ -static void process_text2(STREAM s, TEXT2_ORDER * os, uint32 present, BOOL delta) { - int32_t i; - - if (present & 0x000001) - in_uint8(s, os->font); - - if (present & 0x000002) - in_uint8(s, os->flags); - - if (present & 0x000004) - in_uint8(s, os->opcode); - - if (present & 0x000008) - in_uint8(s, os->mixmode); - - if (present & 0x000010) - rdp_in_colour(s, &os->fgcolour); - - if (present & 0x000020) - rdp_in_colour(s, &os->bgcolour); - - if (present & 0x000040) - in_uint16_le(s, os->clipleft); - - if (present & 0x000080) - in_uint16_le(s, os->cliptop); - - if (present & 0x000100) - in_uint16_le(s, os->clipright); - - if (present & 0x000200) - in_uint16_le(s, os->clipbottom); - - if (present & 0x000400) - in_uint16_le(s, os->boxleft); - - if (present & 0x000800) - in_uint16_le(s, os->boxtop); - - if (present & 0x001000) - in_uint16_le(s, os->boxright); - - if (present & 0x002000) - in_uint16_le(s, os->boxbottom); - - //rdp_parse_brush(s, &os->brush, present >> 14); - - if (present & 0x080000) - in_uint16_le(s, os->x); - - if (present & 0x100000) - in_uint16_le(s, os->y); - - if (present & 0x200000) { - in_uint8(s, os->length); - in_uint8a(s, os->text, os->length); - } - //printf("TEXT2(x=%d,y=%d,cl=%d,ct=%d,cr=%d,cb=%d,bl=%d,bt=%d,br=%d,bb=%d,bs=%d,bg=0x%x,fg=0x%x,font=%d,fl=0x%x,op=0x%x,mix=%d,n=%d)\n", os->x, os->y, os->clipleft, os->cliptop, os->clipright, os->clipbottom, os->boxleft, os->boxtop, os->boxright, os->boxbottom, , os->bgcolour, os->fgcolour, os->font, os->flags, os->opcode, os->mixmode, os->length); - - if (debug) { - printf("[DEBUG] process_text2: "); - - for (i = 0; i < os->length; i++) - printf("%02x ", os->text[i]); - printf(" *** "); - - printf("size: %d\n", os->length); - } - //there is no way to determine if the message from w2k is a success or failure at first - //so we identify it here and set the os version as win 2000 same for win2k3 - if (!memcmp(os->text, LOGON_MESSAGE_2K, 31)) { - os_version = 2000; - } - if (!memcmp(os->text, LOGON_MESSAGE_FAILED_2K3, 18)) { - os_version = 2003; - } - //on win2k, error can be fe 00 00 or fe 02 00 - if (((os->text[0] == 254) && (os->text[2] == 0)) || (!memcmp(os->text, LOGON_MESSAGE_FAILED_XP, 18))) { - if (debug) - hydra_report(stderr, "[DEBUG] login failed from process_text2\n"); - login_result = LOGIN_FAIL; - } else { - //if it's not an well known error and if it's not just traffic from win 2000 server - - if ((os_version == 2000) && (os->length > 50)) { - if (debug) - hydra_report(stderr, "[DEBUG] login success from process_text2\n"); - login_result = LOGIN_SUCC; - } - } -} - -/* Process a secondary order */ -static void process_secondary_order(STREAM s) { - /* The length isn't calculated correctly by the server. - * For very compact orders the length becomes negative - * so a signed integer must be used. */ - uint16 length; - //uint16 flags; - //uint8 type; - uint8 *next_order; - - in_uint16_le(s, length); - //in_uint16_le(s, flags); /* used by bmpcache2 */ - //in_uint8(s, type); - - next_order = s->p + (sint16) length + 7; - - /* - switch (type) - { - case RDP_ORDER_RAW_BMPCACHE: - break; - - case RDP_ORDER_COLCACHE: - break; - - case RDP_ORDER_BMPCACHE: - break; - - case RDP_ORDER_FONTCACHE: - process_fontcache(s); - break; - - case RDP_ORDER_RAW_BMPCACHE2: - break; - - case RDP_ORDER_BMPCACHE2: - break; - - case RDP_ORDER_BRUSHCACHE: - process_brushcache(s, flags); - break; - - default: - unimpl("secondary order %d\n", type); - } - */ - s->p = next_order; -} - -/* Process an order PDU */ -void process_orders(STREAM s, uint16 num_orders) { - RDP_ORDER_STATE *os = &g_order_state; - uint32 present; - uint8 order_flags; - int32_t size, processed = 0; - BOOL delta; - - while (processed < num_orders) { - in_uint8(s, order_flags); - - if (os_version == 2003) - os_version = 0; - - if (!(order_flags & RDP_ORDER_STANDARD)) { - //error("order parsing failed\n"); - //we detected the os is a win 2000 version and the next text msg will be either an error LOGON_MESSAGE_FAILED_2K - //or any other traffic indicating the logon was successfull, so we reset the os_version and let process_text2 handle the msg - if (os_version == 2003) - login_result = LOGIN_SUCC; - break; - } - - if (order_flags & RDP_ORDER_SECONDARY) { - process_secondary_order(s); - } else { - if (order_flags & RDP_ORDER_CHANGE) { - in_uint8(s, os->order_type); - } - - switch (os->order_type) { - case RDP_ORDER_TRIBLT: - case RDP_ORDER_TEXT2: - size = 3; - break; - - case RDP_ORDER_PATBLT: - case RDP_ORDER_MEMBLT: - case RDP_ORDER_LINE: - case RDP_ORDER_POLYGON2: - case RDP_ORDER_ELLIPSE2: - size = 2; - break; - - default: - size = 1; - } - - rdp_in_present(s, &present, order_flags, size); - - if (order_flags & RDP_ORDER_BOUNDS) { - if (!(order_flags & RDP_ORDER_LASTBOUNDS)) - rdp_parse_bounds(s, &os->bounds); - - } - - delta = order_flags & RDP_ORDER_DELTA; - -//printf("order %d\n", os->order_type); - - if (login_result) - return; - - switch (os->order_type) { - - case RDP_ORDER_RECT: - process_rect(s, &os->rect, present, delta); - break; - - case RDP_ORDER_DESKSAVE: - process_desksave(s, &os->desksave, present, delta); - break; - - case RDP_ORDER_MEMBLT: - process_memblt(s, &os->memblt, present, delta); - break; - - case RDP_ORDER_TEXT2: - process_text2(s, &os->text2, present, delta); - break; - - default: - if (debug) - printf("[DEBUG] unknown order_type: %d\n", os->order_type); - - } - } - - processed++; - } -} - -/* Reset order state */ -void reset_order_state(void) { - memset(&g_order_state, 0, sizeof(g_order_state)); - g_order_state.order_type = RDP_ORDER_PATBLT; -} - -/* Disconnect from the RDP layer */ -void rdp_disconnect(void) { - sec_disconnect(); -} - - -void rdp5_process(STREAM s) { - uint16 length, count; - uint8 type/*, ctype*/; - uint8 *next; - - struct stream *ts; - - while (s->p < s->end) { - in_uint8(s, type); - if (type & RDP5_COMPRESSED) { - //in_uint8(s, ctype); - in_uint16_le(s, length); - type ^= RDP5_COMPRESSED; - } else { - //ctype = 0; - in_uint16_le(s, length); - } - g_next_packet = next = s->p + length; - ts = s; -//printf("type: %d\n", type); - switch (type) { - case 0: /* update orders */ - in_uint16_le(ts, count); - process_orders(ts, count); - break; - - } - - s->p = next; - } -} - - -/* Receive an RDP packet */ -static STREAM rdp_recv(uint8 * type) { - static STREAM rdp_s; - uint16 length, pdu_type; - uint8 rdpver; - - if ((rdp_s == NULL) || (g_next_packet >= rdp_s->end) || (g_next_packet == NULL)) { - rdp_s = sec_recv(&rdpver); - if (rdp_s == NULL) - return NULL; - if (rdpver == 0xff) { - g_next_packet = rdp_s->end; - *type = 0; - return rdp_s; - } else if (rdpver != 3) { - /* rdp5_process should move g_next_packet ok */ - rdp5_process(rdp_s); - *type = 0; - return rdp_s; - } - - g_next_packet = rdp_s->p; - } else { - rdp_s->p = g_next_packet; - } - - in_uint16_le(rdp_s, length); - /* 32k packets are really 8, keepalive fix */ - if (length == 0x8000) { - g_next_packet += 8; - *type = 0; - return rdp_s; - } - in_uint16_le(rdp_s, pdu_type); - in_uint8s(rdp_s, 2); /* userid */ - *type = pdu_type & 0xf; - - g_next_packet += length; - return rdp_s; -} - -/* used in uiports and rdp_main_loop, processes the rdp packets waiting */ -BOOL rdp_loop(BOOL * deactivated, uint32 * ext_disc_reason) { - uint8 type; - BOOL cont = True; - STREAM s; - - while (cont) { - s = rdp_recv(&type); - - if (s == NULL) - return False; - switch (type) { - case RDP_PDU_DEMAND_ACTIVE: - process_demand_active(s); - *deactivated = False; - break; - case RDP_PDU_DEACTIVATE: - DEBUG(("RDP_PDU_DEACTIVATE\n")); - *deactivated = True; - break; - case RDP_PDU_REDIRECT: - break; - case RDP_PDU_DATA: - process_data_pdu(s, ext_disc_reason); - break; - case 0: - break; - default: - unimpl("PDU %d\n", type); - } - cont = g_next_packet < s->end; - } - return True; -} - -/* Process incoming packets */ -int32_t rdp_main_loop(BOOL * deactivated, uint32 * ext_disc_reason) { - while (rdp_loop(deactivated, ext_disc_reason)) { - if (login_result != LOGIN_UNKN) { - return login_result; - } - } - return 0; -} - - - -/* Parse a logon info packet */ -static void rdp_send_logon_info(uint32 flags, char *domain, char *user, char *password, char *program, char *directory) { - char *ipaddr = tcp_get_address(); - int32_t len_domain = 2 * strlen(domain); - int32_t len_user = 2 * strlen(user); - int32_t len_password = 2 * strlen(password); - int32_t len_program = 2 * strlen(program); - int32_t len_directory = 2 * strlen(directory); - int32_t len_ip = 2 * strlen(ipaddr); - int32_t len_dll = 2 * strlen("C:\\WINNT\\System32\\mstscax.dll"); - int32_t packetlen = 0; - uint32 sec_flags = g_encryption ? (SEC_LOGON_INFO | SEC_ENCRYPT) : SEC_LOGON_INFO; - STREAM s = NULL; - time_t t = time(NULL); - time_t tzone; - uint8 security_verifier[16]; - - if (!g_use_rdp5 || 1 == g_server_rdp_version) { - DEBUG_RDP5(("Sending RDP4-style Logon packet\n")); - - s = sec_init(sec_flags, 18 + len_domain + len_user + len_password + len_program + len_directory + 10); - - out_uint32(s, 0); - out_uint32_le(s, flags); - out_uint16_le(s, len_domain); - out_uint16_le(s, len_user); - out_uint16_le(s, len_password); - out_uint16_le(s, len_program); - out_uint16_le(s, len_directory); - rdp_out_unistr(s, domain, len_domain); - rdp_out_unistr(s, user, len_user); - rdp_out_unistr(s, password, len_password); - rdp_out_unistr(s, program, len_program); - rdp_out_unistr(s, directory, len_directory); - } else { - - flags |= RDP_LOGON_BLOB; - DEBUG_RDP5(("Sending RDP5-style Logon packet\n")); - packetlen = 4 + /* Unknown uint32 */ - 4 + /* flags */ - 2 + /* len_domain */ - 2 + /* len_user */ - (flags & RDP_LOGON_AUTO ? 2 : 0) + /* len_password */ - (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO) ? 2 : 0) + /* Length of BLOB */ - 2 + /* len_program */ - 2 + /* len_directory */ - (0 < len_domain ? len_domain : 2) + /* domain */ - len_user + /* len user */ - (flags & RDP_LOGON_AUTO ? len_password : 0) + /* len pass */ - 0 + /* We have no 512 byte BLOB. Perhaps we must? */ - (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO) ? 2 : 0) + /* After the BLOB is a unknown int16. If there is a BLOB, that is. */ - (0 < len_program ? len_program : 2) + /* program */ - (0 < len_directory ? len_directory : 2) + /* dir */ - 2 + /* Unknown (2) */ - 2 + /* Client ip length */ - len_ip + /* Client ip */ - 2 + /* DLL string length */ - len_dll + /* DLL string */ - 4 + /* zone */ - strlen("GTB, normaltid") * 2 + /* zonestring */ - 1 + /* len */ - 5 * 4 + /* some int32 */ - 2 * strlen("GTB, sommartid") + /* zonestring */ - 1 + /* len */ - 5 * 4 + /* some int32 */ - 2 * 4 + /* some int32 */ - (g_has_reconnect_random ? 14 + sizeof(security_verifier) : 2) + 105 + /* ??? we need this */ - 0; // end -//printf("pl: %d - flags %d - AUTO %d - BLOB %d\n", packetlen, flags, RDP_LOGON_AUTO, RDP_LOGON_BLOB); - - s = sec_init(sec_flags, packetlen); - DEBUG_RDP5(("Called sec_init with packetlen %d\n", packetlen)); - - out_uint32(s, 0); /* Unknown */ - out_uint32_le(s, flags); - out_uint16_le(s, len_domain); - out_uint16_le(s, len_user); - if (flags & RDP_LOGON_AUTO) { - out_uint16_le(s, len_password); - } - if (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO)) { - out_uint16_le(s, 0); - } - out_uint16_le(s, len_program); - out_uint16_le(s, len_directory); - if (0 < len_domain) - rdp_out_unistr(s, domain, len_domain); - else - out_uint16_le(s, 0); - rdp_out_unistr(s, user, len_user); - if (flags & RDP_LOGON_AUTO) { - rdp_out_unistr(s, password, len_password); - } - if (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO)) { - out_uint16_le(s, 0); - } - if (0 < len_program) { - rdp_out_unistr(s, program, len_program); - } else { - out_uint16_le(s, 0); - } - if (0 < len_directory) { - rdp_out_unistr(s, directory, len_directory); - } else { - out_uint16_le(s, 0); - } - /* TS_EXTENDED_INFO_PACKET */ - out_uint16_le(s, 2); /* clientAddressFamily = AF_INET */ - out_uint16_le(s, len_ip + 2); /* cbClientAddress, Length of client ip */ - rdp_out_unistr(s, ipaddr, len_ip); /* clientAddress */ - out_uint16_le(s, len_dll + 2); /* cbClientDir */ - rdp_out_unistr(s, "C:\\WINNT\\System32\\mstscax.dll", len_dll); /* clientDir */ - - /* TS_TIME_ZONE_INFORMATION */ - tzone = (mktime(gmtime(&t)) - mktime(localtime(&t))) / 60; - out_uint32_le(s, tzone); - rdp_out_unistr(s, "GTB, normaltid", 2 * strlen("GTB, normaltid")); - out_uint8s(s, 62 - 2 * strlen("GTB, normaltid")); - out_uint32_le(s, 0x0a0000); - out_uint32_le(s, 0x050000); - out_uint32_le(s, 3); - out_uint32_le(s, 0); - out_uint32_le(s, 0); - rdp_out_unistr(s, "GTB, sommartid", 2 * strlen("GTB, sommartid")); - out_uint8s(s, 62 - 2 * strlen("GTB, sommartid")); - out_uint32_le(s, 0x30000); - out_uint32_le(s, 0x050000); - out_uint32_le(s, 2); - out_uint32(s, 0); - out_uint32_le(s, 0xffffffc4); /* DaylightBias */ - - /* Rest of TS_EXTENDED_INFO_PACKET */ - out_uint32_le(s, 0xfffffffe); /* clientSessionId, consider changing to 0 */ - out_uint32_le(s, g_rdp5_performanceflags); - - /* Client Auto-Reconnect */ - if (g_has_reconnect_random) { - out_uint16_le(s, 28); /* cbAutoReconnectLen */ - /* ARC_CS_PRIVATE_PACKET */ - out_uint32_le(s, 28); /* cbLen */ - out_uint32_le(s, 1); /* Version */ - out_uint32_le(s, g_reconnect_logonid); /* LogonId */ - ssl_hmac_md5(g_reconnect_random, sizeof(g_reconnect_random), g_client_random, SEC_RANDOM_SIZE, security_verifier); - out_uint8a(s, security_verifier, sizeof(security_verifier)); - } else { - out_uint16_le(s, 0); /* cbAutoReconnectLen */ - } - - } - s_mark_end(s); - sec_send(s, sec_flags); -} - -/* Establish a connection up to the RDP layer */ -BOOL rdp_connect(char *server, uint32 flags, char *domain, char *login, char *password, char *command, char *directory, BOOL reconnect) { - - if (!sec_connect(server, login, reconnect)) - return False; - - rdp_send_logon_info(flags, domain, login, password, command, directory); - return True; -} - -int32_t start_rdp(int32_t s, char *ip, int32_t port, unsigned char options, char *miscptr, FILE * fp) { +#include +freerdp * instance; +BOOL rdp_connect(char *server, int32_t port, char *domain, char *login, char *password) { + instance->settings->Username = login; + instance->settings->Password = password; + int32_t ret = 0; + instance->settings->IgnoreCertificate = TRUE; + instance->settings->AuthenticationOnly = TRUE; + instance->settings->ServerHostname = server; + instance->settings->ServerPort = port; + instance->settings->Domain = domain; + ret = freerdp_connect(instance); + return ret==1? True : False; +} + +/* Client program */ +int32_t start_rdp(char *ip, int32_t port, unsigned char options, char *miscptr, FILE * fp) { char *empty = ""; char *login, *pass; char server[64]; char domain[256]; - char shell[256]; - char directory[256]; - BOOL deactivated = 0; - uint32 flags, ext_disc_reason = 0; - - flags = RDP_LOGON_NORMAL; - flags |= RDP_LOGON_AUTO; - - os_version = 0; - g_redirect = False; - g_redirect_flags = 0; - login_result = LOGIN_UNKN; - - shell[0] = directory[0] = 0; + + BOOL login_result = False; memset(domain, 0, sizeof(domain)); if (strlen(login = hydra_get_next_login()) == 0) @@ -2465,27 +80,28 @@ int32_t start_rdp(int32_t s, char *ip, int32_t port, unsigned char options, char domain[sizeof(domain) - 1] = 0; } - if (!rdp_connect(server, flags, domain, login, pass, shell, directory, g_redirect)) + login_result = rdp_connect(server, port, domain, login, pass); + + int x = 0; + x = freerdp_get_last_error(instance->context); + int err = freerdp_get_last_error(instance->context); + if ( err != 0 && err != 0x00020014) { //0x00020014 == logon failed return 3; + } - rdp_main_loop(&deactivated, &ext_disc_reason); - - if (login_result == LOGIN_SUCC) { + if (login_result == True) { hydra_report_found_host(port, ip, "rdp", fp); hydra_completed_pair_found(); } else { hydra_completed_pair(); } - rdp_disconnect(); - if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0) return 2; return 1; } -/* Client program */ void service_rdp(char *ip, int32_t sp, unsigned char options, char *miscptr, FILE * fp, int32_t port, char *hostname) { int32_t run = 1, next_run = 1; int32_t myport = PORT_RDP; @@ -2496,25 +112,18 @@ void service_rdp(char *ip, int32_t sp, unsigned char options, char *miscptr, FIL hydra_register_socket(sp); if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0) return; - while (1) { next_run = 0; switch (run) { case 1: /* run the cracking function */ - rdesktop_reset_state(); - g_sock = hydra_connect_tcp(ip, myport); - if (g_sock < 0) { - hydra_report(stderr, "[ERROR] Child with pid %d terminating, can not connect\n", (int32_t) getpid()); - hydra_child_exit(1); - } - next_run = start_rdp(g_sock, ip, port, options, miscptr, fp); + next_run = start_rdp(ip, port, options, miscptr, fp); break; case 2: /* clean exit */ - if (g_sock >= 0) - rdp_disconnect(); + freerdp_disconnect(instance); hydra_child_exit(0); return; case 3: /* connection error case */ + hydra_report(stderr, "[ERROR] freerdp: %s\n", freerdp_get_last_error_string(freerdp_get_last_error(instance->context))); hydra_child_exit(1); return; default: @@ -2525,717 +134,6 @@ void service_rdp(char *ip, int32_t sp, unsigned char options, char *miscptr, FIL } } -/* Generate a 32-byte random for the secure transport code. */ -void generate_random(uint8 * random) { - struct stat st; - struct tms tmsbuf; - SSL_MD5 md5; - uint32 *r; - int32_t fd, n; - - /* If we have a kernel random device, try that first */ - if (((fd = open("/dev/urandom", O_RDONLY)) != -1) - || ((fd = open("/dev/random", O_RDONLY)) != -1)) { - n = read(fd, random, 32); - close(fd); - if (n == 32) - return; - } - - r = (uint32 *) random; - r[0] = (getpid()) | (getppid() << 16); - r[1] = (getuid()) | (getgid() << 16); - r[2] = times(&tmsbuf); /* system uptime (clocks) */ - gettimeofday((struct timeval *) &r[3], NULL); /* sec and usec */ - stat("/tmp", &st); - r[5] = st.st_atime; - r[6] = st.st_mtime; - r[7] = st.st_ctime; - - /* Hash both halves with MD5 to obscure possible patterns */ - ssl_md5_init(&md5); - ssl_md5_update(&md5, random, 16); - ssl_md5_final(&md5, random); - ssl_md5_update(&md5, random + 16, 16); - ssl_md5_final(&md5, random + 16); -} - -/* malloc; exit if out of memory */ -void *xmalloc(int32_t size) { - void *mem = malloc(size); - - if (mem == NULL) { - error("xmalloc %d\n", size); - return NULL; - } - return mem; -} - -/* strdup */ -char *xstrdup(const char *s) { - char *mem = strdup(s); - - if (mem == NULL) { - perror("strdup"); - return NULL; - } - return mem; -} - -/* realloc; exit if out of memory */ -void *xrealloc(void *oldmem, size_t size) { - void *mem; - - if (size == 0) - size = 1; -//printf("---? %p %d\n", oldmem, size); - mem = realloc(oldmem, size); -//printf("---!\n"); - if (mem == NULL) { - error("xrealloc %ld\n", size); - return NULL; - } - return mem; -} - -/* report an error */ -void error(char *format, ...) { - va_list ap; - - fprintf(stderr, "[ERROR]: "); - - va_start(ap, format); - hydra_report(stderr, format, ap); - va_end(ap); -} - -/* report a warning */ -void warning(char *format, ...) { - if (verbose) { - va_list ap; - - fprintf(stderr, "[VERBOSE]: "); - - va_start(ap, format); - hydra_report(stderr, format, ap); - va_end(ap); - } -} - -/* report an unimplemented protocol feature */ -void unimpl(char *format, ...) { - if (debug) { - va_list ap; - - fprintf(stderr, "[DEBUG] not implemented: "); - - va_start(ap, format); - hydra_report(stderr, format, ap); - va_end(ap); - } -} - -/* produce a hex dump */ -void hexdump(unsigned char *p, uint32_t len) { - unsigned char *line = p; - int32_t i, thisline, offset = 0; - - while (offset < len) { - printf("%04x ", offset); - thisline = len - offset; - if (thisline > 16) - thisline = 16; - - for (i = 0; i < thisline; i++) - printf("%02x ", line[i]); - - for (; i < 16; i++) - printf(" "); - - for (i = 0; i < thisline; i++) - printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.'); - - printf("\n"); - offset += thisline; - line += thisline; - } -} - -/* Initialise an RDP data packet */ -static STREAM rdp_init_data(int32_t maxlen) { - STREAM s; - - s = sec_init(g_encryption ? SEC_ENCRYPT : 0, maxlen + 18); - s_push_layer(s, rdp_hdr, 18); - - return s; -} - -/* Send an RDP data packet */ -static void rdp_send_data(STREAM s, uint8 data_pdu_type) { - uint16 length; - - s_pop_layer(s, rdp_hdr); - length = s->end - s->p; - - out_uint16_le(s, length); - out_uint16_le(s, (RDP_PDU_DATA | 0x10)); - out_uint16_le(s, (g_mcs_userid + 1001)); - - out_uint32_le(s, g_rdp_shareid); - out_uint8(s, 0); /* pad */ - out_uint8(s, 1); /* streamid */ - out_uint16_le(s, (length - 14)); - out_uint8(s, data_pdu_type); - out_uint8(s, 0); /* compress_type */ - out_uint16(s, 0); /* compress_len */ - - sec_send(s, g_encryption ? SEC_ENCRYPT : 0); -} - -/* Input a string in Unicode - * - * Returns str_len of string - */ -int32_t rdp_in_unistr(STREAM s, char *string, int32_t str_size, int32_t in_len) { - int32_t i = 0; - int32_t len = in_len / 2; - int32_t rem = 0; - - if (len > str_size - 1) { - warning("server sent an unexpectedly long string, truncating\n"); - len = str_size - 1; - rem = in_len - 2 * len; - } - - while (i < len) { - in_uint8a(s, &string[i++], 1); - in_uint8s(s, 1); - } - - in_uint8s(s, rem); - string[len] = 0; - return len; -} - -/* Send a control PDU */ -static void rdp_send_control(uint16 action) { - STREAM s; - - s = rdp_init_data(8); - - out_uint16_le(s, action); - out_uint16(s, 0); /* userid */ - out_uint32(s, 0); /* control id */ - - s_mark_end(s); - rdp_send_data(s, RDP_DATA_PDU_CONTROL); -} - -/* Send a synchronisation PDU */ -static void rdp_send_synchronise(void) { - STREAM s; - - s = rdp_init_data(4); - out_uint16_le(s, 1); /* type */ - out_uint16_le(s, 1002); - - s_mark_end(s); - rdp_send_data(s, RDP_DATA_PDU_SYNCHRONISE); -} - -/* Send a single input event */ -void rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, uint16 param1, uint16 param2) { - STREAM s; - - switch (message_type) { - case RDP_INPUT_MOUSE: - rdp_send_fast_input_mouse(time, device_flags, param1, param2); - break; - case RDP_INPUT_SCANCODE: - rdp_send_fast_input_kbd(time, device_flags, param1); - break; - default: - s = rdp_init_data(16); - out_uint16_le(s, 1); /* number of events */ - out_uint16(s, 0); /* pad */ - out_uint32_le(s, time); - out_uint16_le(s, message_type); - out_uint16_le(s, device_flags); - out_uint16_le(s, param1); - out_uint16_le(s, param2); - s_mark_end(s); - rdp_send_data(s, RDP_DATA_PDU_INPUT); - } -} - -/* Send an (empty) font information PDU */ -static void rdp_send_fonts(uint16 seq) { - STREAM s; - - s = rdp_init_data(8); - - out_uint16(s, 0); /* number of fonts */ - out_uint16_le(s, 0); /* pad? */ - out_uint16_le(s, seq); /* unknown */ - out_uint16_le(s, 0x32); /* entry size */ - - s_mark_end(s); - rdp_send_data(s, RDP_DATA_PDU_FONT2); -} - -/* Output general capability set */ -static void rdp_out_general_caps(STREAM s) { - out_uint16_le(s, RDP_CAPSET_GENERAL); - out_uint16_le(s, RDP_CAPLEN_GENERAL); - out_uint16_le(s, 1); /* OS major type */ - out_uint16_le(s, 3); /* OS minor type */ - out_uint16_le(s, 0x200); /* Protocol version */ - out_uint16(s, 0); /* Pad */ - out_uint16(s, 0); /* Compression types */ - out_uint16_le(s, g_use_rdp5 ? 0x40d : 0); - /* Pad, according to T.128. 0x40d seems to - trigger - the server to start sending RDP5 packets. - However, the value is 0x1d04 with W2KTSK and - NT4MS. Hmm.. Anyway, thankyou, Microsoft, - for sending such information in a padding - field.. */ - out_uint16(s, 0); /* Update capability */ - out_uint16(s, 0); /* Remote unshare capability */ - out_uint16(s, 0); /* Compression level */ - out_uint16(s, 0); /* Pad */ -} - -/* Output bitmap capability set */ -static void rdp_out_bitmap_caps(STREAM s) { - out_uint16_le(s, RDP_CAPSET_BITMAP); - out_uint16_le(s, RDP_CAPLEN_BITMAP); - out_uint16_le(s, g_server_depth); /* Preferred colour depth */ - out_uint16_le(s, 1); /* Receive 1 BPP */ - out_uint16_le(s, 1); /* Receive 4 BPP */ - out_uint16_le(s, 1); /* Receive 8 BPP */ - out_uint16_le(s, 800); /* Desktop width */ - out_uint16_le(s, 600); /* Desktop height */ - out_uint16(s, 0); /* Pad */ - out_uint16(s, 1); /* Allow resize */ - out_uint16_le(s, g_bitmap_compression ? 1 : 0); /* Support compression */ - out_uint16(s, 0); /* Unknown */ - out_uint16_le(s, 1); /* Unknown */ - out_uint16(s, 0); /* Pad */ -} - -/* Output order capability set */ -static void rdp_out_order_caps(STREAM s) { - uint8 order_caps[32]; - - memset(order_caps, 0, 32); - order_caps[0] = 1; /* dest blt */ - order_caps[1] = 1; /* pat blt */ - order_caps[2] = 1; /* screen blt */ - order_caps[3] = (g_bitmap_cache ? 1 : 0); /* memblt */ - order_caps[4] = 0; /* triblt */ - order_caps[8] = 1; /* line */ - order_caps[9] = 1; /* line */ - order_caps[10] = 1; /* rect */ - order_caps[11] = (g_desktop_save ? 1 : 0); /* desksave */ - order_caps[13] = 1; /* memblt */ - order_caps[14] = 1; /* triblt */ - order_caps[20] = 1; /* polygon */ - order_caps[21] = 1; /* polygon2 */ - order_caps[22] = 1; /* polyline */ - order_caps[25] = 1; /* ellipse */ - order_caps[26] = 1; /* ellipse2 */ - order_caps[27] = 1; /* text2 */ - out_uint16_le(s, RDP_CAPSET_ORDER); - out_uint16_le(s, RDP_CAPLEN_ORDER); - - out_uint8s(s, 20); /* Terminal desc, pad */ - out_uint16_le(s, 1); /* Cache X granularity */ - out_uint16_le(s, 20); /* Cache Y granularity */ - out_uint16(s, 0); /* Pad */ - out_uint16_le(s, 1); /* Max order level */ - out_uint16_le(s, 0x147); /* Number of fonts */ - out_uint16_le(s, 0x2a); /* Capability flags */ - out_uint8p(s, order_caps, 32); /* Orders supported */ - out_uint16_le(s, 0x6a1); /* Text capability flags */ - out_uint8s(s, 6); /* Pad */ - out_uint32_le(s, g_desktop_save == False ? 0 : 0x38400); /* Desktop cache size */ - out_uint32(s, 0); /* Unknown */ - out_uint32_le(s, 0x4e4); /* Unknown */ -} - -/* Output bitmap cache capability set */ -static void rdp_out_bmpcache_caps(STREAM s) { - int32_t Bpp; - - out_uint16_le(s, RDP_CAPSET_BMPCACHE); - out_uint16_le(s, RDP_CAPLEN_BMPCACHE); - Bpp = (g_server_depth + 7) / 8; /* bytes per pixel */ - out_uint8s(s, 24); /* unused */ - out_uint16_le(s, 0x258); /* entries */ - out_uint16_le(s, 0x100 * Bpp); /* max cell size */ - out_uint16_le(s, 0x12c); /* entries */ - out_uint16_le(s, 0x400 * Bpp); /* max cell size */ - out_uint16_le(s, 0x106); /* entries */ - out_uint16_le(s, 0x1000 * Bpp); /* max cell size */ -} - -/* Output bitmap cache v2 capability set */ -static void rdp_out_bmpcache2_caps(STREAM s) { - out_uint16_le(s, RDP_CAPSET_BMPCACHE2); - out_uint16_le(s, RDP_CAPLEN_BMPCACHE2); - out_uint16_le(s, g_bitmap_cache_persist_enable ? 2 : 0); /* version */ - out_uint16_be(s, 3); /* number of caches in this set */ - - /* max cell size for cache 0 is 16x16, 1 = 32x32, 2 = 64x64, etc */ - out_uint32_le(s, BMPCACHE2_C0_CELLS); - out_uint32_le(s, BMPCACHE2_C1_CELLS); - out_uint32_le(s, BMPCACHE2_C2_CELLS); - out_uint8s(s, 20); /* other bitmap caches not used */ -} - -/* Output control capability set */ -static void rdp_out_control_caps(STREAM s) { - out_uint16_le(s, RDP_CAPSET_CONTROL); - out_uint16_le(s, RDP_CAPLEN_CONTROL); - out_uint16(s, 0); /* Control capabilities */ - out_uint16(s, 0); /* Remote detach */ - out_uint16_le(s, 2); /* Control interest */ - out_uint16_le(s, 2); /* Detach interest */ -} - -/* Output activation capability set */ -static void rdp_out_activate_caps(STREAM s) { - out_uint16_le(s, RDP_CAPSET_ACTIVATE); - out_uint16_le(s, RDP_CAPLEN_ACTIVATE); - out_uint16(s, 0); /* Help key */ - out_uint16(s, 0); /* Help index key */ - out_uint16(s, 0); /* Extended help key */ - out_uint16(s, 0); /* Window activate */ -} - -/* Output pointer capability set */ -static void rdp_out_pointer_caps(STREAM s) { - out_uint16_le(s, RDP_CAPSET_POINTER); - out_uint16_le(s, RDP_CAPLEN_POINTER); - out_uint16(s, 0); /* Colour pointer */ - out_uint16_le(s, 20); /* Cache size */ -} - -/* Output new pointer capability set */ -static void rdp_out_newpointer_caps(STREAM s) { - out_uint16_le(s, RDP_CAPSET_POINTER); - out_uint16_le(s, RDP_CAPLEN_NEWPOINTER); - out_uint16_le(s, 1); /* Colour pointer */ - out_uint16_le(s, 20); /* Cache size */ - out_uint16_le(s, 20); /* Cache size for new pointers */ -} - -/* Output share capability set */ -static void rdp_out_share_caps(STREAM s) { - out_uint16_le(s, RDP_CAPSET_SHARE); - out_uint16_le(s, RDP_CAPLEN_SHARE); - out_uint16(s, 0); /* userid */ - out_uint16(s, 0); /* pad */ -} - -/* Output colour cache capability set */ -static void rdp_out_colcache_caps(STREAM s) { - out_uint16_le(s, RDP_CAPSET_COLCACHE); - out_uint16_le(s, RDP_CAPLEN_COLCACHE); - out_uint16_le(s, 6); /* cache size */ - out_uint16(s, 0); /* pad */ -} - -/* Output brush cache capability set */ -static void rdp_out_brushcache_caps(STREAM s) { - out_uint16_le(s, RDP_CAPSET_BRUSHCACHE); - out_uint16_le(s, RDP_CAPLEN_BRUSHCACHE); - out_uint32_le(s, 1); /* cache type */ -} - -static uint8 caps_0x0d[] = { - 0x01, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 -}; - -static uint8 caps_0x0c[] = { 0x01, 0x00, 0x00, 0x00 }; - -static uint8 caps_0x0e[] = { 0x01, 0x00, 0x00, 0x00 }; - -static uint8 caps_0x10[] = { - 0xFE, 0x00, 0x04, 0x00, 0xFE, 0x00, 0x04, 0x00, - 0xFE, 0x00, 0x08, 0x00, 0xFE, 0x00, 0x08, 0x00, - 0xFE, 0x00, 0x10, 0x00, 0xFE, 0x00, 0x20, 0x00, - 0xFE, 0x00, 0x40, 0x00, 0xFE, 0x00, 0x80, 0x00, - 0xFE, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x08, - 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00 -}; - -/* Output unknown capability sets */ -static void rdp_out_unknown_caps(STREAM s, uint16 id, uint16 length, uint8 * caps) { - out_uint16_le(s, id); - out_uint16_le(s, length); - out_uint8p(s, caps, length - 4); -} - -#define RDP5_FLAG 0x0030 - -/* Send a confirm active PDU */ -static void rdp_send_confirm_active(void) { - STREAM s; - uint32 sec_flags = g_encryption ? (RDP5_FLAG | SEC_ENCRYPT) : RDP5_FLAG; - uint16 caplen = - RDP_CAPLEN_GENERAL + RDP_CAPLEN_BITMAP + RDP_CAPLEN_ORDER + - RDP_CAPLEN_COLCACHE + RDP_CAPLEN_ACTIVATE + RDP_CAPLEN_CONTROL + RDP_CAPLEN_SHARE + RDP_CAPLEN_BRUSHCACHE + 0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ + - 4 /* w2k fix, sessionid */ ; - - if (g_use_rdp5) { - caplen += RDP_CAPLEN_BMPCACHE2; - caplen += RDP_CAPLEN_NEWPOINTER; - } else { - caplen += RDP_CAPLEN_BMPCACHE; - caplen += RDP_CAPLEN_POINTER; - } - - s = sec_init(sec_flags, 6 + 14 + caplen + sizeof(RDP_SOURCE)); - - out_uint16_le(s, 2 + 14 + caplen + sizeof(RDP_SOURCE)); - out_uint16_le(s, (RDP_PDU_CONFIRM_ACTIVE | 0x10)); /* Version 1 */ - out_uint16_le(s, (g_mcs_userid + 1001)); - - out_uint32_le(s, g_rdp_shareid); - out_uint16_le(s, 0x3ea); /* userid */ - out_uint16_le(s, sizeof(RDP_SOURCE)); - out_uint16_le(s, caplen); - - out_uint8p(s, RDP_SOURCE, sizeof(RDP_SOURCE)); - out_uint16_le(s, 0xe); /* num_caps */ - out_uint8s(s, 2); /* pad */ - - rdp_out_general_caps(s); - rdp_out_bitmap_caps(s); - rdp_out_order_caps(s); - if (g_use_rdp5) { - rdp_out_bmpcache2_caps(s); - rdp_out_newpointer_caps(s); - } else { - rdp_out_bmpcache_caps(s); - rdp_out_pointer_caps(s); - } - - rdp_out_colcache_caps(s); - rdp_out_activate_caps(s); - rdp_out_control_caps(s); - rdp_out_share_caps(s); - rdp_out_brushcache_caps(s); - - rdp_out_unknown_caps(s, 0x0d, 0x58, caps_0x0d); /* CAPSTYPE_INPUT */ - rdp_out_unknown_caps(s, 0x0c, 0x08, caps_0x0c); /* CAPSTYPE_SOUND */ - rdp_out_unknown_caps(s, 0x0e, 0x08, caps_0x0e); /* CAPSTYPE_FONT */ - rdp_out_unknown_caps(s, 0x10, 0x34, caps_0x10); /* CAPSTYPE_GLYPHCACHE */ - - s_mark_end(s); - sec_send(s, sec_flags); -} - -/* Process a general capability set */ -static void rdp_process_general_caps(STREAM s) { - uint16 pad2octetsB; /* rdp5 flags? */ - - in_uint8s(s, 10); - in_uint16_le(s, pad2octetsB); - if (!pad2octetsB) - g_use_rdp5 = False; -} - -/* Process a bitmap capability set */ -static void rdp_process_bitmap_caps(STREAM s) { - uint16 width, height, depth; - - in_uint16_le(s, depth); - in_uint8s(s, 6); - in_uint16_le(s, width); - in_uint16_le(s, height); - DEBUG(("setting desktop size and depth to: %dx%dx%d\n", width, height, depth)); -} - -/* Process server capabilities */ -static void rdp_process_server_caps(STREAM s, uint16 length) { - int32_t n; - uint8 *next, *start; - uint16 ncapsets, capset_type, capset_length; - - start = s->p; - - in_uint16_le(s, ncapsets); - in_uint8s(s, 2); /* pad */ - - for (n = 0; n < ncapsets; n++) { - if (s->p > start + length) - return; - - in_uint16_le(s, capset_type); - in_uint16_le(s, capset_length); - - next = s->p + capset_length - 4; - - switch (capset_type) { - case RDP_CAPSET_GENERAL: - rdp_process_general_caps(s); - break; - - case RDP_CAPSET_BITMAP: - rdp_process_bitmap_caps(s); - break; - } - - s->p = next; - } -} - -/* Respond to a demand active PDU */ -static void process_demand_active(STREAM s) { - uint8 type; - uint16 len_src_descriptor, len_combined_caps; - - in_uint32_le(s, g_rdp_shareid); - in_uint16_le(s, len_src_descriptor); - in_uint16_le(s, len_combined_caps); - in_uint8s(s, len_src_descriptor); - - DEBUG(("DEMAND_ACTIVE(id=0x%x)\n", g_rdp_shareid)); - rdp_process_server_caps(s, len_combined_caps); - - rdp_send_confirm_active(); - rdp_send_synchronise(); - rdp_send_control(RDP_CTL_COOPERATE); - rdp_send_control(RDP_CTL_REQUEST_CONTROL); - rdp_recv(&type); /* RDP_PDU_SYNCHRONIZE */ - rdp_recv(&type); /* RDP_CTL_COOPERATE */ - rdp_recv(&type); /* RDP_CTL_GRANT_CONTROL */ - rdp_send_input(0, 0, 0, 0, 0); /* RDP_INPUT_SYNCHRONIZE */ - // here? XXX TODO BUGFIX - - if (g_use_rdp5) { - rdp_send_fonts(3); - } else { - rdp_send_fonts(1); - rdp_send_fonts(2); - } - - rdp_recv(&type); /* RDP_PDU_UNKNOWN 0x28 (Fonts?) */ - reset_order_state(); -} - -/* Process an update PDU */ -static void process_update_pdu(STREAM s) { - uint16 update_type, count; - - in_uint16_le(s, update_type); - - //ui_begin_update(); - switch (update_type) { - case RDP_UPDATE_ORDERS: - in_uint8s(s, 2); /* pad */ - in_uint16_le(s, count); - in_uint8s(s, 2); /* pad */ - process_orders(s, count); - break; - - case RDP_UPDATE_BITMAP: - //process_bitmap_updates(s); - break; - - case RDP_UPDATE_PALETTE: - //process_palette(s); - break; - - case RDP_UPDATE_SYNCHRONIZE: - break; - - default: - unimpl("update %d\n", update_type); - } -} - - -/* Process a disconnect PDU */ -void process_disconnect_pdu(STREAM s, uint32 * ext_disc_reason) { - in_uint32_le(s, *ext_disc_reason); - - DEBUG(("Received disconnect PDU\n")); -} - -/* Process data PDU */ -static BOOL process_data_pdu(STREAM s, uint32 * ext_disc_reason) { - uint8 data_pdu_type; - //uint8 ctype; - uint16 clen; - //uint32 len; - - in_uint8s(s, 6); /* shareid, pad, streamid */ - //in_uint16_le(s, len); - in_uint8(s, data_pdu_type); - //in_uint8(s, ctype); - in_uint16_le(s, clen); - clen -= 18; - - switch (data_pdu_type) { - case RDP_DATA_PDU_UPDATE: - process_update_pdu(s); - break; - - case RDP_DATA_PDU_CONTROL: - DEBUG(("Received Control PDU\n")); - break; - - case RDP_DATA_PDU_SYNCHRONISE: - DEBUG(("Received Sync PDU\n")); - break; - - case RDP_DATA_PDU_POINTER: - //process_pointer_pdu(s); - break; - - case RDP_DATA_PDU_BELL: - //ui_bell(); - break; - - case RDP_DATA_PDU_LOGON: - DEBUG(("Received Logon PDU\n")); - /* User logged on */ - login_result = LOGIN_SUCC; - return 1; - break; - - case RDP_DATA_PDU_DISCONNECT: - process_disconnect_pdu(s, ext_disc_reason); - - /* We used to return true and disconnect immediately here, but - * Windows Vista sends a disconnect PDU with reason 0 when - * reconnecting to a disconnected session, and MSTSC doesn't - * drop the connection. I think we should just save the status. - */ - break; - - default: - unimpl("data PDU %d\n", data_pdu_type); - } - return False; -} -#endif - int32_t service_rdp_init(char *ip, int32_t sp, unsigned char options, char *miscptr, FILE * fp, int32_t port, char *hostname) { // called before the childrens are forked off, so this is the function // which should be filled if initial connections and service setup has to be @@ -3247,9 +145,17 @@ int32_t service_rdp_init(char *ip, int32_t sp, unsigned char options, char *misc // 0 all OK // -1 error, hydra will exit, so print a good error message here + // Disable freerdp output + wLog* root = WLog_GetRoot(); + WLog_SetStringLogLevel(root, "OFF"); + + // Init freerdp instance + instance = freerdp_new(); + freerdp_context_new(instance); return 0; } void usage_rdp(const char* service) { printf("Module rdp is optionally taking the windows domain name.\n" "For example:\nhydra rdp://192.168.0.1/firstdomainname -l john -p doe\n\n"); } +#endif \ No newline at end of file diff --git a/hydra.c b/hydra.c index 0f9de0d..1f27988 100644 --- a/hydra.c +++ b/hydra.c @@ -110,6 +110,8 @@ extern void service_oracle_sid(char *ip, int32_t sp, unsigned char options, char extern int32_t service_oracle_sid_init(char *ip, int32_t sp, unsigned char options, char *miscptr, FILE * fp, int32_t port, char *hostname); extern void service_sip(char *ip, int32_t sp, unsigned char options, char *miscptr, FILE * fp, int32_t port, char *hostname); extern int32_t service_sip_init(char *ip, int32_t sp, unsigned char options, char *miscptr, FILE * fp, int32_t port, char *hostname); +#endif +#ifdef LIBFREERDP2 extern void service_rdp(char *ip, int32_t sp, unsigned char options, char *miscptr, FILE * fp, int32_t port, char *hostname); extern int32_t service_rdp_init(char *ip, int32_t sp, unsigned char options, char *miscptr, FILE * fp, int32_t port, char *hostname); #endif @@ -418,7 +420,7 @@ SERVICE3("mongodb", mongodb), #endif SERVICE(redis), SERVICE(rexec), -#ifdef LIBOPENSSL +#ifdef LIBFREERDP2 SERVICE3("rdp", rdp), #endif SERVICE(rlogin), @@ -2150,8 +2152,6 @@ int main(int argc, char *argv[]) { SERVICES = hydra_string_replace(SERVICES, "[-{cram|digest}md5]", ""); // for sip SERVICES = hydra_string_replace(SERVICES, " sip", ""); - // for rdp - SERVICES = hydra_string_replace(SERVICES, " rdp", ""); // for oracle-listener SERVICES = hydra_string_replace(SERVICES, " oracle-listener", ""); // general @@ -2160,6 +2160,12 @@ int main(int argc, char *argv[]) { SERVICES = hydra_string_replace(SERVICES, " oracle-sid", ""); strcat(unsupported, "SSL-services (ftps, sip, rdp, oracle-services, ...) "); #endif + +#ifndef LIBFREERDP2 + // for rdp + SERVICES = hydra_string_replace(SERVICES, " rdp", ""); +#endif + #ifndef HAVE_MATH_H if (strlen(unsupported) > 0) strcat(unsupported, "and "); @@ -2759,10 +2765,15 @@ int main(int argc, char *argv[]) { #endif } if ((strcmp(hydra_options.service, "smb") == 0) || (strcmp(hydra_options.service, "smbnt") == 0) || - (strcmp(hydra_options.service, "sip") == 0) || (strcmp(hydra_options.service, "rdp") == 0) || + (strcmp(hydra_options.service, "sip") == 0) || (strcmp(hydra_options.service, "oracle-listener") == 0) || (strcmp(hydra_options.service, "oracle-sid") == 0)) { #ifndef LIBOPENSSL bail("Compiled without OPENSSL support, module not available!"); +#endif + } + if (strcmp(hydra_options.service, "rdp") == 0){ +#ifndef LIBFREERDP2 + bail("Compiled without FREERDP2 support, module not available!"); #endif } if (strcmp(hydra_options.service, "pcnfs") == 0) { @@ -3061,17 +3072,16 @@ int main(int argc, char *argv[]) { if (strcmp(hydra_options.service, "irc") == 0) i = 1; if (strcmp(hydra_options.service, "rdp") == 0) { - //if (hydra_options.tasks > 4) - // fprintf(stderr, "[WARNING] rdp servers often don't like many connections, use -t 1 or -t 4 to reduce the number of parallel connections and -W 1 or -W 3 to wait between connection to allow the server to recover\n"); - //if (hydra_options.tasks > 4) { - // fprintf(stderr, "[INFO] Reduced number of tasks to 4 (rdp does not like many parallel connections)\n"); - // hydra_options.tasks = 4; - //} - //if (conwait == 0) - // hydra_options.conwait = conwait = 1; - //printf("[WARNING] the rdp module is currently reported to be unreliable, most likely against new Windows version. Please test, report - and if possible, fix.\n"); - printf("[ERROR] the rdp module does not support the current protocol, hence it is disabled. If you want to develop it, please contact vh@thc.org\n"); - exit(-1); + if (hydra_options.tasks > 4) + fprintf(stderr, "[WARNING] rdp servers often don't like many connections, use -t 1 or -t 4 to reduce the number of parallel connections and -W 1 or -W 3 to wait between connection to allow the server to recover\n"); + if (hydra_options.tasks > 4) { + fprintf(stderr, "[INFO] Reduced number of tasks to 4 (rdp does not like many parallel connections)\n"); + hydra_options.tasks = 4; + } + if (conwait == 0) + hydra_options.conwait = conwait = 1; + printf("[WARNING] the rdp module is experimental. Please test, report - and if possible, fix.\n"); + i = 1; } if (strcmp(hydra_options.service, "radmin2") == 0) { #ifdef HAVE_GCRYPT