add siemens s7 scanner

This commit is contained in:
Justin Bastress 2018-03-22 17:06:44 -04:00
parent 1508e01582
commit 13c4944e91
8 changed files with 777 additions and 13 deletions

7
modules/siemens.go Normal file
View File

@ -0,0 +1,7 @@
package modules
import "github.com/zmap/zgrab2/modules/siemens"
func init() {
siemens.RegisterModule()
}

30
modules/siemens/common.go Normal file
View File

@ -0,0 +1,30 @@
package siemens
import "errors"
var (
errS7PacketTooShort = errors.New("s7 packet too short")
errInvalidPacket = errors.New("invalid S7 packet")
errNotS7 = errors.New("not a S7 packet")
)
// S7Error provides an interface to get S7 errors.
type S7Error struct{}
var (
// S7_ERROR_CODES maps error codes to the friendly error string
S7_ERROR_CODES = map[uint32]string{
// s7 data errors
0x05: "address error",
0x0a: "item not available",
// s7 header errors
0x8104: "context not supported",
0x8500: "wrong PDU size",
}
)
// New gets an S7 error instance for the given error code.
// TODO: Shouldn't it be sharing a single error instance, rather than returning a new error instance each time?
func (s7Error *S7Error) New(errorCode uint32) error {
return errors.New(S7_ERROR_CODES[errorCode])
}

49
modules/siemens/log.go Normal file
View File

@ -0,0 +1,49 @@
package siemens
// S7Log is the output type for the Siemens S7 scan.
type S7Log struct {
// IsS7 indicates that S7 was actually detected, so it should always be true.
IsS7 bool `json:"is_s7"`
// System is the first field returned in the component ID response.
System string `json:"system,omitempty"`
// Module is the second field returned in the component ID response.
Module string `json:"module,omitempty"`
// PlantId is the third field returned in the component ID response.
PlantId string `json:"plant_id,omitempty"`
// Copyright is the fourth field returned in the component ID response.
Copyright string `json:"copyright,omitempty"`
// SerialNumber is the fifth field returned in the component ID response.
SerialNumber string `json:"serial_number,omitempty"`
// ModuleType is the sixth field returned in the component ID response.
ModuleType string `json:"module_type,omitempty"`
// ReservedForOS is the seventh field returned in the component ID response.
ReservedForOS string `json:"reserved_for_os,omitempty"`
// MemorySerialNumber is the eighth field returned in the component ID response.
MemorySerialNumber string `json:"memory_serial_number,omitempty"`
// CpuProfile is the ninth field returned in the component ID response.
CpuProfile string `json:"cpu_profile,omitempty"`
// OemId is the tenth field returned in the component ID response.
OEMId string `json:"oem_id,omitempty"`
// Location is the eleventh field returned in the component ID response.
Location string `json:"location,omitempty"`
// ModuleId is the first field returned in the module identification response.
ModuleId string `json:"module_id,omitempty"`
// Hardware is the second field returned in the module identification response.
Hardware string `json:"hardware,omitempty"`
// Fiirmware is the third field returned in the module identification response.
Firmware string `json:"firmware,omitempty"`
}

240
modules/siemens/messages.go Normal file
View File

@ -0,0 +1,240 @@
package siemens
import (
"encoding/binary"
"errors"
)
// TPKTPacket is defined in RFC 1006
type TPKTPacket struct {
// Data is the packet's content
Data []byte
}
const tpktLength = 4 // 4 bytes (excluding Data slice)
// Marshal encodes a TPKTPacket to binary.
func (tpktPacket *TPKTPacket) Marshal() ([]byte, error) {
totalLength := len(tpktPacket.Data) + tpktLength
bytes := make([]byte, 0, totalLength)
bytes = append(bytes, byte(3)) // version
bytes = append(bytes, byte(0)) // reserved
uint16BytesHolder := make([]byte, 2)
binary.BigEndian.PutUint16(uint16BytesHolder, uint16(totalLength))
bytes = append(bytes, uint16BytesHolder...)
bytes = append(bytes, tpktPacket.Data...)
return bytes, nil
}
// Unmarshal decodes a TPKTPacket from binary.
func (tpktPacket *TPKTPacket) Unmarshal(bytes []byte) error {
if len(bytes) < tpktLength {
return errS7PacketTooShort
}
tpktPacket.Data = bytes[tpktLength:]
return nil
}
// COTPConnectionPacket is defined in RFC 892.
type COTPConnectionPacket struct {
// DestinationRef is the DST-REF TPDU field
DestinationRef uint16
// SourceRef is the SCE-REF TPDU field
SourceRef uint16
// DestinationTSAP is the destination transport service access point.
DestinationTSAP uint16
// SourceTSAP is the source transport service access point.
SourceTSAP uint16
// TPDUSize is the size (in bytes) of the TPDU
TPDUSize byte
}
const cotpConnRequestLength = 18
// Marshal encodes a COTPConnectionPacket to binary.
func (cotpConnPacket *COTPConnectionPacket) Marshal() ([]byte, error) {
bytes := make([]byte, 0, cotpConnRequestLength)
uint16BytesHolder := make([]byte, 2)
bytes = append(bytes, byte(cotpConnRequestLength-1)) // length of packet (excluding 1-byte length header)
bytes = append(bytes, byte(0xe0)) // connection request code
binary.BigEndian.PutUint16(uint16BytesHolder, cotpConnPacket.DestinationRef)
bytes = append(bytes, uint16BytesHolder...)
binary.BigEndian.PutUint16(uint16BytesHolder, cotpConnPacket.SourceRef)
bytes = append(bytes, uint16BytesHolder...)
bytes = append(bytes, byte(0)) // class 0 transport protocol with no flags
bytes = append(bytes, byte(0xc1)) // code for identifier of the calling TSAP field
bytes = append(bytes, byte(2)) // byte-length of subsequent field SourceTSAP
binary.BigEndian.PutUint16(uint16BytesHolder, cotpConnPacket.SourceTSAP)
bytes = append(bytes, uint16BytesHolder...)
bytes = append(bytes, byte(0xc2)) // code fo identifier of the called TSAP field
bytes = append(bytes, byte(2)) // byte-length of subsequent field DestinationTSAP
binary.BigEndian.PutUint16(uint16BytesHolder, cotpConnPacket.DestinationTSAP)
bytes = append(bytes, uint16BytesHolder...)
bytes = append(bytes, byte(0xc0)) // code for proposed maximum TPDU size field
bytes = append(bytes, byte(1)) // byte-length of subsequent field
bytes = append(bytes, cotpConnPacket.TPDUSize)
return bytes, nil
}
// Unmarshal decodes a COTPConnectionPacket from binary that must be a connection confirmation.
func (cotpConnPacket *COTPConnectionPacket) Unmarshal(bytes []byte) error {
if bytes == nil || len(bytes) < 2 {
return errInvalidPacket
}
if sizeByte := bytes[0]; int(sizeByte)+1 != len(bytes) {
return errS7PacketTooShort
}
if pduType := bytes[1]; pduType != 0xd0 {
return errors.New("Not a connection confirmation packet")
}
// TODO: implement these fields with proper bounds checking
// cotpConnPacket.DestinationRef = binary.BigEndian.Uint16(bytes[2:4])
// cotpConnPacket.SourceRef = binary.BigEndian.Uint16(bytes[4:6])
// cotpConnPacket.DestinationTSAP
// cotpConnPacket.SourceTSAP
// cotpConnPacket.TPDUSize
return nil
}
// COTPDataPacket wraps the state / interface for a COTP data packet.
type COTPDataPacket struct {
Data []byte
}
const cotpDataPacketHeaderLength = 2
// Marshal encodes a COTPDataPacket to binary.
func (cotpDataPacket *COTPDataPacket) Marshal() ([]byte, error) {
bytes := make([]byte, 0, cotpDataPacketHeaderLength+len(cotpDataPacket.Data))
bytes = append(bytes, byte(2)) // data header length
bytes = append(bytes, byte(0xf0)) // code for data packet
bytes = append(bytes, byte(0x80)) // code for data packet
bytes = append(bytes, cotpDataPacket.Data...)
return bytes, nil
}
// Unmarshal decodes a COTPDataPacket from binary.
func (cotpDataPacket *COTPDataPacket) Unmarshal(bytes []byte) error {
if bytes == nil || len(bytes) < 1 {
return errInvalidPacket
}
headerSize := bytes[0]
if int(headerSize+1) > len(bytes) {
return errInvalidPacket
}
cotpDataPacket.Data = bytes[headerSize+1:]
return nil
}
// S7Packet represents an S7 packet.
type S7Packet struct {
PDUType byte
RequestId uint16
Parameters []byte
Data []byte
Error uint16
}
const (
S7_PROTOCOL_ID = byte(0x32)
S7_REQUEST_ID = uint16(0)
S7_REQUEST = byte(0x01)
S7_REQUEST_USER_DATA = byte(0x07)
S7_ACKNOWLEDGEMENT = byte(0x02)
S7_RESPONSE = byte(0x03)
S7_SZL_REQUEST = byte(0x04)
S7_SZL_FUNCTIONS = byte(0x04)
S7_SZL_READ = byte(0x01)
S7_SZL_MODULE_IDENTIFICATION = uint16(0x11)
S7_SZL_COMPONENT_IDENTIFICATION = uint16(0x1c)
S7_DATA_BYTE_OFFSET = 12 // offset for real data
)
const s7PacketHeaderLength = 3
// Marshal encodes a S7Packet to binary.
func (s7Packet *S7Packet) Marshal() ([]byte, error) {
if s7Packet.PDUType != S7_REQUEST && s7Packet.PDUType != S7_REQUEST_USER_DATA {
return nil, errors.New("Invalid PDU request type")
}
bytes := make([]byte, 0, s7PacketHeaderLength+len(s7Packet.Data))
uint16BytesHolder := make([]byte, 2)
bytes = append(bytes, S7_PROTOCOL_ID) // s7 protocol id
bytes = append(bytes, s7Packet.PDUType)
binary.BigEndian.PutUint16(uint16BytesHolder, 0)
bytes = append(bytes, uint16BytesHolder...) // reserved
binary.BigEndian.PutUint16(uint16BytesHolder, s7Packet.RequestId)
bytes = append(bytes, uint16BytesHolder...)
binary.BigEndian.PutUint16(uint16BytesHolder, uint16(len(s7Packet.Parameters)))
bytes = append(bytes, uint16BytesHolder...)
binary.BigEndian.PutUint16(uint16BytesHolder, uint16(len(s7Packet.Data)))
bytes = append(bytes, uint16BytesHolder...)
bytes = append(bytes, s7Packet.Parameters...)
bytes = append(bytes, s7Packet.Data...)
return bytes, nil
}
// Unmarshal decodes a S7Packet from binary.
func (s7Packet *S7Packet) Unmarshal(bytes []byte) (err error) {
if bytes == nil || len(bytes) < 1 {
return errInvalidPacket
}
if protocolId := bytes[0]; protocolId != S7_PROTOCOL_ID {
return errNotS7
}
var headerSize int
pduType := bytes[1]
if pduType == S7_ACKNOWLEDGEMENT || pduType == S7_RESPONSE {
headerSize = 12
s7Packet.Error = binary.BigEndian.Uint16(bytes[10:12])
} else if pduType == S7_REQUEST || pduType == S7_REQUEST_USER_DATA {
headerSize = 10
} else {
return errors.New("Unknown PDU type " + string(pduType))
}
s7Packet.PDUType = pduType
s7Packet.RequestId = binary.BigEndian.Uint16(bytes[4:6])
paramLength := int(binary.BigEndian.Uint16(bytes[6:8]))
dataLength := int(binary.BigEndian.Uint16(bytes[8:10]))
if paramLength < 0 || dataLength < 0 || headerSize+paramLength+dataLength > len(bytes) {
return errInvalidPacket
}
s7Packet.Parameters = bytes[headerSize : headerSize+paramLength]
s7Packet.Data = bytes[headerSize+paramLength : headerSize+paramLength+dataLength]
return nil
}

297
modules/siemens/s7.go Normal file
View File

@ -0,0 +1,297 @@
package siemens
import (
"bytes"
"encoding/binary"
"net"
)
// ReconnectFunction is used to re-connect to the target to re-try the scan with a different TSAP destination.
type ReconnectFunction func() (net.Conn, error)
// GetS7Banner scans the target for S7 information, reconnecting if necessary.
func GetS7Banner(logStruct *S7Log, connection net.Conn, reconnect ReconnectFunction) (err error) {
// Attempt connection
var connPacketBytes, connResponseBytes []byte
connPacketBytes, err = makeCOTPConnectionPacketBytes(uint16(0x102), uint16(0x100))
if err != nil {
return err
}
connResponseBytes, err = sendRequestReadResponse(connection, connPacketBytes)
if connResponseBytes == nil || len(connResponseBytes) == 0 || err != nil {
connection.Close()
connection, err = reconnect()
if err != nil {
return err
}
connPacketBytes, err = makeCOTPConnectionPacketBytes(uint16(0x200), uint16(0x100))
if err != nil {
return err
}
connResponseBytes, err = sendRequestReadResponse(connection, connPacketBytes)
if err != nil {
return err
}
}
_, err = unmarshalCOTPConnectionResponse(connResponseBytes)
if err != nil {
return err
}
// Negotiate S7
requestPacketBytes, err := makeRequestPacketBytes(S7_REQUEST, makeNegotiatePDUParamBytes(), nil)
if err != nil {
return err
}
_, err = sendRequestReadResponse(connection, requestPacketBytes)
if err != nil {
return err
}
logStruct.IsS7 = true
// Make Module Identification request
moduleIdentificationResponse, err := readRequest(connection, S7_SZL_MODULE_IDENTIFICATION)
if err != nil {
return nil // mask errors after detecting IsS7
}
parseModuleIdentificatioNRequest(logStruct, &moduleIdentificationResponse)
// Make Component Identification request
componentIdentificationResponse, err := readRequest(connection, S7_SZL_COMPONENT_IDENTIFICATION)
if err != nil {
return nil // mask errors after detecting IsS7
}
parseComponentIdentificationResponse(logStruct, &componentIdentificationResponse)
return nil
}
func makeCOTPConnectionPacketBytes(dstTsap uint16, srcTsap uint16) ([]byte, error) {
var cotpConnPacket COTPConnectionPacket
cotpConnPacket.DestinationRef = uint16(0x00) // nmap uses 0x00
cotpConnPacket.SourceRef = uint16(0x04) // nmap uses 0x14
cotpConnPacket.DestinationTSAP = dstTsap
cotpConnPacket.SourceTSAP = srcTsap
cotpConnPacket.TPDUSize = byte(0x0a) // nmap uses 0x0a
cotpConnPacketBytes, err := cotpConnPacket.Marshal()
if err != nil {
return nil, err
}
var tpktPacket TPKTPacket
tpktPacket.Data = cotpConnPacketBytes
bytes, err := tpktPacket.Marshal()
if err != nil {
return nil, err
}
return bytes, nil
}
func makeRequestPacketBytes(pduType byte, parameters []byte, data []byte) ([]byte, error) {
var s7Packet S7Packet
s7Packet.PDUType = pduType
s7Packet.RequestId = S7_REQUEST_ID
s7Packet.Parameters = parameters
s7Packet.Data = data
s7PacketBytes, err := s7Packet.Marshal()
if err != nil {
return nil, err
}
var cotpDataPacket COTPDataPacket
cotpDataPacket.Data = s7PacketBytes
cotpDataPacketBytes, err := cotpDataPacket.Marshal()
if err != nil {
return nil, err
}
var tpktPacket TPKTPacket
tpktPacket.Data = cotpDataPacketBytes
bytes, err := tpktPacket.Marshal()
if err != nil {
return nil, err
}
return bytes, nil
}
// Send a generic packet request and return the response
func sendRequestReadResponse(connection net.Conn, requestBytes []byte) ([]byte, error) {
connection.Write(requestBytes)
responseBytes := make([]byte, 2048)
bytesRead, err := connection.Read(responseBytes)
if err != nil {
return nil, err
}
return responseBytes[0:bytesRead], nil
}
func unmarshalCOTPConnectionResponse(responseBytes []byte) (cotpConnPacket COTPConnectionPacket, err error) {
var tpktPacket TPKTPacket
if err := tpktPacket.Unmarshal(responseBytes); err != nil {
return cotpConnPacket, err
}
if err := cotpConnPacket.Unmarshal(tpktPacket.Data); err != nil {
return cotpConnPacket, err
}
return cotpConnPacket, nil
}
func makeNegotiatePDUParamBytes() (bytes []byte) {
uint16BytesHolder := make([]byte, 2)
bytes = make([]byte, 0, 8) // fixed param length for negotiating PDU params
bytes = append(bytes, byte(0xf0)) // negotiate PDU function code
bytes = append(bytes, byte(0)) // ?
binary.BigEndian.PutUint16(uint16BytesHolder, 0x01)
bytes = append(bytes, uint16BytesHolder...) // min # of parallel jobs
binary.BigEndian.PutUint16(uint16BytesHolder, 0x01)
bytes = append(bytes, uint16BytesHolder...) // max # of parallel jobs
binary.BigEndian.PutUint16(uint16BytesHolder, 0x01e0)
bytes = append(bytes, uint16BytesHolder...) // pdu length
return bytes
}
func makeReadRequestParamBytes(data []byte) (bytes []byte) {
bytes = make([]byte, 0, 16)
bytes = append(bytes, byte(0x00)) // magic parameter
bytes = append(bytes, byte(0x01)) // magic parameter
bytes = append(bytes, byte(0x12)) // magic parameter
bytes = append(bytes, byte(0x04)) // param length
bytes = append(bytes, byte(0x11)) // ?
bytes = append(bytes, byte((S7_SZL_REQUEST*0x10)+S7_SZL_FUNCTIONS))
bytes = append(bytes, byte(S7_SZL_READ))
bytes = append(bytes, byte(0))
return bytes
}
func makeReadRequestDataBytes(szlId uint16) []byte {
bytes := make([]byte, 0, 4)
bytes = append(bytes, byte(0xff))
bytes = append(bytes, byte(0x09))
uint16BytesHolder := make([]byte, 2)
binary.BigEndian.PutUint16(uint16BytesHolder, uint16(4)) // size of subsequent data
bytes = append(bytes, uint16BytesHolder...)
binary.BigEndian.PutUint16(uint16BytesHolder, szlId)
bytes = append(bytes, uint16BytesHolder...) // szl id
binary.BigEndian.PutUint16(uint16BytesHolder, 1)
bytes = append(bytes, uint16BytesHolder...) // szl index
return bytes
}
func makeReadRequestBytes(szlId uint16) ([]byte, error) {
readRequestParamBytes := makeReadRequestParamBytes(makeReadRequestDataBytes(szlId))
readRequestBytes, err := makeRequestPacketBytes(S7_REQUEST_USER_DATA, readRequestParamBytes, makeReadRequestDataBytes(szlId))
if err != nil {
return nil, err
}
return readRequestBytes, nil
}
func unmarshalReadResponse(bytes []byte) (S7Packet, error) {
var tpktPacket TPKTPacket
var cotpDataPacket COTPDataPacket
var s7Packet S7Packet
if err := tpktPacket.Unmarshal(bytes); err != nil {
return s7Packet, err
}
if err := cotpDataPacket.Unmarshal(tpktPacket.Data); err != nil {
return s7Packet, err
}
if err := s7Packet.Unmarshal(cotpDataPacket.Data); err != nil {
return s7Packet, err
}
return s7Packet, nil
}
func parseComponentIdentificationResponse(logStruct *S7Log, s7Packet *S7Packet) error {
if len(s7Packet.Data) < S7_DATA_BYTE_OFFSET {
return errS7PacketTooShort
}
fields := bytes.FieldsFunc(s7Packet.Data[S7_DATA_BYTE_OFFSET:], func(c rune) bool {
return int(c) == 0
})
for i := len(fields) - 1; i >= 0; i-- {
switch i {
case 0:
logStruct.System = string(fields[i][1:]) // exclude index byte
case 1:
logStruct.Module = string(fields[i][1:])
case 2:
logStruct.PlantId = string(fields[i][1:])
case 3:
logStruct.Copyright = string(fields[i][1:])
case 4:
logStruct.SerialNumber = string(fields[i][1:])
case 5:
logStruct.ModuleType = string(fields[i][1:])
case 6:
logStruct.ReservedForOS = string(fields[i][1:])
case 7:
logStruct.MemorySerialNumber = string(fields[i][1:])
case 8:
logStruct.CpuProfile = string(fields[i][1:])
case 9:
logStruct.OEMId = string(fields[i][1:])
case 10:
logStruct.Location = string(fields[i][1:])
}
}
return nil
}
func parseModuleIdentificatioNRequest(logStruct *S7Log, s7Packet *S7Packet) error {
if len(s7Packet.Data) < S7_DATA_BYTE_OFFSET {
return errS7PacketTooShort
}
fields := bytes.FieldsFunc(s7Packet.Data[S7_DATA_BYTE_OFFSET:], func(c rune) bool {
return int(c) == 0
})
for i := len(fields) - 1; i >= 0; i-- {
switch i {
case 0:
logStruct.ModuleId = string(fields[i][1:]) // exclude index byte
case 5:
logStruct.Hardware = string(fields[i][1:])
case 6:
logStruct.Firmware = string(fields[i][1:])
}
}
return nil
}
func readRequest(connection net.Conn, slzId uint16) (packet S7Packet, err error) {
readRequestBytes, err := makeReadRequestBytes(slzId)
if err != nil {
return packet, err
}
readResponse, err := sendRequestReadResponse(connection, readRequestBytes)
if err != nil {
return packet, err
}
packet, err = unmarshalReadResponse(readResponse)
if err != nil {
return packet, err
}
return packet, nil
}

108
modules/siemens/scanner.go Normal file
View File

@ -0,0 +1,108 @@
// Package siemens provides a zgrab2 module that scans for Siemens S7.
// Default port: TCP 102
// Ported from the original zgrab. Input and output are identical.
package siemens
import (
log "github.com/sirupsen/logrus"
"github.com/zmap/zgrab2"
"net"
)
// Flags holds the command-line configuration for the siemens scan module.
// Populated by the framework.
type Flags struct {
zgrab2.BaseFlags
// TODO: configurable TSAP source / destination, etc
Verbose bool `long:"verbose" description:"More verbose logging, include debug fields in the scan results"`
}
// Module implements the zgrab2.Module interface.
type Module struct {
}
// Scanner implements the zgrab2.Scanner interface.
type Scanner struct {
config *Flags
}
// RegisterModule registers the zgrab2 module.
func RegisterModule() {
var module Module
_, err := zgrab2.AddCommand("siemens", "siemens", "Probe for Siemens S7", 102, &module)
if err != nil {
log.Fatal(err)
}
}
// NewFlags returns a default Flags object.
func (module *Module) NewFlags() interface{} {
return new(Flags)
}
// NewScanner returns a new Scanner instance.
func (module *Module) NewScanner() zgrab2.Scanner {
return new(Scanner)
}
// Validate checks that the flags are valid.
// On success, returns nil.
// On failure, returns an error instance describing the error.
func (flags *Flags) Validate(args []string) error {
return nil
}
// Help returns the module's help string.
func (flags *Flags) Help() string {
return ""
}
// Init initializes the Scanner.
func (scanner *Scanner) Init(flags zgrab2.ScanFlags) error {
f, _ := flags.(*Flags)
scanner.config = f
return nil
}
// InitPerSender initializes the scanner for a given sender.
func (scanner *Scanner) InitPerSender(senderID int) error {
return nil
}
// GetName returns the Scanner name defined in the Flags.
func (scanner *Scanner) GetName() string {
return scanner.config.Name
}
// Protocol returns the protocol identifier of the scan.
func (scanner *Scanner) Protocol() string {
return "siemens"
}
// GetPort returns the port being scanned.
func (scanner *Scanner) GetPort() uint {
return scanner.config.Port
}
// Scan probes for Siemens S7 services.
// 1. Connect to TCP port 102
// 2. Send a COTP connection packet with destination TSAP 0x0102, source TSAP 0x0100
// 3. If that fails, reconnect and send a COTP connection packet with destination TSAP 0x0200, source 0x0100
// 4. Negotiate S7
// 5. Request to read the module identification (and store it in the output)
// 6. Request to read the component identification (and store it in the output)
// 7. Return the output
func (scanner *Scanner) Scan(target zgrab2.ScanTarget) (zgrab2.ScanStatus, interface{}, error) {
conn, err := target.Open(&scanner.config.BaseFlags)
if err != nil {
return zgrab2.TryGetScanStatus(err), nil, err
}
defer conn.Close()
result := new(S7Log)
err = GetS7Banner(result, conn, func() (net.Conn, error){ return target.Open(&scanner.config.BaseFlags)})
if !result.IsS7 {
result = nil
}
return zgrab2.TryGetScanStatus(err), result, err
}

View File

@ -1,17 +1,18 @@
# Ensure that all of the modules get executed so that they are registered
import schemas.mysql
import schemas.ssh
import schemas.postgres
import schemas.http
import schemas.ftp
import schemas.ntp
import schemas.mssql
import schemas.redis
import schemas.smtp
import schemas.telnet
import schemas.pop3
import schemas.smb
import schemas.modbus
import schemas.bacnet
import schemas.dnp3
import schemas.fox
import schemas.ftp
import schemas.http
import schemas.modbus
import schemas.mssql
import schemas.mysql
import schemas.ntp
import schemas.pop3
import schemas.postgres
import schemas.redis
import schemas.siemens
import schemas.smb
import schemas.smtp
import schemas.ssh
import schemas.telnet

32
schemas/siemens.py Normal file
View File

@ -0,0 +1,32 @@
# zschema sub-schema for zgrab2's siemens module
# Registers zgrab2-siemens globally, and siemens with the main zgrab2 schema.
from zschema.leaves import *
from zschema.compounds import *
import zschema.registry
import schemas.zcrypto as zcrypto
import schemas.zgrab2 as zgrab2
siemens_scan_response = SubRecord({
'result': SubRecord({
'is_s7': Boolean(),
'system': String(),
'module': String(),
'plant_id': String(),
'copyright': String(),
'serial_number': String(),
'module_type': String(),
'reserved_for_os': String(),
'memory_serial_number': String(),
'cpu_profile': String(),
'oem_id': String(),
'location': String(),
'module_id': String(),
'hardware': String(),
'firmware': String(),
})
}, extends=zgrab2.base_scan_response)
zschema.registry.register_schema('zgrab2-siemens', siemens_scan_response)
zgrab2.register_scan_response_type('siemens', siemens_scan_response)