mirror of https://github.com/OISF/suricata
DNP3: Application layer decoder.
Decodes TCP DNP3 and raises some DNP3 decoder alerts.pull/2391/head
parent
240d789c40
commit
bbaa79b80e
@ -0,0 +1,26 @@
|
|||||||
|
# DNP3 application decoder event rules.
|
||||||
|
#
|
||||||
|
# This SIDs fall in the 2270000+ range. See:
|
||||||
|
# http://doc.emergingthreats.net/bin/view/Main/SidAllocation
|
||||||
|
|
||||||
|
# Flooded.
|
||||||
|
alert dnp3 any any -> any any (msg:"SURICATA DNP3 Request flood detected"; \
|
||||||
|
app-layer-event:dnp3.flooded; sid:2270000; rev:1;)
|
||||||
|
|
||||||
|
# Length to small for PDU type. For example, link specifies the type
|
||||||
|
# as user data, but the length field is not large enough for user
|
||||||
|
# data.
|
||||||
|
alert dnp3 any any -> any any (msg:"SURICATA DNP3 Length too small"; \
|
||||||
|
app-layer-event:dnp3.len_too_small; sid:2270001; rev:2;)
|
||||||
|
|
||||||
|
# Bad link layer CRC.
|
||||||
|
alert dnp3 any any -> any any (msg:"SURICATA DNP3 Bad link CRC"; \
|
||||||
|
app-layer-event:dnp3.bad_link_crc; sid:2270002; rev:1;)
|
||||||
|
|
||||||
|
# Bad transport layer CRC.
|
||||||
|
alert dnp3 any any -> any any (msg:"SURICATA DNP3 Bad transport CRC"; \
|
||||||
|
app-layer-event:dnp3.bad_transport_crc; sid:2270003; rev:1;)
|
||||||
|
|
||||||
|
# Unknown object.
|
||||||
|
alert dnp3 any any -> any any (msg:"SURICATA DNP3 Unknown object"; \
|
||||||
|
app-layer-event:dnp3.unknown_object; sid:2270004; rev:1;)
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,277 @@
|
|||||||
|
/* Copyright (C) 2015 Open Information Security Foundation
|
||||||
|
*
|
||||||
|
* You can copy, redistribute or modify this Program under the terms of
|
||||||
|
* the GNU General Public License version 2 as published by the Free
|
||||||
|
* Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* version 2 along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __APP_LAYER_DNP3_H__
|
||||||
|
#define __APP_LAYER_DNP3_H__
|
||||||
|
|
||||||
|
#include "detect-engine-state.h"
|
||||||
|
#include "util-hashlist.h"
|
||||||
|
#include "util-byte.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum size of a DNP3 link PDU.
|
||||||
|
*/
|
||||||
|
#define DNP3_MAX_LINK_PDU_LEN 292
|
||||||
|
|
||||||
|
/* DNP3 application request function codes. */
|
||||||
|
#define DNP3_APP_FC_CONFIRM 0x00
|
||||||
|
#define DNP3_APP_FC_READ 0x01
|
||||||
|
#define DNP3_APP_FC_WRITE 0x02
|
||||||
|
#define DNP3_APP_FC_SELECT 0x03
|
||||||
|
#define DNP3_APP_FC_OPERATE 0x04
|
||||||
|
#define DNP3_APP_FC_DIR_OPERATE 0x05
|
||||||
|
#define DNP3_APP_FC_DIR_OPERATE_NR 0x06
|
||||||
|
#define DNP3_APP_FC_FREEZE 0x07
|
||||||
|
#define DNP3_APP_FC_FREEZE_NR 0x08
|
||||||
|
#define DNP3_APP_FC_FREEZE_CLEAR 0x09
|
||||||
|
#define DNP3_APP_FC_FREEZE_CLEAR_NR 0x0a
|
||||||
|
#define DNP3_APP_FC_FREEZE_AT_TIME 0x0b
|
||||||
|
#define DNP3_APP_FC_FREEZE_AT_TIME_NR 0x0c
|
||||||
|
#define DNP3_APP_FC_COLD_RESTART 0x0d
|
||||||
|
#define DNP3_APP_FC_WARM_RESTART 0x0e
|
||||||
|
#define DNP3_APP_FC_INITIALIZE_DATA 0x0f
|
||||||
|
#define DNP3_APP_FC_INITIALIZE_APPLICATION 0x10
|
||||||
|
#define DNP3_APP_FC_START_APPLICATION 0x11
|
||||||
|
#define DNP3_APP_FC_STOP_APPLICATION 0x12
|
||||||
|
#define DNP3_APP_FC_SAVE_CONFIGURATION 0x13
|
||||||
|
#define DNP3_APP_FC_ENABLE_UNSOLICITED 0x14
|
||||||
|
#define DNP3_APP_FC_DISABLE_UNSOLICTED 0x15
|
||||||
|
#define DNP3_APP_FC_ASSIGN_CLASS 0x16
|
||||||
|
#define DNP3_APP_FC_DELAY_MEASUREMENT 0x17
|
||||||
|
#define DNP3_APP_FC_RECORD_CURRENT_TIME 0x18
|
||||||
|
#define DNP3_APP_FC_OPEN_TIME 0x19
|
||||||
|
#define DNP3_APP_FC_CLOSE_FILE 0x1a
|
||||||
|
#define DNP3_APP_FC_DELETE_FILE 0x1b
|
||||||
|
#define DNP3_APP_FC_GET_FILE_INFO 0x1c
|
||||||
|
#define DNP3_APP_FC_AUTHENTICATE_FILE 0x1d
|
||||||
|
#define DNP3_APP_FC_ABORT_FILE 0x1e
|
||||||
|
#define DNP3_APP_FC_ACTIVATE_CONFIG 0x1f
|
||||||
|
#define DNP3_APP_FC_AUTH_REQ 0x20
|
||||||
|
#define DNP3_APP_FC_AUTH_REQ_NR 0x21
|
||||||
|
|
||||||
|
/* DNP3 application response function codes. */
|
||||||
|
#define DNP3_APP_FC_RESPONSE 0x81
|
||||||
|
#define DNP3_APP_FC_UNSOLICITED_RESP 0x82
|
||||||
|
#define DNP3_APP_FC_AUTH_RESP 0x83
|
||||||
|
|
||||||
|
/* Extract fields from the link control octet. */
|
||||||
|
#define DNP3_LINK_DIR(control) (control & 0x80)
|
||||||
|
#define DNP3_LINK_PRI(control) (control & 0x40)
|
||||||
|
#define DNP3_LINK_FCB(control) (control & 0x20)
|
||||||
|
#define DNP3_LINK_FCV(control) (control & 0x10)
|
||||||
|
#define DNP3_LINK_FC(control) (control & 0x0f)
|
||||||
|
|
||||||
|
/* Extract fields from transport layer header octet. */
|
||||||
|
#define DNP3_TH_FIN(x) (x & 0x80)
|
||||||
|
#define DNP3_TH_FIR(x) (x & 0x40)
|
||||||
|
#define DNP3_TH_SEQ(x) (x & 0x3f)
|
||||||
|
|
||||||
|
/* Extract fields from the application control octet. */
|
||||||
|
#define DNP3_APP_FIR(x) (x & 0x80)
|
||||||
|
#define DNP3_APP_FIN(x) (x & 0x40)
|
||||||
|
#define DNP3_APP_CON(x) (x & 0x20)
|
||||||
|
#define DNP3_APP_UNS(x) (x & 0x10)
|
||||||
|
#define DNP3_APP_SEQ(x) (x & 0x0f)
|
||||||
|
|
||||||
|
/* DNP3 values are stored in little endian on the wire, so swapping will be
|
||||||
|
* needed on big endian architectures. */
|
||||||
|
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||||
|
#define DNP3_SWAP16(x) SCByteSwap16(x)
|
||||||
|
#define DNP3_SWAP32(x) SCByteSwap32(x)
|
||||||
|
#define DNP3_SWAP64(x) SCByteSwap64(x)
|
||||||
|
#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
#define DNP3_SWAP16(x) x
|
||||||
|
#define DNP3_SWAP32(x) x
|
||||||
|
#define DNP3_SWAP64(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* DNP3 decoder events. */
|
||||||
|
enum {
|
||||||
|
DNP3_DECODER_EVENT_FLOODED = 1,
|
||||||
|
DNP3_DECODER_EVENT_LEN_TOO_SMALL,
|
||||||
|
DNP3_DECODER_EVENT_BAD_LINK_CRC,
|
||||||
|
DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC,
|
||||||
|
DNP3_DECODER_EVENT_MALFORMED,
|
||||||
|
DNP3_DECODER_EVENT_UNKNOWN_OBJECT,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief DNP3 link header.
|
||||||
|
*/
|
||||||
|
typedef struct DNP3LinkHeader_ {
|
||||||
|
uint8_t start_byte0; /**< First check byte. */
|
||||||
|
uint8_t start_byte1; /**< Second check byte. */
|
||||||
|
uint8_t len; /**< Length of PDU without CRCs. */
|
||||||
|
uint8_t control; /**< Control flags. */
|
||||||
|
uint16_t dst; /**< DNP3 destination address. */
|
||||||
|
uint16_t src; /**< DNP3 source address. */
|
||||||
|
uint16_t crc; /**< Link header CRC. */
|
||||||
|
} __attribute__((__packed__)) DNP3LinkHeader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief DNP3 transport header.
|
||||||
|
*/
|
||||||
|
typedef uint8_t DNP3TransportHeader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief DNP3 application header.
|
||||||
|
*/
|
||||||
|
typedef struct DNP3ApplicationHeader_ {
|
||||||
|
uint8_t control; /**< Control flags. */
|
||||||
|
uint8_t function_code; /**< Application function code. */
|
||||||
|
} __attribute__((__packed__)) DNP3ApplicationHeader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief DNP3 internal indicators.
|
||||||
|
*
|
||||||
|
* Part of the application header for responses only.
|
||||||
|
*/
|
||||||
|
typedef struct DNP3InternalInd_ {
|
||||||
|
uint8_t iin1;
|
||||||
|
uint8_t iin2;
|
||||||
|
} __attribute__((__packed__)) DNP3InternalInd;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief A struct used for buffering incoming data prior to reassembly.
|
||||||
|
*/
|
||||||
|
typedef struct DNP3Buffer_ {
|
||||||
|
uint8_t *buffer;
|
||||||
|
size_t size;
|
||||||
|
int len;
|
||||||
|
int offset;
|
||||||
|
} DNP3Buffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief DNP3 application object header.
|
||||||
|
*/
|
||||||
|
typedef struct DNP3ObjHeader_ {
|
||||||
|
uint8_t group;
|
||||||
|
uint8_t variation;
|
||||||
|
uint8_t qualifier;
|
||||||
|
} __attribute__((packed)) DNP3ObjHeader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief DNP3 object point.
|
||||||
|
*
|
||||||
|
* Each DNP3 object can have 0 or more points representing the values
|
||||||
|
* of the object.
|
||||||
|
*/
|
||||||
|
typedef struct DNP3Point_ {
|
||||||
|
uint32_t prefix; /**< Prefix value for point. */
|
||||||
|
uint32_t index; /**< Index of point. If the object is prefixed
|
||||||
|
* with an index then this will be that
|
||||||
|
* value. Otherwise this is the place the point
|
||||||
|
* was in the list of points (starting at 0). */
|
||||||
|
uint32_t size; /**< Size of point if the object prefix was a
|
||||||
|
* size. */
|
||||||
|
void *data; /**< Data for this point. */
|
||||||
|
TAILQ_ENTRY(DNP3Point_) next;
|
||||||
|
} DNP3Point;
|
||||||
|
|
||||||
|
typedef TAILQ_HEAD(DNP3PointList_, DNP3Point_) DNP3PointList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Struct to hold the list of decoded objects.
|
||||||
|
*/
|
||||||
|
typedef struct DNP3Object_ {
|
||||||
|
uint8_t group;
|
||||||
|
uint8_t variation;
|
||||||
|
uint8_t qualifier;
|
||||||
|
uint8_t prefix_code;
|
||||||
|
uint8_t range_code;
|
||||||
|
uint32_t start;
|
||||||
|
uint32_t stop;
|
||||||
|
uint32_t count;
|
||||||
|
DNP3PointList *points; /**< List of points for this object. */
|
||||||
|
|
||||||
|
TAILQ_ENTRY(DNP3Object_) next;
|
||||||
|
} DNP3Object;
|
||||||
|
|
||||||
|
typedef TAILQ_HEAD(DNP3ObjectList_, DNP3Object_) DNP3ObjectList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief DNP3 transaction.
|
||||||
|
*/
|
||||||
|
typedef struct DNP3Transaction_ {
|
||||||
|
uint64_t tx_num; /**< Internal transaction ID. */
|
||||||
|
uint32_t logged; /**< Flags indicating which loggers have logged this tx. */
|
||||||
|
|
||||||
|
struct DNP3State_ *dnp3;
|
||||||
|
|
||||||
|
uint8_t has_request;
|
||||||
|
uint8_t request_done;
|
||||||
|
DNP3LinkHeader request_lh;
|
||||||
|
DNP3TransportHeader request_th;
|
||||||
|
DNP3ApplicationHeader request_ah;
|
||||||
|
uint8_t *request_buffer; /**< Reassembled request
|
||||||
|
* buffer. */
|
||||||
|
uint32_t request_buffer_len;
|
||||||
|
uint8_t request_complete; /**< Was the decode
|
||||||
|
* complete. It will not be
|
||||||
|
* complete if we hit objects
|
||||||
|
* we do not know. */
|
||||||
|
DNP3ObjectList request_objects;
|
||||||
|
|
||||||
|
uint8_t has_response;
|
||||||
|
uint8_t response_done;
|
||||||
|
DNP3LinkHeader response_lh;
|
||||||
|
DNP3TransportHeader response_th;
|
||||||
|
DNP3ApplicationHeader response_ah;
|
||||||
|
DNP3InternalInd response_iin;
|
||||||
|
uint8_t *response_buffer; /**< Reassembed response
|
||||||
|
* buffer. */
|
||||||
|
uint32_t response_buffer_len;
|
||||||
|
uint8_t response_complete; /**< Was the decode
|
||||||
|
* complete. It will not be
|
||||||
|
* complete if we hit objects
|
||||||
|
* we do not know. */
|
||||||
|
DNP3ObjectList response_objects;
|
||||||
|
|
||||||
|
AppLayerDecoderEvents *decoder_events; /**< Per transcation
|
||||||
|
* decoder events. */
|
||||||
|
DetectEngineState *de_state;
|
||||||
|
|
||||||
|
TAILQ_ENTRY(DNP3Transaction_) next;
|
||||||
|
} DNP3Transaction;
|
||||||
|
|
||||||
|
TAILQ_HEAD(TxListHead, DNP3Transaction_);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Per flow DNP3 state.
|
||||||
|
*/
|
||||||
|
typedef struct DNP3State_ {
|
||||||
|
TAILQ_HEAD(, DNP3Transaction_) tx_list;
|
||||||
|
DNP3Transaction *curr; /**< Current transaction. */
|
||||||
|
uint64_t transaction_max;
|
||||||
|
uint16_t events;
|
||||||
|
uint32_t unreplied; /**< Number of unreplied requests. */
|
||||||
|
uint8_t flooded; /**< Flag indicating flood. */
|
||||||
|
|
||||||
|
DNP3Buffer request_buffer; /**< Request buffer for buffering
|
||||||
|
* incomplete request PDUs received
|
||||||
|
* over TCP. */
|
||||||
|
DNP3Buffer response_buffer; /**< Response buffer for buffering
|
||||||
|
* incomplete response PDUs received
|
||||||
|
* over TCP. */
|
||||||
|
|
||||||
|
} DNP3State;
|
||||||
|
|
||||||
|
void RegisterDNP3Parsers(void);
|
||||||
|
void DNP3ParserRegisterTests(void);
|
||||||
|
int DNP3PrefixIsSize(uint8_t);
|
||||||
|
|
||||||
|
#endif /* __APP_LAYER_DNP3_H__ */
|
Loading…
Reference in New Issue