WOWW: Add working decryption
This commit is contained in:
parent
e1b3796419
commit
92e62a74fd
|
@ -34,6 +34,8 @@
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <epan/packet.h> /* Should be first Wireshark include (other than config.h) */
|
#include <epan/packet.h> /* Should be first Wireshark include (other than config.h) */
|
||||||
|
#include <epan/conversation.h> /* Should be first Wireshark include (other than config.h) */
|
||||||
|
#include <epan/wmem/wmem.h> /* Should be first Wireshark include (other than config.h) */
|
||||||
|
|
||||||
/* Prototypes */
|
/* Prototypes */
|
||||||
void proto_reg_handoff_woww(void);
|
void proto_reg_handoff_woww(void);
|
||||||
|
@ -51,11 +53,27 @@ static int hf_woww_opcode_field = -1;
|
||||||
#define WOWW_CLIENT_TO_SERVER pinfo->destport == WOWW_TCP_PORT
|
#define WOWW_CLIENT_TO_SERVER pinfo->destport == WOWW_TCP_PORT
|
||||||
#define WOWW_SERVER_TO_CLIENT pinfo->srcport == WOWW_TCP_PORT
|
#define WOWW_SERVER_TO_CLIENT pinfo->srcport == WOWW_TCP_PORT
|
||||||
|
|
||||||
|
#define WOWW_HEADER_ARRAY_ALLOC_SIZE 8
|
||||||
|
#define WOWW_SESSION_KEY_LENGTH 40
|
||||||
|
|
||||||
static gint ett_woww = -1;
|
static gint ett_woww = -1;
|
||||||
|
|
||||||
/* Packets that do not have at least a u16 size field and a u16 opcode field are not valid. */
|
/* Packets that do not have at least a u16 size field and a u16 opcode field are not valid. */
|
||||||
#define WOWW_MIN_LENGTH 4
|
#define WOWW_MIN_LENGTH 4
|
||||||
|
|
||||||
|
typedef struct WowwParticipant {
|
||||||
|
guint8 last_encrypted_value;
|
||||||
|
guint8 index;
|
||||||
|
gboolean unencrypted_packet_encountered;
|
||||||
|
} WowwParticipant_t;
|
||||||
|
|
||||||
|
typedef struct WowwConversation {
|
||||||
|
guint8 session_key[WOWW_SESSION_KEY_LENGTH];
|
||||||
|
wmem_tree_t* decrypted_headers;
|
||||||
|
WowwParticipant_t client;
|
||||||
|
WowwParticipant_t server;
|
||||||
|
} WowwConversation_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SMSG_AUTH_CHALLENGE = 0x1EC,
|
SMSG_AUTH_CHALLENGE = 0x1EC,
|
||||||
CMSG_AUTH_SESSION = 0x1ED,
|
CMSG_AUTH_SESSION = 0x1ED,
|
||||||
|
@ -67,6 +85,21 @@ static const value_string world_packet_strings[] = {
|
||||||
{ 0, NULL }
|
{ 0, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static guint8*
|
||||||
|
get_decrypted_header(const guint8 session_key[WOWW_SESSION_KEY_LENGTH], WowwParticipant_t* participant, const guint8* header, guint8 header_size) {
|
||||||
|
guint8* decrypted_header = wmem_alloc0(wmem_file_scope(), 8);
|
||||||
|
|
||||||
|
for (guint8 i = 0; i < header_size; i++) {
|
||||||
|
|
||||||
|
decrypted_header[i] = (header[i] - participant->last_encrypted_value) ^ session_key[participant->index];
|
||||||
|
|
||||||
|
participant->last_encrypted_value = header[i];
|
||||||
|
participant->index = (participant->index + 1) % WOWW_SESSION_KEY_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
return decrypted_header;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
dissect_woww(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
|
dissect_woww(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
|
||||||
void *data _U_)
|
void *data _U_)
|
||||||
|
@ -95,7 +128,6 @@ dissect_woww(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
|
||||||
if (tvb_captured_length(tvb) < 1)
|
if (tvb_captured_length(tvb) < 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
/*** COLUMN DATA ***/
|
/*** COLUMN DATA ***/
|
||||||
|
|
||||||
/* Set the Protocol column to the constant string of WOWW */
|
/* Set the Protocol column to the constant string of WOWW */
|
||||||
|
@ -114,28 +146,93 @@ dissect_woww(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
|
||||||
|
|
||||||
woww_tree = proto_item_add_subtree(ti, ett_woww);
|
woww_tree = proto_item_add_subtree(ti, ett_woww);
|
||||||
|
|
||||||
|
// Get conversation data
|
||||||
|
conversation_t* conv = find_or_create_conversation(pinfo);
|
||||||
|
WowwConversation_t* wowwConversation = (WowwConversation_t *)conversation_get_proto_data(conv,
|
||||||
|
proto_woww);
|
||||||
|
if (wowwConversation == NULL) {
|
||||||
|
// Assume that file scope means for the lifetime of the dissection
|
||||||
|
wowwConversation = (WowwConversation_t*) wmem_new0(wmem_file_scope(), WowwConversation_t);
|
||||||
|
conversation_add_proto_data(conv, proto_woww, wowwConversation);
|
||||||
|
wowwConversation->decrypted_headers = wmem_tree_new(wmem_file_scope());
|
||||||
|
|
||||||
|
guint8 session_key[WOWW_SESSION_KEY_LENGTH] = {0xfc, 0x97, 0x81, 0xd9, 0xde, 0xbb, 0xc5, 0x8b, 0x84, 0x57, 0x9a, 0xe3, 0xe3, 0xaa, 0x8c, 0x0c, 0x6b, 0xdc, 0x9c, 0xbc, 0x9f, 0x4b, 0x09, 0x35, 0xc5, 0xa9, 0x67, 0xb6, 0x1d, 0x0c, 0x8a, 0xca, 0x56, 0x73, 0xdc, 0xe5, 0x14, 0xcf, 0xd9, 0xdd};
|
||||||
|
memcpy(wowwConversation->session_key, session_key, WOWW_SESSION_KEY_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Isolate session key for packet
|
||||||
|
WowwParticipant_t* participant;
|
||||||
|
guint8 headerSize = 4;
|
||||||
|
|
||||||
|
if (WOWW_SERVER_TO_CLIENT) {
|
||||||
|
participant = &wowwConversation->server;
|
||||||
|
headerSize = 4;
|
||||||
|
} else {
|
||||||
|
participant = &wowwConversation->client;
|
||||||
|
headerSize = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
guint8* decrypted_header = NULL;
|
||||||
|
|
||||||
|
// First time we see this header, we need to decrypt it
|
||||||
|
if (!pinfo->fd->visited) {
|
||||||
|
guint8* header = wmem_alloc0(wmem_packet_scope(), WOWW_HEADER_ARRAY_ALLOC_SIZE);
|
||||||
|
|
||||||
|
// Read directly
|
||||||
|
for (int i = 0; i < headerSize; i++) {
|
||||||
|
header[i] = tvb_get_guint8(tvb, offset);
|
||||||
|
offset += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only first packet is unencrypted, all the rest are encrypted
|
||||||
|
if (participant->unencrypted_packet_encountered) {
|
||||||
|
// Do analysis
|
||||||
|
decrypted_header = get_decrypted_header(wowwConversation->session_key, participant, header, headerSize);
|
||||||
|
} else {
|
||||||
|
participant->unencrypted_packet_encountered = true;
|
||||||
|
|
||||||
|
decrypted_header = wmem_alloc0(wmem_file_scope(), WOWW_HEADER_ARRAY_ALLOC_SIZE);
|
||||||
|
memcpy(decrypted_header, header, headerSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to hashmap
|
||||||
|
wmem_tree_insert32(wowwConversation->decrypted_headers, pinfo->num, decrypted_header);
|
||||||
|
}
|
||||||
|
// Seen header before, no need to analyze again
|
||||||
|
else {
|
||||||
|
decrypted_header = wmem_tree_lookup32(wowwConversation->decrypted_headers, pinfo->num);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to tree
|
||||||
|
tvbuff_t *next_tvb = tvb_new_child_real_data(tvb, decrypted_header, headerSize, headerSize);
|
||||||
|
add_new_data_source(pinfo, next_tvb, "Decrypted Header");
|
||||||
|
|
||||||
/* Add an item to the subtree, see section 1.5 of README.dissector for more
|
/* Add an item to the subtree, see section 1.5 of README.dissector for more
|
||||||
* information. */
|
* information. */
|
||||||
|
// We're indexing into another tvb
|
||||||
|
offset = 0;
|
||||||
len = 2;
|
len = 2;
|
||||||
proto_tree_add_item(woww_tree, hf_woww_size_field, tvb,
|
proto_tree_add_item(woww_tree, hf_woww_size_field, next_tvb,
|
||||||
offset, len, ENC_BIG_ENDIAN);
|
offset, len, ENC_BIG_ENDIAN);
|
||||||
offset += len;
|
offset += len;
|
||||||
|
|
||||||
if (WOWW_SERVER_TO_CLIENT) {
|
if (WOWW_SERVER_TO_CLIENT) {
|
||||||
len = 2;
|
len = 2;
|
||||||
opcode = tvb_get_guint16(tvb, offset, ENC_LITTLE_ENDIAN);
|
opcode = tvb_get_guint16(next_tvb, offset, ENC_LITTLE_ENDIAN);
|
||||||
} else if (WOWW_CLIENT_TO_SERVER) {
|
} else if (WOWW_CLIENT_TO_SERVER) {
|
||||||
len = 4;
|
len = 4;
|
||||||
opcode = tvb_get_guint32(tvb, offset, ENC_LITTLE_ENDIAN);
|
opcode = tvb_get_guint32(next_tvb, offset, ENC_LITTLE_ENDIAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
proto_tree_add_item(woww_tree, hf_woww_opcode_field, tvb,
|
proto_tree_add_item(woww_tree, hf_woww_opcode_field, next_tvb,
|
||||||
offset, len, ENC_LITTLE_ENDIAN);
|
offset, len, ENC_LITTLE_ENDIAN);
|
||||||
|
|
||||||
col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(opcode,
|
col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(opcode,
|
||||||
world_packet_strings,
|
world_packet_strings,
|
||||||
"Encrypted Header"));
|
"Encrypted Header"));
|
||||||
|
|
||||||
|
// Remember to go back to original tvb
|
||||||
|
|
||||||
return tvb_captured_length(tvb);
|
return tvb_captured_length(tvb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,6 +274,7 @@ proto_register_woww(void)
|
||||||
|
|
||||||
prefs_register_protocol(proto_woww,
|
prefs_register_protocol(proto_woww,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue