GSSAPI

Scapy provides access to various Security Providers following the GSSAPI model, but aiming at interacting with the Windows world.

Note

The GSSAPI interfaces are based off the following documentations:

Usage

The following SSPs are currently provided:

Basically those are classes that implement two functions, trying to micmic the RFCs:

They both return the updated Context, a token to optionally send to the server/client and a GSSAPI status code.

Note

You can typically use it in SMB_Client, SMB_Server, DCERPC_Client or DCERPC_Server. Have a look at SMB and DCE/RPC to get examples on how to use it.

Let’s implement our own client that uses one of those SSPs.

Client

First let’s create the SSP. We’ll take NTLMSSP as an example but the others would work just as well.

from scapy.layers.ntlm import *
clissp = NTLMSSP(
    UPN="Administrator@domain.local",
    PASSWORD="Password1!",
)

Let’s get the first token (in this case, the ntlm negotiate):

# We start with a context = None and a val (server answer) = None
sspcontext, token, status = clissp.GSS_Init_sec_context(None, None)
# sspcontext will be passed to subsequent calls and stores information
# regarding this NTLM session, token is the NTLM_NEGOTIATE and status
# the state of the SSP
assert status == GSS_S_CONTINUE_NEEDED

Send this token to the server, or use it as required, and get back the server’s token. You can then pass that token as the second parameter of GSS_Init_sec_context(). To give an example, this is what is done in the LDAP client:

# Do we have a token to send to the server?
while token:
    resp = self.sr1(
        LDAP_BindRequest(
            bind_name=ASN1_STRING(b""),
            authentication=LDAP_Authentication_SaslCredentials(
                mechanism=ASN1_STRING(b"SPNEGO"),
                credentials=ASN1_STRING(bytes(token)),
            ),
        )
    )
    sspcontext, token, status = clissp.GSS_Init_sec_context(
        self.sspcontext, GSSAPI_BLOB(resp.protocolOp.serverSaslCreds.val)
    )

If you want to use SPEGOSSP, you could wrap the SSP as so:

from scapy.layers.ntlm import *
from scapy.layers.spnegossp import SPNEGOSSP
clissp = SPNEGOSSP(
    [
        NTLMSSP(
            UPN="Administrator@domain.local",
            PASSWORD="Password1!",
        ),
        KerberosSSP(
            UPN="Administrator@domain.local",
            PASSWORD="Password1!",
            SPN="host/dc1.domain.local",
        ),
    ]
)

You can override the GSS-API req_flags when calling GSS_Init_sec_context(), using values from GSS_C_FLAGS:

sspcontext, token, status = clissp.GSS_Init_sec_context(None, None, req_flags=(
    GSS_C_FLAGS.GSS_C_EXTENDED_ERROR_FLAG |
    GSS_C_FLAGS.GSS_C_MUTUAL_FLAG |
    GSS_C_FLAGS.GSS_C_CONF_FLAG  # Asking for CONFIDENTIALITY
))

Server

Implementing a server is very similar to a client but you’d use GSS_Accept_sec_context() instead. The client is properly authenticated when status is GSS_S_COMPLETE.

Let’s use NTLMSSP as an example of server-side SSP.

from scapy.layers.ntlm import *
clissp = NTLMSSP(
    IDENTITIES={
        "User1": MD4le("Password1!"),
        "User2": MD4le("Password2!"),
    }
)

You’ll find other examples of how to instantiate a SSP in the docstrings of each SSP. See the list