mirror of
https://github.com/zeek/zeek.git
synced 2025-10-04 15:48:19 +00:00
Add RDP over UDP analyzer
This commit is contained in:
parent
c42ebfa1cf
commit
60644bc85f
15 changed files with 512 additions and 7 deletions
|
@ -10,3 +10,12 @@ signature dpd_rdp_server {
|
||||||
ip-proto == tcp
|
ip-proto == tcp
|
||||||
payload /(.{5}\xd0|.*McDn)/
|
payload /(.{5}\xd0|.*McDn)/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signature dpd_rdpeudp_syn {
|
||||||
|
ip-proto == udp
|
||||||
|
payload-size <= 1232
|
||||||
|
payload-size >= 1132
|
||||||
|
payload /^\xff{4}.{2}.{1}\x01/
|
||||||
|
enable "rdpeudp"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,13 +85,15 @@ redef record connection += {
|
||||||
rdp: Info &optional;
|
rdp: Info &optional;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ports = { 3389/tcp };
|
const rdp_ports = { 3389/tcp };
|
||||||
redef likely_server_ports += { ports };
|
const rdpeudp_ports = { 3389/udp };
|
||||||
|
redef likely_server_ports += { rdp_ports, rdpeudp_ports };
|
||||||
|
|
||||||
event zeek_init() &priority=5
|
event zeek_init() &priority=5
|
||||||
{
|
{
|
||||||
Log::create_stream(RDP::LOG, [$columns=RDP::Info, $ev=log_rdp, $path="rdp"]);
|
Log::create_stream(RDP::LOG, [$columns=RDP::Info, $ev=log_rdp, $path="rdp"]);
|
||||||
Analyzer::register_for_ports(Analyzer::ANALYZER_RDP, ports);
|
Analyzer::register_for_ports(Analyzer::ANALYZER_RDP, rdp_ports);
|
||||||
|
Analyzer::register_for_ports(Analyzer::ANALYZER_RDP, rdpeudp_ports);
|
||||||
}
|
}
|
||||||
|
|
||||||
function write_log(c: connection)
|
function write_log(c: connection)
|
||||||
|
|
|
@ -3,8 +3,9 @@ include(ZeekPlugin)
|
||||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
zeek_plugin_begin(Zeek RDP)
|
zeek_plugin_begin(Zeek RDP)
|
||||||
zeek_plugin_cc(RDP.cc Plugin.cc)
|
zeek_plugin_cc(RDPEUDP.cc RDP.cc Plugin.cc)
|
||||||
zeek_plugin_bif(events.bif)
|
zeek_plugin_bif(events.bif)
|
||||||
zeek_plugin_bif(types.bif)
|
zeek_plugin_bif(types.bif)
|
||||||
zeek_plugin_pac(rdp.pac rdp-analyzer.pac rdp-protocol.pac ../asn1/asn1.pac)
|
zeek_plugin_pac(rdp.pac rdp-analyzer.pac rdp-protocol.pac ../asn1/asn1.pac)
|
||||||
|
zeek_plugin_pac(rdpeudp.pac rdpeudp-analyzer.pac rdpeudp-protocol.pac)
|
||||||
zeek_plugin_end()
|
zeek_plugin_end()
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "RDP.h"
|
#include "RDP.h"
|
||||||
|
#include "RDPEUDP.h"
|
||||||
#include "plugin/Plugin.h"
|
#include "plugin/Plugin.h"
|
||||||
#include "analyzer/Component.h"
|
#include "analyzer/Component.h"
|
||||||
|
|
||||||
|
@ -10,6 +11,7 @@ public:
|
||||||
plugin::Configuration Configure() override
|
plugin::Configuration Configure() override
|
||||||
{
|
{
|
||||||
AddComponent(new ::analyzer::Component("RDP", ::analyzer::rdp::RDP_Analyzer::InstantiateAnalyzer));
|
AddComponent(new ::analyzer::Component("RDP", ::analyzer::rdp::RDP_Analyzer::InstantiateAnalyzer));
|
||||||
|
AddComponent(new ::analyzer::Component("RDPEUDP", ::analyzer::rdpeudp::RDP_Analyzer::InstantiateAnalyzer));
|
||||||
|
|
||||||
plugin::Configuration config;
|
plugin::Configuration config;
|
||||||
config.name = "Zeek::RDP";
|
config.name = "Zeek::RDP";
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "events.bif.h"
|
#include "events.bif.h"
|
||||||
|
|
||||||
|
|
||||||
#include "analyzer/protocol/tcp/TCP.h"
|
#include "analyzer/protocol/tcp/TCP.h"
|
||||||
#include "analyzer/protocol/pia/PIA.h"
|
#include "analyzer/protocol/pia/PIA.h"
|
||||||
|
|
||||||
#include "rdp_pac.h"
|
#include "rdp_pac.h"
|
||||||
|
|
||||||
namespace analyzer { namespace rdp {
|
namespace analyzer { namespace rdp {
|
||||||
|
|
37
src/analyzer/protocol/rdp/RDPEUDP.cc
Normal file
37
src/analyzer/protocol/rdp/RDPEUDP.cc
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#include "RDPEUDP.h"
|
||||||
|
#include "Reporter.h"
|
||||||
|
#include "events.bif.h"
|
||||||
|
#include "rdpeudp_pac.h"
|
||||||
|
|
||||||
|
using namespace analyzer::rdpeudp;
|
||||||
|
|
||||||
|
RDP_Analyzer::RDP_Analyzer(Connection* c)
|
||||||
|
: analyzer::Analyzer("RDPEUDP", c)
|
||||||
|
{
|
||||||
|
interp = new binpac::RDPEUDP::RDPEUDP_Conn(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
RDP_Analyzer::~RDP_Analyzer()
|
||||||
|
{
|
||||||
|
delete interp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RDP_Analyzer::Done()
|
||||||
|
{
|
||||||
|
Analyzer::Done();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RDP_Analyzer::DeliverPacket(int len, const u_char* data, bool orig,
|
||||||
|
uint64_t seq, const IP_Hdr* ip, int caplen)
|
||||||
|
{
|
||||||
|
Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
interp->NewData(orig, data, data + len);
|
||||||
|
}
|
||||||
|
catch ( const binpac::Exception& e )
|
||||||
|
{
|
||||||
|
ProtocolViolation(fmt("Binpac exception: %s", e.c_msg()));
|
||||||
|
}
|
||||||
|
}
|
24
src/analyzer/protocol/rdp/RDPEUDP.h
Normal file
24
src/analyzer/protocol/rdp/RDPEUDP.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "events.bif.h"
|
||||||
|
#include "analyzer/protocol/udp/UDP.h"
|
||||||
|
#include "rdpeudp_pac.h"
|
||||||
|
|
||||||
|
namespace analyzer { namespace rdpeudp {
|
||||||
|
class RDP_Analyzer : public analyzer::Analyzer {
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit RDP_Analyzer(Connection* conn);
|
||||||
|
~RDP_Analyzer() override;
|
||||||
|
|
||||||
|
void Done() override;
|
||||||
|
void DeliverPacket(int len, const u_char* data, bool orig,
|
||||||
|
uint64_t seq, const IP_Hdr* ip, int caplen) override;
|
||||||
|
static analyzer::Analyzer* InstantiateAnalyzer(Connection* conn)
|
||||||
|
{ return new RDP_Analyzer(conn); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
binpac::RDPEUDP::RDPEUDP_Conn* interp;
|
||||||
|
};
|
||||||
|
|
||||||
|
} }
|
|
@ -1,3 +1,31 @@
|
||||||
|
## Generated for RDPEUDP SYN UDP Datagram
|
||||||
|
##
|
||||||
|
## c: The connection record for the underlying transport-layer session/flow.
|
||||||
|
event rdpeudp_syn%(c: connection%);
|
||||||
|
|
||||||
|
## Generated for RDPEUDP SYNACK UDP Datagram
|
||||||
|
##
|
||||||
|
## c: The connection record for the underlying transport-layer session/flow.
|
||||||
|
event rdpeudp_synack%(c: connection%);
|
||||||
|
|
||||||
|
## Generated when RDPEUDP connections are established (both sides SYN)
|
||||||
|
##
|
||||||
|
## c: The connection record for the underlying transport-layer session/flow.
|
||||||
|
##
|
||||||
|
## version: Whether the connection is RDPEUDP1 or RDPEUDP2
|
||||||
|
event rdpeudp_established%(c: connection, version: count%);
|
||||||
|
|
||||||
|
## Generated when for data messages exchanged after a RDPEUDP connection establishes
|
||||||
|
##
|
||||||
|
## c: The connection record for the underlying transport-layer session/flow.
|
||||||
|
##
|
||||||
|
## is_orig: Whether the data was sent by the originator or responder of the connection.
|
||||||
|
##
|
||||||
|
## version: Whether the connection is RDPEUDP1 or RDPEUDP2
|
||||||
|
##
|
||||||
|
## data: The payload of the packet. This is probably very non-performant.
|
||||||
|
event rdpeudp_data%(c: connection, is_orig: bool, version: count, data: string%);
|
||||||
|
|
||||||
## Generated for each packet after RDP native encryption begins
|
## Generated for each packet after RDP native encryption begins
|
||||||
##
|
##
|
||||||
## c: The connection record for the underlying transport-layer session/flow.
|
## c: The connection record for the underlying transport-layer session/flow.
|
||||||
|
|
112
src/analyzer/protocol/rdp/rdpeudp-analyzer.pac
Normal file
112
src/analyzer/protocol/rdp/rdpeudp-analyzer.pac
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
refine connection RDPEUDP_Conn += {
|
||||||
|
%member{
|
||||||
|
enum RDPEUDP_STATE {
|
||||||
|
NEED_SYN = 0x1,
|
||||||
|
NEED_SYNACK = 0x2,
|
||||||
|
NED_ACK = 0x3,
|
||||||
|
ESTABLISHED = 0x4,
|
||||||
|
};
|
||||||
|
uint8 state_ = NEED_SYN;
|
||||||
|
bool orig_rdpeudp2_ = false;
|
||||||
|
bool resp_rdpeudp2_ = false;
|
||||||
|
bool orig_lossy_ = false;
|
||||||
|
bool resp_lossy_ = false;
|
||||||
|
%}
|
||||||
|
function get_state(): uint8
|
||||||
|
%{
|
||||||
|
return state_;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function get_version(): bool
|
||||||
|
%{
|
||||||
|
return (orig_rdpeudp2_ && resp_rdpeudp2_);
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_rdpeudp_syn(is_orig: bool, uFlags: uint16, snSourceAck: uint32): bool
|
||||||
|
%{
|
||||||
|
if (!is_orig) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((uFlags & 0x01) == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (snSourceAck != 0xffffffff) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uFlags >= 0x1000) {
|
||||||
|
orig_rdpeudp2_ = true;
|
||||||
|
}
|
||||||
|
if ((uFlags & 0x0200) == 0x0200) {
|
||||||
|
orig_lossy_ = true;
|
||||||
|
}
|
||||||
|
if (rdpeudp_syn) {
|
||||||
|
BifEvent::generate_rdpeudp_syn(bro_analyzer(), bro_analyzer()->Conn());
|
||||||
|
}
|
||||||
|
state_ = NEED_SYNACK;
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_rdpeudp_synack(is_orig: bool, uFlags: uint16): bool
|
||||||
|
%{
|
||||||
|
if (is_orig) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((uFlags & 0x05) == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rdpeudp_synack) {
|
||||||
|
BifEvent::generate_rdpeudp_synack(bro_analyzer(), bro_analyzer()->Conn());
|
||||||
|
}
|
||||||
|
bro_analyzer()->ProtocolConfirmation();
|
||||||
|
state_ = NEED_ACK;
|
||||||
|
if (uFlags >= 0x1000) {
|
||||||
|
resp_rdpeudp2_ = true;
|
||||||
|
}
|
||||||
|
if ((uFlags & 0x0200) == 0x0200) {
|
||||||
|
resp_lossy_ = true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_rdpeudp1_ack(is_orig: bool, data: bytestring): bool
|
||||||
|
%{
|
||||||
|
if (state_ == NEED_ACK) {
|
||||||
|
state_ = ESTABLISHED;
|
||||||
|
if (rdpeudp_established) {
|
||||||
|
BifEvent::generate_rdpeudp_established(bro_analyzer(), bro_analyzer()->Conn(), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( state_ == ESTABLISHED && rdpeudp_data )
|
||||||
|
BifEvent::generate_rdpeudp_data(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
is_orig,
|
||||||
|
1,
|
||||||
|
new StringVal(data.length(), (const char*) data.data())
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_rdpeudp2_ack(is_orig: bool, pkt_type: uint8, data: bytestring): bool
|
||||||
|
%{
|
||||||
|
if (pkt_type == 8) {
|
||||||
|
// This is a "dummy packet".
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (state_ == NEED_ACK) {
|
||||||
|
if (rdpeudp_established) {
|
||||||
|
BifEvent::generate_rdpeudp_established(bro_analyzer(), bro_analyzer()->Conn(), 2);
|
||||||
|
}
|
||||||
|
state_ = ESTABLISHED;
|
||||||
|
}
|
||||||
|
if ( state_ == ESTABLISHED && rdpeudp_data )
|
||||||
|
BifEvent::generate_rdpeudp_data(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
is_orig,
|
||||||
|
2,
|
||||||
|
new StringVal(data.length(), (const char*) data.data())
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
};
|
223
src/analyzer/protocol/rdp/rdpeudp-protocol.pac
Normal file
223
src/analyzer/protocol/rdp/rdpeudp-protocol.pac
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
# There are basically 5 PDU types for RDUEUDP1
|
||||||
|
# 1. SYN - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeudp/066f9acf-fd57-4f95-ab3f-334e748bab10
|
||||||
|
# 2. SYNACK - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeudp/96eaa81a-ff42-40a2-884c-96b3834db6c8
|
||||||
|
# 3. ACK (bare) - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeudp/facb0b31-63c6-44f4-aeec-03b5163aedae
|
||||||
|
# 4. ACK + FEC - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeudp/7eaacd17-7012-468f-aa00-6e629cb88df8
|
||||||
|
# 5. ACK + Source - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeudp/427c5d29-6b08-4cdb-bbdf-a1ed09e76e2d
|
||||||
|
# There is basically 1 PDU type for RDPEUDP2. It has a bunch of optional fields indicated by flags.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
enum RDPEUDP_STATE {
|
||||||
|
NEED_SYN = 0x1,
|
||||||
|
NEED_SYNACK = 0x2,
|
||||||
|
NEED_ACK = 0x3,
|
||||||
|
ESTABLISHED = 0x4,
|
||||||
|
};
|
||||||
|
|
||||||
|
type RDPEUDP_PDU(is_orig: bool) = record {
|
||||||
|
state: case $context.connection.get_state() of {
|
||||||
|
NEED_SYN -> need_syn: RDPEUDP_SYN(this, is_orig);
|
||||||
|
NEED_SYNACK -> need_synack: RDPEUDP_SYNACK(this, is_orig);
|
||||||
|
NEED_ACK -> need_ack: RDPEUDP_ACK(this, is_orig);
|
||||||
|
default -> established: RDPEUDP_ACK(this, is_orig);
|
||||||
|
};
|
||||||
|
} &byteorder=bigendian;
|
||||||
|
|
||||||
|
type RDPEUDP_SYN(pdu: RDPEUDP_PDU, is_orig: bool) = record {
|
||||||
|
fec_header: RDPUDP_FEC_HEADER;
|
||||||
|
syndata_payload: RDPUDP_SYNDATA_PAYLOAD;
|
||||||
|
# TODO: parse the rest of the SYN pkt fields
|
||||||
|
# RDPUDP_CORRELATION_ID_PAYLOAD
|
||||||
|
# RDPUDP_SYNEX_PAYLOAD
|
||||||
|
#
|
||||||
|
} &let {
|
||||||
|
proc_rdpeudp_syn: bool = $context.connection.proc_rdpeudp_syn(is_orig, fec_header.uFlags, fec_header.snSourceAck);
|
||||||
|
};
|
||||||
|
|
||||||
|
type RDPUDP_SYNDATA_PAYLOAD = record {
|
||||||
|
snInitialSequenceNumber: uint32;
|
||||||
|
uUpStreamMtu: uint16;
|
||||||
|
uDownStreamMtu: uint16;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RDPEUDP_SYNACK(pdu: RDPEUDP_PDU, is_orig: bool) = record {
|
||||||
|
fec_header: RDPUDP_FEC_HEADER;
|
||||||
|
} &let {
|
||||||
|
proc_rdpeudp_synack: bool = $context.connection.proc_rdpeudp_synack(is_orig, fec_header.uFlags);
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RDPUDP_FLAG {
|
||||||
|
RDPUDP_FLAG_SYN = 0x0001,
|
||||||
|
RDPUDP_FLAG_FIN = 0x0002,
|
||||||
|
RDPUDP_FLAG_ACK = 0x0004,
|
||||||
|
RDPUDP_FLAG_DATA = 0x0008,
|
||||||
|
RDPUDP_FLAG_FEC = 0x0010,
|
||||||
|
RDPUDP_FLAG_CN = 0x0020,
|
||||||
|
RDPUDP_FLAG_CWR = 0x0040,
|
||||||
|
RDPUDP_FLAG_SACK_OPTION = 0x0080,
|
||||||
|
RDPUDP_FLAG_ACK_OF_ACKS = 0x0100,
|
||||||
|
RDPUDP_FLAG_SYNLOSSY = 0x0200,
|
||||||
|
RDPUDP_FLAG_ACKDELAYED = 0x0400,
|
||||||
|
RDPUDP_FLAG_CORRELATION_ID = 0x800,
|
||||||
|
RDPUDP_FLAG_SYNEX = 0x1000
|
||||||
|
};
|
||||||
|
|
||||||
|
type RDPEUDP_ACK(pdu: RDPEUDP_PDU, is_orig: bool) = record {
|
||||||
|
version: case ($context.connection.get_version()) of {
|
||||||
|
true -> version2: RDPEUDP2_ACK(pdu, is_orig);
|
||||||
|
false -> version1: RDPEUDP1_ACK(pdu, is_orig);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type RDPEUDP1_ACK(pdu: RDPEUDP_PDU, is_orig: bool) = record {
|
||||||
|
fec_header: RDPUDP_FEC_HEADER;
|
||||||
|
ack_vec_header: RDPUDP_ACK_VECTOR_HEADER;
|
||||||
|
ack_of_ackvec_header: case fec_header.uFlags & RDPUDP_FLAG_ACK_OF_ACKS of {
|
||||||
|
RDPUDP_FLAG_ACK_OF_ACKS -> some: RDPUDP_ACK_OF_ACKVECTOR_HEADER;
|
||||||
|
default -> no_ack_of_ackvec_header: empty;
|
||||||
|
};
|
||||||
|
# This doesn't handle ACK+FEC packets, which have both RDPUDP_FLAG_DATA and RDPUDP_FLAG_FEC set
|
||||||
|
source_payload_header: case (fec_header.uFlags & RDPUDP_FLAG_DATA) of {
|
||||||
|
RDPUDP_FLAG_DATA -> some_source_payload: RDPUDP_SOURCE_PAYLOAD_HEADER;
|
||||||
|
default -> no_source_payload_header: empty;
|
||||||
|
};
|
||||||
|
data: bytestring &restofdata;
|
||||||
|
} &let {
|
||||||
|
proc_rdpeudp1_ack: bool = $context.connection.proc_rdpeudp1_ack(is_orig, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
type RDPUDP_SOURCE_PAYLOAD_HEADER = record {
|
||||||
|
snCoded: uint32;
|
||||||
|
snSourceStart: uint32;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RDPUDP_ACK_OF_ACKVECTOR_HEADER = record {
|
||||||
|
snAckOfAcksSeqNum: uint32;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RDPUDP_FEC_HEADER = record {
|
||||||
|
snSourceAck: uint32;
|
||||||
|
uReceiveWindowSize: uint16;
|
||||||
|
uFlags: uint16;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RDPUDP_ACK_VECTOR_HEADER = record {
|
||||||
|
uAckVectorSize: uint16;
|
||||||
|
AckVectorElement: uint8[uAckVectorSize];
|
||||||
|
pad: padding align 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
# version 2
|
||||||
|
type RDPEUDP2_ACK(pdu: RDPEUDP_PDU, is_orig: bool) = record {
|
||||||
|
PacketPrefixByte: uint8;
|
||||||
|
header: RDPUDP2_PACKET_HEADER;
|
||||||
|
# TODO:
|
||||||
|
# ack_payload: case ((header.Flags & ACK) > 0) of {
|
||||||
|
# true -> has_ack_p: RDPUDP2_ACK_PAYLOAD;
|
||||||
|
# false -> has_no_ack_p: empty;
|
||||||
|
# };
|
||||||
|
# oversize_payload: case ((header.Flags & 0x040) > OVERHEADSIZE) of {
|
||||||
|
# true -> has_oversize: RDPUDP2_OVERSIZE_PAYLOAD;
|
||||||
|
# false -> has_no_oversize: empty;
|
||||||
|
# };
|
||||||
|
# delay_ack_info_payload: case ((header.Flags & DELAYACKINFO) > 0) of {
|
||||||
|
# true -> has_ack_info_p: RDPUDP2_DELAYACKINFO_PAYLOAD;
|
||||||
|
# false -> has_no_ack_info_p: empty;
|
||||||
|
# };
|
||||||
|
# ack_of_acks_payload: case ((header.Flags & AOA) > 0) of {
|
||||||
|
# true -> has_aoa_p: RDPUDP2_ACKOFACKS_PAYLOAD;
|
||||||
|
# false -> has_no_aoa_p: empty;
|
||||||
|
# };
|
||||||
|
# data_header_payload: case ((header.Flags & DATA) > 0) of {
|
||||||
|
# true -> has_data_h: RDPUDP2_DATAHEADER_PAYLOAD;
|
||||||
|
# false -> has_no_data_h: empty;
|
||||||
|
# };
|
||||||
|
# ack_vector_payload: case ((header.Flags & ACKVEC) > 0) of {
|
||||||
|
# true -> has_av_p: RDPUDP2_ACKVECTOR_PAYLOAD;
|
||||||
|
# false -> has_no_av_p: empty;
|
||||||
|
# };
|
||||||
|
# data_body_payload: case ((header.Flags & DATA) > 0) of {
|
||||||
|
# true -> has_data_p: RDPUDP2_DATABODY_PAYLOAD;
|
||||||
|
# false -> has_no_data_p: empty;
|
||||||
|
# };
|
||||||
|
# data_body_payload: RDPUDP2_DATABODY_PAYLOAD;
|
||||||
|
data: bytestring &restofdata;
|
||||||
|
} &let {
|
||||||
|
Reserved: uint8 = PacketPrefixByte & 0x80;
|
||||||
|
Packet_Type_Index: uint8 = PacketPrefixByte & 0x78;
|
||||||
|
Short_Packet_Length: uint8 = PacketPrefixByte & 0x07;
|
||||||
|
# proc_rdpeudp2_ack: bool = $context.connection.proc_rdpeudp2_ack(is_orig, Packet_Type_Index, data_body_payload.Data);
|
||||||
|
proc_rdpeudp2_ack: bool = $context.connection.proc_rdpeudp2_ack(is_orig, Packet_Type_Index, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
type RDPUDP2_PACKET_HEADER = record {
|
||||||
|
everything: uint16;
|
||||||
|
} &let {
|
||||||
|
Flags: uint16 = everything & 0xfff0; # The high 12
|
||||||
|
LogWindowSize: uint8 = everything & 0x000f; # The low 4
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RDPUDP2_PACKET_HEADER_FLAGS {
|
||||||
|
ACK = 0x001,
|
||||||
|
DATA = 0x004,
|
||||||
|
ACKVEC = 0x008,
|
||||||
|
AOA = 0x010,
|
||||||
|
OVERHEADSIZE = 0x040,
|
||||||
|
DELAYACKINFO = 0x100
|
||||||
|
};
|
||||||
|
|
||||||
|
type RDPUDP2_ACK_PAYLOAD = record {
|
||||||
|
SeqNum: uint16;
|
||||||
|
tmp1: uint32;
|
||||||
|
tmp2: uint8;
|
||||||
|
delayAckTimeAdditions: uint8[numDelayedAcks];
|
||||||
|
} &let {
|
||||||
|
receivedTS: uint8 = tmp1 & 0xffffff00;
|
||||||
|
sendAckTimeGap: uint8 = tmp1 & 0xff;
|
||||||
|
numDelayedAcks: uint8 = tmp2 & 0xf0; # top 4 bits
|
||||||
|
delayAckTimeScale: uint8 = tmp2 & 0x0f; # bottom 4 bits
|
||||||
|
};
|
||||||
|
|
||||||
|
type RDPUDP2_OVERSIZE_PAYLOAD = record{
|
||||||
|
OverheadSize: uint8;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RDPUDP2_DATABODY_PAYLOAD = record {
|
||||||
|
ChannelSeqNum: uint16;
|
||||||
|
Data: bytestring &restofdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RDPUDP2_ACKVECTOR_PAYLOAD = record {
|
||||||
|
BaseSeqNum: uint16;
|
||||||
|
tmp1: uint8;
|
||||||
|
TimeStamp_or_not: case TimeStampPresent of {
|
||||||
|
0 -> none: empty;
|
||||||
|
default -> some: RDPUDP2_ACKVECTOR_PAYLOAD_TimeStamp;
|
||||||
|
} &requires(TimeStampPresent);
|
||||||
|
codedAckVector: uint8[codedAckVecSize];
|
||||||
|
} &let {
|
||||||
|
codedAckVecSize: uint8 = tmp1 & 0xfe;
|
||||||
|
TimeStampPresent: uint8 = tmp1 & 0x01;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RDPUDP2_ACKVECTOR_PAYLOAD_TimeStamp = record {
|
||||||
|
tmp1: uint8;
|
||||||
|
tmp2: uint8;
|
||||||
|
tmp3: uint8;
|
||||||
|
} &let {
|
||||||
|
TimeStamp: uint32 = tmp3 | (tmp2 << 8) | (tmp1 << 16);
|
||||||
|
};
|
||||||
|
|
||||||
|
type RDPUDP2_DATAHEADER_PAYLOAD = record {
|
||||||
|
DataSeqNum: uint16;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RDPUDP2_ACKOFACKS_PAYLOAD = record {
|
||||||
|
AckOfAcksSeqNum: uint16;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RDPUDP2_DELAYACKINFO_PAYLOAD = record {
|
||||||
|
MaxDelayedAcks: uint8;
|
||||||
|
DelayedAckTimeoutInMs: uint16;
|
||||||
|
};
|
24
src/analyzer/protocol/rdp/rdpeudp.pac
Normal file
24
src/analyzer/protocol/rdp/rdpeudp.pac
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
%include binpac.pac
|
||||||
|
%include bro.pac
|
||||||
|
|
||||||
|
%extern{
|
||||||
|
#include "events.bif.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
analyzer RDPEUDP withcontext {
|
||||||
|
connection: RDPEUDP_Conn;
|
||||||
|
flow: RDPEUDP_Flow;
|
||||||
|
};
|
||||||
|
|
||||||
|
connection RDPEUDP_Conn(bro_analyzer: BroAnalyzer) {
|
||||||
|
upflow = RDPEUDP_Flow(true);
|
||||||
|
downflow = RDPEUDP_Flow(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
%include rdpeudp-protocol.pac
|
||||||
|
|
||||||
|
flow RDPEUDP_Flow(is_orig: bool) {
|
||||||
|
datagram = RDPEUDP_PDU(is_orig) withcontext(connection, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
%include rdpeudp-analyzer.pac
|
BIN
testing/btest/Traces/rdp/rdp-rdpeudp-handshake-fail.pcap
Normal file
BIN
testing/btest/Traces/rdp/rdp-rdpeudp-handshake-fail.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/rdp/rdp-rdpeudp-handshake-success.pcap
Normal file
BIN
testing/btest/Traces/rdp/rdp-rdpeudp-handshake-success.pcap
Normal file
Binary file not shown.
|
@ -0,0 +1,23 @@
|
||||||
|
# @TEST-EXEC: zeek -r $TRACES/rdp/rdp-rdpeudp-handshake-fail.pcap %INPUT
|
||||||
|
# @TEST-EXEC: btest-diff conn.log
|
||||||
|
|
||||||
|
@load base/protocols/rdp
|
||||||
|
|
||||||
|
event rdpeudp_syn(c: connection) {
|
||||||
|
print "rdpeudp_syn";
|
||||||
|
}
|
||||||
|
|
||||||
|
event rdpeudp_synack(c: connection) {
|
||||||
|
print "rdpeudp_synack";
|
||||||
|
}
|
||||||
|
|
||||||
|
event rdpeudp_established(c: connection, version: count) {
|
||||||
|
print "rdpeudp_established";
|
||||||
|
print "version", version;
|
||||||
|
}
|
||||||
|
|
||||||
|
event rdpeudp_data(c: connection, is_orig: bool, version: count, data: string)
|
||||||
|
{
|
||||||
|
print "rdpeudp_data";
|
||||||
|
print fmt("is_orig: %s, version %d, data: %s", is_orig, version, data);
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
# @TEST-EXEC: zeek -r $TRACES/rdp/rdp-rdpeudp-handshake-success.pcap %INPUT
|
||||||
|
# @TEST-EXEC: btest-diff conn.log
|
||||||
|
|
||||||
|
@load base/protocols/rdp
|
||||||
|
|
||||||
|
event rdpeudp_syn(c: connection) {
|
||||||
|
print "rdpeudp_syn";
|
||||||
|
}
|
||||||
|
|
||||||
|
event rdpeudp_synack(c: connection) {
|
||||||
|
print "rdpeudp_synack";
|
||||||
|
}
|
||||||
|
|
||||||
|
event rdpeudp_established(c: connection, version: count) {
|
||||||
|
print "rdpeudp_established";
|
||||||
|
print "version", version;
|
||||||
|
}
|
||||||
|
|
||||||
|
event rdpeudp_data(c: connection, is_orig: bool, version: count, data: string)
|
||||||
|
{
|
||||||
|
print "rdpeudp_data";
|
||||||
|
print fmt("is_orig: %s, version %d, data: %s", is_orig, version, data);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue