WOWW: Add working decryption
This commit is contained in:
parent
e1b3796419
commit
92e62a74fd
|
@ -34,6 +34,8 @@
|
|||
|
||||
#include <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 */
|
||||
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_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;
|
||||
|
||||
/* Packets that do not have at least a u16 size field and a u16 opcode field are not valid. */
|
||||
#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 {
|
||||
SMSG_AUTH_CHALLENGE = 0x1EC,
|
||||
CMSG_AUTH_SESSION = 0x1ED,
|
||||
|
@ -67,6 +85,21 @@ static const value_string world_packet_strings[] = {
|
|||
{ 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
|
||||
dissect_woww(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
|
||||
void *data _U_)
|
||||
|
@ -95,7 +128,6 @@ dissect_woww(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
|
|||
if (tvb_captured_length(tvb) < 1)
|
||||
return 0;
|
||||
|
||||
|
||||
/*** COLUMN DATA ***/
|
||||
|
||||
/* 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);
|
||||
|
||||
// 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
|
||||
* information. */
|
||||
// We're indexing into another tvb
|
||||
offset = 0;
|
||||
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;
|
||||
|
||||
if (WOWW_SERVER_TO_CLIENT) {
|
||||
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) {
|
||||
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);
|
||||
|
||||
col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(opcode,
|
||||
world_packet_strings,
|
||||
"Encrypted Header"));
|
||||
|
||||
// Remember to go back to original tvb
|
||||
|
||||
return tvb_captured_length(tvb);
|
||||
}
|
||||
|
||||
|
@ -177,6 +274,7 @@ proto_register_woww(void)
|
|||
|
||||
prefs_register_protocol(proto_woww,
|
||||
NULL);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue