Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangdebiao committed Sep 21, 2021
0 parents commit 916976d
Show file tree
Hide file tree
Showing 14 changed files with 1,548 additions and 0 deletions.
26 changes: 26 additions & 0 deletions README.md
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
```

66 changes: 66 additions & 0 deletions main.py
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 added util/__init__.py
Empty file.
Binary file added util/__pycache__/__init__.cpython-39.pyc
Binary file not shown.
Binary file added util/__pycache__/goose.cpython-39.pyc
Binary file not shown.
Binary file added util/__pycache__/iec104.cpython-39.pyc
Binary file not shown.
Binary file added util/__pycache__/mms.cpython-39.pyc
Binary file not shown.
Binary file added util/__pycache__/modbus.cpython-39.pyc
Binary file not shown.
Binary file added util/__pycache__/sampled_values.cpython-39.pyc
Binary file not shown.
127 changes: 127 additions & 0 deletions util/goose.py
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()


110 changes: 110 additions & 0 deletions util/iec104.py
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()

Loading

0 comments on commit 916976d

Please sign in to comment.