# encoding: utf-8
# pysap - Python library for crafting SAP's network protocols packets
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# 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.
#
# Author:
# Martin Gallo (@martingalloar)
# Code contributed by SecureAuth to the OWASP CBAS project
#
# External imports
from scapy.fields import (ByteField, ShortField, IntField, StrFixedLenField, FieldLenField, StrLenField,
ConditionalField, ByteEnumKeysField, ShortEnumKeysField)
# Custom imports
from pysap.utils.fields import (PacketNoPadded)
# SNC Frame Types
snc_frame_type = {
0x00: "REVERSE_REQ",
0x01: "INIT_REQ",
0x02: "INIT",
0x03: "INIT_ACK",
0x04: "ACCEPT",
0x05: "ACCEPT_ACK",
0x06: "ACCEPT_FAILED",
0x07: "DATA_OPEN",
0x08: "DATA_MIC/DATA_SIGNED",
0x09: "DATA_WRAP/DATA_SEALED",
0x0a: "SHUTDOWN",
0x0b: "SHUTDOWN_MSG",
0x0c: "REJECTED",
0x0d: "ERROR",
0x0e: "UNKNOWN",
}
# SNC Mech ID values
snc_mech_id_values = {
0x00: "No security",
0x01: "Generic GSS-API v2 Mechanism",
0x02: "Kerberos 5/GSS-API v2",
0x03: "Secude 5 GSS-API v2",
0x04: "SAP's GSS-API v2 over NTLM(SSPI)",
0x05: "SPKM1 GSS-API v2 library",
0x06: "SPKM2 GSS-API v2 library",
0x07: "reserved ID",
0x08: "itsec",
0x09: "SDTI Connect Agent",
0x0a: "AccessMaster DCE",
}
# SNC Quality of protection values
snc_qop = {
0x00: "INVALID",
0x01: "OPEN",
0x02: "INTEGRITY/SIGNED",
0x03: "PRIVACY/SEALED",
0x07: "MIN",
0x08: "DEFAULT",
0x09: "MAX",
}
[docs]class SAPSNCFrame(PacketNoPadded):
"""SAP SNC Frame packet
This packet is used to contain and wrap SNC Frames.
"""
name = "SAP SNC Frame"
fields_desc = [
StrFixedLenField("eye_catcher", "SNCFRAME", 8),
ByteEnumKeysField("frame_type", 2, snc_frame_type),
ByteField("protocol_version", 5),
ShortField("header_length", 24),
FieldLenField("token_length", 0, length_of="token", fmt="I"),
FieldLenField("data_length", 0, length_of="data", fmt="I"),
ShortEnumKeysField("mech_id", 3, snc_mech_id_values),
ShortField("flags", 0),
ConditionalField(IntField("ext_flags", 0), lambda pkt: pkt.header_length > 24),
ConditionalField(FieldLenField("ext_field_length", 0, length_of="ext_fields", fmt="!H"), lambda pkt: pkt.header_length > 24),
ConditionalField(StrLenField("ext_fields", "", length_from=lambda pkt:pkt.ext_field_length), lambda pkt: pkt.header_length > 24),
StrLenField("token", "", length_from=lambda pkt:pkt.token_length),
StrLenField("data", "", length_from=lambda pkt:pkt.data_length),
]
[docs]def unwrap_snc(s, offset):
"""Unwraps an SNC frame if it's possible. This is, if the frame type is
data open or signed but not encrypted. Appends the unwrapped data to the
end of the string being dissected and adjust the offset properly to skip
the SNC frame.
:param s: string to dissect
:type s: C{string}
:param offset: offset where the SNC frame starts
:type offset: int
:return: tuple of string with the SNC frame wrapped, adjusted offset
:rtype: tuple of C{string}, int
"""
snc_frame = SAPSNCFrame(s[offset:])
if snc_frame.frame_type in [0x07, 0x08] and snc_frame.data_length > 0:
s = s + snc_frame.data
offset += snc_frame.header_length + snc_frame.token_length + snc_frame.data_length
return s, offset
[docs]def wrap_snc(s, offset, data):
"""Wraps an SNC frame if it's possible. This is, if the frame type is
data open. Adds the data to the frame and properly updates the length
field on the SNC frame.
:param s: string to dissect
:type s: string
:param offset: offset where the SNC frame starts
:type offset: int
:param data: data to wrap
:type data: string
:return: string with the SNC frame wrapped
:rtype: string
"""
snc_frame = SAPSNCFrame(s[offset:])
if snc_frame.frame_type == 0x07:
snc_frame.data = data
snc_frame.data_length = len(data)
snc_frame_length = snc_frame.header_length + snc_frame.token_length + snc_frame.data_length
s = s[:offset] + str(snc_frame)[:snc_frame_length]
return s