-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 916976d
Showing
14 changed files
with
1,548 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# ElecFuzz | ||
fuzz IEC-104协议 | ||
``` | ||
python3 main.py --host 192.168.161.25 --port 2404 --service IEC104 | ||
``` | ||
|
||
fuzz MMS协议 | ||
``` | ||
python3 main.py --host 192.168.161.25 --port 102 --service MMS | ||
``` | ||
|
||
fuzz Modbus协议 | ||
``` | ||
python3 main.py --host 192.168.161.25 --port 502 --service MODBUS | ||
``` | ||
|
||
fuzz GOOSE协议 | ||
``` | ||
python3 main.py --service GOOSE --interface eth1 | ||
``` | ||
|
||
fuzz SV协议 | ||
``` | ||
python3 main.py --service SV --interface eth1 | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
#!/usr/bin/python3 | ||
import argparse | ||
import logging | ||
import sys | ||
import util.iec104 | ||
import util.mms | ||
import util.goose | ||
import util.sampled_values | ||
import util.modbus | ||
|
||
|
||
def main(): | ||
parser = argparse.ArgumentParser(description="Electric Fuzzer") | ||
parser.add_argument("--host", action="store", dest="host", | ||
type=str, required=False, | ||
help="target host to fuzz" | ||
) | ||
parser.add_argument("--port", action="store", dest="port", | ||
type=str, required=False, | ||
help="target port" | ||
) | ||
parser.add_argument("--interface", action="store", dest="interface", | ||
type=str, required=False, | ||
help="target interface" | ||
) | ||
parser.add_argument("--service", action="store", dest="service", | ||
type=str, required=True, | ||
help="target service" | ||
) | ||
|
||
args = parser.parse_args() | ||
host = args.host | ||
port = args.port | ||
service = args.service | ||
interface = args.interface | ||
|
||
if host != None and port != None: | ||
if util.iec104.isServiceExposed(host, port): | ||
logging.info("Service found active on %s:%s" % (host,port)) | ||
else: | ||
logging.warn("Service is not exposed by %s on %s port" % (host,port)) | ||
logging.info("Stopping Fuzzing on %s:%s" % (host,port)) | ||
|
||
if service.upper() == "IEC104": | ||
util.iec104.IEC104Fuzz(host, port) | ||
elif service.upper() == "MMS": | ||
util.mms.MMSFuzz(host, port) | ||
elif service.upper() == "GOOSE": | ||
util.goose.GOOSEFuzz(interface) | ||
elif service.upper() == "SV": | ||
util.sampled_values.SVFuzz(interface) | ||
elif service.upper() == "MODBUS": | ||
util.modbus.ModbusFuzz(host, port) | ||
else: | ||
logging.info("Unsupported Service!") | ||
sys.exit(0) | ||
|
||
logging.info("Electric Fuzzing is finished... bye.") | ||
|
||
|
||
if __name__ == "__main__": | ||
logging.basicConfig(level=logging.DEBUG, | ||
format='%(asctime)s - %(message)s', | ||
datefmt='%d-%b-%y %H:%M:%S') | ||
main() | ||
|
Empty file.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import sys | ||
|
||
from boofuzz import s_initialize, s_static, s_get, s_random, s_block, Session, Target | ||
from boofuzz.connections.raw_l2_socket_connection import RawL2SocketConnection | ||
|
||
|
||
def initialize_goose(session): | ||
s_initialize('goose_msg') | ||
|
||
with s_block("Preamble"): | ||
s_static('\x01\x0c\xcd\x01\x00\x01', name="Destination") | ||
s_static('\x00\x00\x00\x00\x00\x00', name="Source") | ||
s_static('\x81\x00', name="Tag Protocol Identifier (TPID)") | ||
s_static('\x80\x00', name="Tag Control Information (TCI)") | ||
s_static('\x88\xb8', name="Ethertype = Goose") | ||
s_static('\x03\xe8', name="Application Identifier (APPID) laut Paper allerdings x3f xff") | ||
s_static('\x00\xb7', name="Length (183) --> Wovon?") | ||
s_static('\x00\x00', name="Reserved 1") | ||
s_static('\x00\x00', name="Reserved 2") | ||
|
||
with s_block("goosePDU"): | ||
s_random('\x61', min_length=0, max_length=100, num_mutations=100000, name="TAG goosePDU") | ||
s_random('\x81\xac', min_length=0, max_length=100, num_mutations=100000, name="LENGTH goosePDU (172)") | ||
|
||
with s_block("gocbRef"): | ||
s_random("\x80", min_length=0, max_length=100, num_mutations=100000, name="TAG gocbRef") | ||
s_random("\x29", min_length=0, max_length=100, num_mutations=100000, name="LENGTH gocbRef = 41") | ||
s_random("\x73\x69\x6d\x70\x6c\x65\x49\x4f\x47\x65" | ||
"\x6e\x65\x72\x69\x63\x49\x4f\x2f\x4c\x4c" | ||
"\x4e\x30\x24\x47\x4f\x24\x67\x63\x62\x41" | ||
"\x6e\x61\x6c\x6f\x67\x56\x61\x6c\x75\x65" | ||
"\x73", min_length=0, max_length=100, num_mutations=100000, name="DATA gocbRef") | ||
|
||
with s_block("TimeAllowedToLive"): | ||
s_random("\x81", min_length=0, max_length=100, num_mutations=100000, name="TAG TimeAllowedToLive") | ||
s_random("\x01", min_length=0, max_length=100, num_mutations=100000, name="LENGTH TimeAllowedToLive = 1") | ||
s_random("\x00", min_length=0, max_length=100, num_mutations=100000, name="DATA TimeAllowedToLive") | ||
|
||
with s_block("datSet"): | ||
s_random("\x82", min_length=0, max_length=100, num_mutations=100000, name="TAG datSet") | ||
s_random("\x23", min_length=0, max_length=100, num_mutations=100000, name="Length datSet = 35") | ||
s_random("\x73\x69\x6d\x70\x6c\x65\x49\x4f\x47\x65" | ||
"\x6e\x65\x72\x69\x63\x49\x4f\x2f\x4c\x4c" | ||
"\x4e\x30\x24\x41\x6e\x61\x6c\x6f\x67\x56" | ||
"\x61\x6c\x75\x65\x73", min_length=0, max_length=100, num_mutations=100000, name="DATA datSet") | ||
|
||
with s_block("goID"): | ||
s_random("\x83", min_length=0, max_length=100, num_mutations=100000, name="TAG goID") | ||
s_random("\x29", min_length=0, max_length=100, num_mutations=100000, name="LENGTH goID = 41") | ||
s_random("\x73\x69\x6d\x70\x6c\x65\x49\x4f\x47\x65" | ||
"\x6e\x65\x72\x69\x63\x49\x4f\x2f\x4c\x4c" | ||
"\x4e\x30\x24\x47\x4f\x24\x67\x63\x62\x41" | ||
"\x6e\x61\x6c\x6f\x67\x56\x61\x6c\x75\x65" | ||
"\x73", min_length=0, max_length=100, num_mutations=100000, name="DATA goID") | ||
|
||
with s_block("time"): | ||
s_random("\x84", min_length=0, max_length=100, num_mutations=100000, name="TAG time") | ||
s_random("\x08", min_length=0, max_length=100, num_mutations=100000, name="LENGTH time = 8") | ||
s_random("\x5d\xe6\x60\x85\xb8\xd4\xfd\x0a", min_length=0, max_length=100, num_mutations=100000, name="DATA time") | ||
|
||
with s_block("stNum"): | ||
s_random("\x85", min_length=0, max_length=100, num_mutations=100000, name="TAG stNum") | ||
s_random("\x01", min_length=0, max_length=100, num_mutations=100000, name="LENGTH stNum = 1") | ||
s_random("\x01", min_length=0, max_length=100, num_mutations=100000, name="DATA stNum") | ||
|
||
with s_block("sqNum"): | ||
s_random("\x86", min_length=0, max_length=100, num_mutations=100000, name="TAG sqNum") | ||
s_random("\x01", min_length=0, max_length=100, num_mutations=100000, name="LENGTH sqNum = 1") | ||
s_random("\x00", min_length=0, max_length=100, num_mutations=100000, name="DATA sqNum") | ||
|
||
with s_block("Test Bit"): | ||
s_random("\x87", min_length=0, max_length=100, num_mutations=100000, name="TAG Test Bit") | ||
s_random("\x01", min_length=0, max_length=100, num_mutations=100000, name="LENGTH Test Bit = 1") | ||
s_random("\x00", min_length=0, max_length=100, num_mutations=100000, name="DATA Test Bit") | ||
|
||
with s_block("ConfRev"): | ||
s_random("\x88", min_length=0, max_length=100, num_mutations=100000, name="TAG ConfRev") | ||
s_random("\x01", min_length=0, max_length=100, num_mutations=100000, name="LENGTH ConfRev = 1") | ||
s_random("\x01", min_length=0, max_length=100, num_mutations=100000, name="DATA ConfRev") | ||
|
||
with s_block("ndsCom"): | ||
s_random("\x89", min_length=0, max_length=100, num_mutations=100000, name="TAG ndsCom") | ||
s_random("\x01", min_length=0, max_length=100, num_mutations=100000, name="LENGTH ndsCom = 1") | ||
s_random("\x00", min_length=0, max_length=100, num_mutations=100000, name="DATA ndsCom") | ||
|
||
with s_block("numDatSetEntries"): | ||
s_random("\x8a", min_length=0, max_length=100, num_mutations=100000, name="TAG numDatSetEntries") | ||
s_random("\x01", min_length=0, max_length=100, num_mutations=100000, name="LENGTH numDatSetEntries = 1") | ||
s_random("\x03", min_length=0, max_length=100, num_mutations=100000, name="DATA numDatSetEntries") | ||
|
||
with s_block("allData"): | ||
s_random("\xab", min_length=0, max_length=100, num_mutations=100000, name="TAG allData") | ||
s_random("\x10", min_length=0, max_length=100, num_mutations=100000, name="LENGTH allData = 16") | ||
|
||
with s_block("data 1"): | ||
s_random("\x85", min_length=0, max_length=100, num_mutations=100000, name="TAG data 1 = integer") | ||
s_random("\x02", min_length=0, max_length=100, num_mutations=100000, name="LENGTH data 1 = 2") | ||
s_random("\x04\xd2", min_length=0, max_length=100, num_mutations=100000, name="DATA data 1") | ||
|
||
with s_block("data 2"): | ||
s_random("\x8c", min_length=0, max_length=100, num_mutations=100000, name="TAG data 2 = binary-time") | ||
s_random("\x06", min_length=0, max_length=100, num_mutations=100000, name="LENGTH data 2 = 6") | ||
s_random("\x00\x00\x00\x00\x00\x00", min_length=0, max_length=100, num_mutations=100000, name="DATA data 2") | ||
|
||
with s_block("data 3"): | ||
s_random("\x85", min_length=0, max_length=100, num_mutations=100000, name="TAG data 3 = integer") | ||
s_random("\x02", min_length=0, max_length=100, num_mutations=100000, name="LENGTH data 3 = 2") | ||
s_random("\x16\x2e", min_length=0, max_length=100, num_mutations=100000, name="DATA data 3") | ||
|
||
session.connect(s_get('goose_msg')) | ||
|
||
|
||
def GOOSEFuzz(eth0): | ||
try: | ||
session = Session( | ||
target=Target( | ||
connection=RawL2SocketConnection(interface=eth0, ethernet_proto=33024) | ||
), | ||
) | ||
except ValueError as value_error: | ||
sys.stderr.write('Error: {}'.format(value_error)) | ||
|
||
initialize_goose(session) | ||
|
||
session.fuzz() | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
from boofuzz import * | ||
import binascii | ||
import logging | ||
import socket | ||
import sys | ||
|
||
def isServiceExposed(host, port): | ||
logging.info("Searching Fuzz service on %s:%s" % (host, port)) | ||
|
||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: | ||
try: | ||
s.settimeout(5.0) | ||
s.connect((host, int(port))) | ||
return True | ||
except socket.error: | ||
return False | ||
|
||
def IEC104Fuzz(host, port): | ||
session = Session( | ||
target=Target( | ||
connection=SocketConnection(host, int(port), proto='tcp') | ||
), | ||
# sleep_time=1, | ||
# receive_data_after_fuzz=True | ||
) | ||
|
||
# STARTDT: | ||
# 0x68, -> start | ||
# 0x04, -> APDU len | ||
# 0x07, -> type 0000 0111 | ||
# 0x00, 0x00, 0x00 -> padding | ||
|
||
s_initialize("iec_startdt") | ||
if s_block_start("iec_apcii"): | ||
s_byte(0x68, name="start",fuzzable=False) | ||
s_byte(0x04, name="apdu_length", fuzzable=False) | ||
# s_dword(0x07000000, name="type", fuzzable=False) | ||
s_static("\x07\x00\x00\x00") | ||
s_block_end("iec_apci") | ||
|
||
s_initialize("iec_apci_empty") | ||
if s_block_start("iec_apci"): | ||
s_byte(0x68, name="start",fuzzable=False) | ||
s_byte(0x04, name="apdu_length", fuzzable=False) | ||
# s_dword(0x01000000, name="type", fuzzable=False) | ||
s_static("\x01\x00\x00\x00") | ||
s_block_end("iec_apci") | ||
|
||
s_initialize("iec_clock_sync") | ||
if s_block_start("iec_apci"): | ||
s_byte(0x68, name="start",fuzzable=False) | ||
s_byte(0x14, name="apdu_length", fuzzable=True) | ||
s_dword(0x000000, name="type", fuzzable=False) | ||
if s_block_start("iec_asdu"): | ||
s_byte(0x67, name="type_id",fuzzable=False) # C_CS_NA_1 Act | ||
s_byte(0x01, name="sq_plus_no",fuzzable=True) # A-BBBBBBB (1-7 bit) | ||
s_byte(0x06, name="cot",fuzzable=True) # T-P/N-COT (1-1-6 bit) | ||
s_byte(0x00, name="org",fuzzable=False) # Originator Address | ||
s_word(0xffff, name="com",fuzzable=True) # Common Address of ASDU | ||
if s_block_start("iec_ioa"): # Information Object | ||
s_byte(0x67, name="ioa_1",fuzzable=True) # IOA: 3-byte length | ||
s_byte(0x67, name="ioa_2",fuzzable=True) | ||
s_byte(0x67, name="ioa_3",fuzzable=True) | ||
s_static("\xee\xd8\x09\x0c\x0c\x02\x14") # Fixed CP56Time: Feb 12, 2020 | ||
s_block_end("iec_ioa") | ||
s_block_end("iec_asdu") | ||
s_block_end("iec_apci") | ||
|
||
s_initialize("iec_inter_command") | ||
if s_block_start("iec_apci"): | ||
s_byte(0x68, name="start",fuzzable=False) | ||
s_byte(0x0e, name="apdu_length", fuzzable=True) | ||
# s_dword(0x02000000, name="type", fuzzable=False) | ||
s_static("\x02\x00\x00\x00") | ||
if s_block_start("iec_asdu"): | ||
s_byte(0x64, name="type_id",fuzzable=False) # C_IC_NA_1 Act | ||
s_byte(0x01, name="sq_plus_no",fuzzable=True) # A-BBBBBBB (1-7 bit) | ||
s_byte(0x06, name="cot",fuzzable=True) | ||
s_byte(0x00, name="org",fuzzable=False) | ||
s_word(0xffff, name="com",fuzzable=True) | ||
if s_block_start("iec_ioa"): | ||
s_byte(0x00, name="ioa_1",fuzzable=True) # IOA: 3-byte length | ||
s_byte(0x00, name="ioa_2",fuzzable=True) | ||
s_byte(0x00, name="ioa_3",fuzzable=True) | ||
s_byte(0x14, name="qoi",fuzzable=True) | ||
s_block_end("iec_ioa") | ||
s_block_end("iec_asdu") | ||
s_block_end("iec_apci") | ||
|
||
# IEC104 Flow | ||
# ----------------------------------------------- | ||
# STARTDT act -> | ||
# STARTDT con <- | ||
# C_CS_NA_1 Act (Clock syncronization command) -> | ||
# C_IC_NA_1 Act (Interrogation command) -> | ||
# M_EI_NA_1 Init (End of initialization) <- | ||
# M_SP_NA_1 Spont (Single-point information) <- | ||
# C_CI_NA_1 Act -> | ||
# C_IC_NA_1 ActCon <- | ||
|
||
session.connect(s_get('iec_startdt')) | ||
session.connect(s_get('iec_startdt'), s_get("iec_clock_sync")) | ||
session.connect(s_get("iec_clock_sync"), s_get("iec_inter_command")) | ||
session.fuzz() | ||
# session.connect(s_get('iec_startdt'), s_get("iec_apci_empty")) | ||
# session.connect(s_get("iec_apci_empty"), s_get("iec_clock_sync")) | ||
# session.connect(s_get("iec_apci_empty"), s_get("iec_inter_command")) | ||
# session.connect(s_get("iec_clock_sync"), s_get("iec_inter_command")) | ||
# session.fuzz() | ||
|
Oops, something went wrong.