Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ab58593
Implement CMS signing/verification
gpotter2 Sep 21, 2025
f8e39d5
Implement PKINIT in AS-REQ + Improve SPNEGOSSP getter
gpotter2 Sep 25, 2025
a2bb2a0
NTLM: add old variant support
gpotter2 Sep 25, 2025
d931590
DCE/RPC: improve context handling
gpotter2 Oct 19, 2025
755b700
Kerberos: fix passive with DCE/RPC + improve deleg
gpotter2 Oct 19, 2025
55277c8
MS-NRPC: support Kerberos secure channel
gpotter2 Oct 19, 2025
cd4b7a5
Fix case in Kerberos check
gpotter2 Nov 2, 2025
8d9d1f3
HTTP client: allow to drop channel bindings
gpotter2 Nov 26, 2025
60291c7
Add Kerberos doc
gpotter2 Nov 26, 2025
8fe1193
PEP8 fixes
gpotter2 Nov 26, 2025
5ab0ae2
Cert.py: fix TreeChain tests
gpotter2 Nov 26, 2025
8fff3d9
Add missing NETLOGON flags
gpotter2 Dec 1, 2025
144df4e
SPNEGO: support reading KRB5CCNAME
gpotter2 Dec 1, 2025
1719971
SPNEGO: add tests & fix bugs
gpotter2 Dec 1, 2025
d14731c
Update IKEv2 tests with new X509_AlgorithmIdentifier
gpotter2 Dec 12, 2025
5915554
doc: add FAST documentation
gpotter2 Dec 12, 2025
5981bbb
More correct omit
gpotter2 Dec 12, 2025
064221d
PEP8 & CI
gpotter2 Dec 12, 2025
b8daa97
Fix send test
gpotter2 Dec 12, 2025
7ea2540
Handle missing cryptography
gpotter2 Dec 12, 2025
a207766
SPNEGO: big refactor
gpotter2 Dec 15, 2025
ed7f1f1
Increase debugging logs
gpotter2 Dec 15, 2025
9c1e909
Add CSR parsing
gpotter2 Dec 22, 2025
d32ccfa
cryptography test: include more crypto tests
gpotter2 Dec 22, 2025
08c3315
Remove spnego.uts from test configurations
gpotter2 Dec 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/cifuzz.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: CIFuzz

on:
pull_request:
push:
branches: [master]

permissions:
Expand Down
33 changes: 31 additions & 2 deletions doc/scapy/layers/kerberos.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ This section tries to give many usage examples, but isn't exhaustive. For more d
>>> t.show()
Tickets:
0. Administrator@DOMAIN.LOCAL -> krbtgt/DOMAIN.LOCAL@DOMAIN.LOCAL
Start time End time Renew until Auth time
Start time End time Renew until Auth time
31/08/23 11:38:34 31/08/23 21:38:34 31/08/23 21:38:35 31/08/23 01:38:34

1. Administrator@DOMAIN.LOCAL -> host/dc1.domain.local@DOMAIN.LOCAL
Start time End time Renew until Auth time
Start time End time Renew until Auth time
31/08/23 11:39:07 31/08/23 21:38:34 31/08/23 21:38:35 31/08/23 01:38:34


Expand All @@ -68,12 +68,41 @@ This section tries to give many usage examples, but isn't exhaustive. For more d
>>> # Using the AES-256-SHA1-96 Kerberos Key
>>> t.request_tgt("Administrator@domain.local", key=Key(EncryptionType.AES256_CTS_HMAC_SHA1_96, bytes.fromhex("63a2577d8bf6abeba0847cded36b9aed202c23750eb9c56b6155be1cc946bb1d")))

- **Request a TGT using PKINIT**:

.. code:: pycon

>>> from scapy.libs.rfc3961 import EncryptionType
>>> load_module("ticketer")
>>> t = Ticketer()
>>> # If P12:
>>> t.request_tgt("Administrator@DOMAIN.LOCAL", p12="admin.pfx", ca="ca.pem")
>>> # One could also have used a different cert and key file:
>>> t.request_tgt("Administrator@DOMAIN.LOCAL", x509="admin.cert", x509key="admin.key", ca="ca.pem")

- **Request a user TGT with Kerberos armoring (FAST)**

The ``armor_with`` keyword allows to select a ticket to armor the request with.

.. code:: pycon

>>> load_module("ticketer")
>>> t = Ticketer()
>>> t.request_tgt("Machine01$@DOMAIN.LOCAL", key=Key(EncryptionType.RC4_HMAC, bytes.fromhex("2b576acbe6bcfda7294d6bd18041b8fe")))
>>> t.show()
Tickets:
0. Machine01$@DOMAIN.LOCAL -> krbtgt/DOMAIN.LOCAL@DOMAIN.LOCAL
Start time End time Renew until Auth time
31/08/23 11:38:34 31/08/23 21:38:34 31/08/23 21:38:35 31/08/23 01:38:34
>>> t.request_tgt("Administrator@domain.local", armor_with=0) # Armor with ticket n°0

- **Renew a TGT or ST**:

.. code::

>>> t.renew(0) # renew TGT
>>> t.renew(1) # renew ST. Works only with 'host/' SPNs
>>> t.renew(1, armor_with=0) # renew something with armoring

- **Import tickets from a ccache**:

Expand Down
54 changes: 50 additions & 4 deletions scapy/asn1/mib.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,16 +284,25 @@ def load_mib(filenames):
"1.3.101.113": "Ed448",
}

# pkcs3 #

pkcs3_oids = {
"1.2.840.113549.1.3": "pkcs-3",
"1.2.840.113549.1.3.1": "dhKeyAgreement",
}

# pkcs7 #

pkcs7_oids = {
"1.2.840.113549.1.7": "pkcs-7",
"1.2.840.113549.1.7.2": "id-signedData",
"1.2.840.113549.1.7.3": "id-envelopedData",
}

# pkcs9 #

pkcs9_oids = {
"1.2.840.113549.1.9": "pkcs9",
"1.2.840.113549.1.9": "pkcs-9",
"1.2.840.113549.1.9.0": "modules",
"1.2.840.113549.1.9.1": "emailAddress",
"1.2.840.113549.1.9.2": "unstructuredName",
Expand All @@ -320,6 +329,13 @@ def load_mib(filenames):
"1.2.840.113549.1.9.52": "id-aa-CMSAlgorithmProtection"
}

# enc algs #

encAlgs_oids = {
"1.2.840.113549.3.4": "rc4",
"1.2.840.113549.3.7": "des-ede3-cbc",
}

# x509 #

attributeType_oids = {
Expand Down Expand Up @@ -492,10 +508,21 @@ def load_mib(filenames):
"2.5.29.67": "id-ce-allowedAttAss",
"2.5.29.68": "id-ce-attributeMappings",
"2.5.29.69": "id-ce-holderNameConstraints",
# [MS-WCCE]
"1.3.6.1.4.1.311.2.1.14": "CERT_EXTENSIONS",
"1.3.6.1.4.1.311.10.3.4": "szOID_EFS_CRYPTO",
# [MS-WCCE] + wincrypt.h
"1.3.6.1.4.1.311.2.1.14": "OID_CERT_EXTENSIONS",
"1.3.6.1.4.1.311.10.3.4": "OID_EFS_CRYPTO",
"1.3.6.1.4.1.311.13.2.1": "OID_ENROLLMENT_NAME_VALUE_PAIR",
"1.3.6.1.4.1.311.13.2.2": "OID_ENROLLMENT_CSP_PROVIDER",
"1.3.6.1.4.1.311.13.2.3": "OID_OS_VERSION",
"1.3.6.1.4.1.311.10.10.1": "OID_CMC_ADD_ATTRIBUTES",
"1.3.6.1.4.1.311.20.2": "ENROLL_CERTTYPE",
"1.3.6.1.4.1.311.21.10": "OID_APPLICATION_CERT_POLICIES",
"1.3.6.1.4.1.311.21.20": "OID_REQUEST_CLIENT_INFO",
"1.3.6.1.4.1.311.21.23": "OID_ENROLL_EK_INFO",
"1.3.6.1.4.1.311.21.24": "OID_ENROLL_ATTESTATION_STATEMENT",
"1.3.6.1.4.1.311.21.25": "OID_ENROLL_KSP_NAME",
"1.3.6.1.4.1.311.21.39": "OID_ENROLL_AIK_INFO",
"1.3.6.1.4.1.311.21.7": "OID_CERTIFICATE_TEMPLATE",
"1.3.6.1.4.1.311.25.1": "NTDS_REPLICATION",
"1.3.6.1.4.1.311.25.2": "NTDS_CA_SECURITY_EXT",
"1.3.6.1.4.1.311.25.2.1": "NTDS_OBJECTSID",
Expand Down Expand Up @@ -551,6 +578,15 @@ def load_mib(filenames):
"1.3.6.1.5.5.7.3.22": "secureShellServer"
}

certPkixCmc_oids = {
"1.3.6.1.5.5.7.7.8": "id-cmc-addExtensions",
}

certPkixCct_oids = {
"1.3.6.1.5.5.7.12.2": "id-cct-PKIData",
"1.3.6.1.5.5.7.12.3": "id-cct-PKIResponse",
}

certPkixAd_oids = {
"1.3.6.1.5.5.7.48.1": "ocsp",
"1.3.6.1.5.5.7.48.2": "caIssuers",
Expand All @@ -563,6 +599,11 @@ def load_mib(filenames):
"1.3.6.1.5.5.7.48.1.1": "basic-response"
}

certIpsec_oids = {
"1.3.6.1.5.5.8.2.1": "iKEEnd",
"1.3.6.1.5.5.8.2.2": "iKEIntermediate",
}

certTransp_oids = {
'1.3.6.1.4.1.11129.2.4.2': "SignedCertificateTimestampList",
}
Expand Down Expand Up @@ -724,16 +765,21 @@ def load_mib(filenames):
secsig_oids,
nist_oids,
thawte_oids,
pkcs3_oids,
pkcs7_oids,
pkcs9_oids,
encAlgs_oids,
attributeType_oids,
certificateExtension_oids,
certExt_oids,
certPkixAd_oids,
certPkixKp_oids,
certPkixCmc_oids,
certPkixCct_oids,
certPkixPe_oids,
certPkixQt_oids,
certPolicy_oids,
certIpsec_oids,
certTransp_oids,
evPolicy_oids,
x962KeyType_oids,
Expand Down
28 changes: 22 additions & 6 deletions scapy/asn1fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
BER_tagging_enc,
)
from scapy.base_classes import BasePacket
from scapy.compat import raw
from scapy.volatile import (
GeneralizedTime,
RandChoice,
Expand Down Expand Up @@ -599,7 +598,7 @@ def build(self, pkt):
elif val is None:
s = b""
else:
s = b"".join(raw(i) for i in val)
s = b"".join(bytes(i) for i in val)
return self.i2m(pkt, s)

def i2repr(self, pkt, x):
Expand Down Expand Up @@ -642,6 +641,9 @@ class ASN1F_TIME_TICKS(ASN1F_INTEGER):
#############################

class ASN1F_optional(ASN1F_element):
"""
ASN.1 field that is optional.
"""
def __init__(self, field):
# type: (ASN1F_field[Any, Any]) -> None
field.flexible_tag = False
Expand Down Expand Up @@ -682,6 +684,20 @@ def i2repr(self, pkt, x):
return self._field.i2repr(pkt, x)


class ASN1F_omit(ASN1F_field[None, None]):
"""
ASN.1 field that is not specified. This is simply omitted on the network.
This is different from ASN1F_NULL which has a network representation.
"""
def m2i(self, pkt, s):
# type: (ASN1_Packet, bytes) -> Tuple[None, bytes]
return None, s

def i2m(self, pkt, x):
# type: (ASN1_Packet, Optional[bytes]) -> bytes
return b""


_CHOICE_T = Union['ASN1_Packet', Type[ASN1F_field[Any, Any]], 'ASN1F_PACKET']


Expand Down Expand Up @@ -769,7 +785,7 @@ def i2m(self, pkt, x):
if x is None:
s = b""
else:
s = raw(x)
s = bytes(x)
if hash(type(x)) in self.pktchoices:
imp, exp = self.pktchoices[hash(type(x))]
s = BER_tagging_enc(s,
Expand Down Expand Up @@ -852,11 +868,11 @@ def i2m(self,
s = x
elif isinstance(x, ASN1_Object):
if x.val:
s = raw(x.val)
s = bytes(x.val)
else:
s = b""
else:
s = raw(x)
s = bytes(x)
if not hasattr(x, "ASN1_root"):
# A normal Packet (!= ASN1)
return s
Expand Down Expand Up @@ -897,7 +913,7 @@ def __init__(self,
self.cls = cls
super(ASN1F_BIT_STRING_ENCAPS, self).__init__( # type: ignore
name,
default and raw(default),
default and bytes(default),
context=context,
implicit_tag=implicit_tag,
explicit_tag=explicit_tag
Expand Down
11 changes: 9 additions & 2 deletions scapy/layers/dcerpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,14 @@ class RPC_C_AUTHN_LEVEL(IntEnum):
DCE_C_AUTHN_LEVEL = RPC_C_AUTHN_LEVEL # C706 name


class RPC_C_IMP_LEVEL(IntEnum):
DEFAULT = 0x0
ANONYMOUS = 0x1
IDENTIFY = 0x2
IMPERSONATE = 0x3
DELEGATE = 0x4


# C706 sect 13.2.6.1


Expand Down Expand Up @@ -2766,9 +2774,9 @@ def __init__(self, *args, **kwargs):
self.ssp = kwargs.pop("ssp", None)
self.sspcontext = kwargs.pop("sspcontext", None)
self.auth_level = kwargs.pop("auth_level", None)
self.auth_context_id = kwargs.pop("auth_context_id", 0)
self.sent_cont_ids = []
self.cont_id = 0 # Currently selected context
self.auth_context_id = 0 # Currently selected authentication context
self.map_callid_opnum = {}
self.frags = collections.defaultdict(lambda: b"")
self.sniffsspcontexts = {} # Unfinished contexts for passive
Expand Down Expand Up @@ -3283,7 +3291,6 @@ def __init__(self, *args, **kwargs):
self.session = DceRpcSession(
ssp=kwargs.pop("ssp", None),
auth_level=kwargs.pop("auth_level", None),
auth_context_id=kwargs.pop("auth_context_id", None),
support_header_signing=kwargs.pop("support_header_signing", True),
)
super(DceRpcSocket, self).__init__(*args, **kwargs)
Expand Down
Loading
Loading