Scapy 中的 LDAP 协议实现与 LDAP_Client 实战指南:从 LDAPv2/v3 报文构造到认证绑定与查询
2026/9/23 13:52:20 网站建设 项目流程
  • 网络
  • 网络安全

【免费下载链接】scapy

Scapy: the Python-based interactive packet manipulation program & library.

项目地址:https://gitcode.com/gh_mirrors/sc/scapy
点击查看免费下载

本篇技术指南以 doc/scapy/layers/ldap.rst 为骨架,深入讲解 Scapy 对 LDAPv2/LDAPv3 消息的完整实现,以及内置LDAP_Client类的连接、绑定(NONE / SIMPLE / SICILY / SASL_GSSAPI / SASL_GSS_SPNEGO)、签名加密、搜索与属性修改全流程,并辅以 scapy/layers/ldap.py 源码与 test/scapy/layers/ldap.uts 测试用例佐证实现细节。读完本文,你将能够使用 Scapy 以纯 Python 方式对 LDAP 服务器(包括 Windows Active Directory)进行抓包级报文构造、协议调试与自动化操作,并会使用图形化封装 LDAPHero。

概述:Scapy 的 LDAP 支持范围

Scapy 在 scapy/layers/ldap.py 中实现了 LDAP 协议栈,依据的标准包括:

  • RFC 1777:LDAP v2;
  • RFC 4511:LDAP v3(Bind、Search、Modify、Add、Delete、ModifyDN、Abandon、Extended 等完整操作);
  • RFC 2254:LDAP 过滤字符串语法(LDAP_Filter.from_rfc2254_string);
  • [MS-ADTS]:微软 Active Directory 技术规范中的扩展,包括 Sicily 绑定(NTLM)、分页搜索结果控件、安全描述符相关控件等。

除报文层的完整实现外,还附带一个功能"够用但基础"的LDAP_Client类,以及基于它的图形化 LDAP 浏览器 LDAPHero。从源码头部注释可以看到一个实用提示:要模拟微软 Windows LDAP 报文的编码风格,需设置conf.ASN1_default_long_size = 4;测试 test/scapy/layers/ldap.uts 中的 "Microsoft LDAP tests" 一节正是用这一开关验证了与 Windows 报文逐字节一致的构建与重新解包。

LDAP主类本身是一个 ASN.1(BER 编码)包,其顶层结构由messageID(ASN1_INTEGER)、protocolOp(ASN1F_CHOICE,覆盖 BindRequest / SearchRequest / ModifyRequest / AddRequest / DelRequest / ModifyDNRequest / AbandonRequest / ExtendedResponse 等全部操作)以及可选的 LDAP v3Controls序列构成(见 scapy/layers/ldap.py#L1042-L1071)。它同时提供了tcp_reassemble重组逻辑,用于在 TCP 流上正确拼接被分片的 LDAP 响应,以及answers()按 messageID 匹配请求/响应的机制。

在传输层绑定上,源码通过bind_bottom_up(TCP, LDAP, dport=389)dport=3268(全局编录)以及 UDP 389 上的 CLDAP 完成自动解包挂接,因此用rdpcapsniff抓到的 LDAP 流量可以直接被识别为LDAP/CLDAP层。

LDAP_Client 使用总览

LDAP_Client(定义于 scapy/layers/ldap.py#L1762)的使用思路非常直接,遵循"连接 → 绑定 → 操作"三步走:

  1. 实例化LDAP_Client()
  2. 调用connect(ip)——在这里指定是否使用 SSL;
  3. 调用bind(...)——在这里指定认证机制(SSP)以及是否需要签名/加密;
  4. 调用search(...)查询数据;
  5. 调用modify(...)编辑属性(此外还提供add()modifydn()close()等方法)。

最简单的无认证演示(摘自原文档,并保留其真实输出格式):

>>> client = LDAP_Client() >>> client.connect("192.168.0.100") >>> client.bind(LDAP_BIND_MECHS.NONE) >>> client.sr1(LDAP_SearchRequest()).show() ┃ Connecting to 192.168.0.100 on port 389... └ Connected from ('192.168.0.102', 40228) NONE bind succeeded ! >> LDAP_SearchRequest << LDAP_SearchResponseEntry ###[ LDAP ]### messageID = 0x1 <ASN1_INTEGER[1]> \protocolOp\ |###[ LDAP_SearchResponseEntry ]### | objectName= <ASN1_STRING[b'']> | \attributes\ | |###[ LDAP_PartialAttribute ]### | | type = <ASN1_STRING[b'domainFunctionality']> | | \values \ | | |###[ LDAP_AttributeValue ]### | | | value = <ASN1_STRING[b'7']> | |###[ LDAP_PartialAttribute ]### | | type = <ASN1_STRING[b'forestFunctionality']> | | \values \ | | |###[ LDAP_AttributeValue ]### | | | value = <ASN1_STRING[b'7']> | |###[ LDAP_PartialAttribute ]### | | type = <ASN1_STRING[b'domainControllerFunctionality']> | | \values \ | | |###[ LDAP_AttributeValue ]### | | | value = <ASN1_STRING[b'7']> [...]

可见sr1()发送的LDAP_SearchRequest拿到了服务器的 root DSE(根 DSA 信息)应答,结果被结构化为LDAP_SearchResponseEntry,每个属性为LDAP_PartialAttribute,属性值包装在LDAP_AttributeValue中。这就是 LDAP_Client 交互时的典型报文视图,非常适合协议教学与调试。

若客户端输出过于啰嗦,可在实例化时传入verb=False关闭连接/收发过程的打印(LDAP_Client(verb=False),对应源码__init__(self, verb=True)的默认参数)。

连接服务器:普通连接与 LDAPS

默认端口 389 的连接

client = LDAP_Client() client.connect("192.168.0.100")

connect()的完整签名(scapy/layers/ldap.py#L1836)为:

def connect(self, host, port=None, use_ssl=False, sslcontext=None, sni=None, no_check_certificate=False, timeout=5):
  • host:目标 IP 或主机名;
  • port:默认 389(非 SSL)或 636(SSL),可用port属性覆盖;
  • use_ssl:是否启用 LDAPS;
  • sslcontext:自定义ssl.SSLContext,用于严格校验证书;
  • sni:LDAPS 时的 SNI,缺省使用 host;
  • no_check_certificate:SSL 下跳过证书检查;
  • timeout:连接超时,默认 5 秒。

底层实现会创建 TCP socket(开启SO_KEEPALIVE),按StreamSocket(sock, LDAP)封装为 Scapy 流式套接字。

使用 TLS(LDAPS)连接

client = LDAP_Client() client.connect("192.168.0.100", use_ssl=True)

使用 TLS 时默认端口变为 636。重要安全提示:默认情况下此模式不会校验服务器证书,因为目标服务器证书很可能是自签名的。要实现真正安全的 TLS,应传入sslcontext

import ssl client = LDAP_Client() sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) sslcontext.load_verify_locations('path/to/ca.crt') client.connect("192.168.0.100", use_ssl=True, sspcontext=sslcontext)

(注意:文档示例中该参数名为sspcontext,而源码connect()中实际参数名为sslcontext,按当前仓库源码为准传sslcontext即可;no_check_certificate=True也可用于测试环境跳过校验。)

从源码看,SSL 分支还会额外执行两步:一是用GssChannelBindings.fromssl(ChannelBindingType.TLS_SERVER_END_POINT, ...)计算 TLS 通道绑定令牌(CBT),供后续 GSSAPI/SASL 认证使用;二是将 socket 封装为SSLStreamSocket(sock, LDAP)

绑定:五种认证机制详解

绑定必须显式指定机制类型,其枚举LDAP_BIND_MECHS(scapy/layers/ldap.py#L1661)定义如下:

枚举成员字符串值含义与安全属性
NONE"ANONYMOUS"匿名绑定,不携带任何凭据
SIMPLE"SIMPLE"简单绑定机制,凭据明文传输,务必配合 LDAPS 使用
SICILY"SICILY"Windows 特有机制([MS-ADTS]),仅支持 NTLM
SASL_GSSAPI"GSSAPI"SASL 认证机制(RFC 4422),通常配合 Kerberos
SASL_GSS_SPNEGO"GSS-SPNEGO"SPNEGO 认证机制([MS-SPNG]),NTLM / Kerberos 皆可,Windows 场景常用
SASL_EXTERNAL"EXTERNAL"SASL EXTERNAL(基于外部凭据,如客户端证书)
SASL_DIGEST_MD5"DIGEST-MD5"SASL DIGEST-MD5

需要说明:SASL_EXTERNALSASL_DIGEST_MD5已出现在枚举中,但bind()的校验分支(scapy/layers/ldap.py#L2023-L2061)目前仅实现了 NONE、SIMPLE、SICILY、SASL_GSSAPI、SASL_GSS_SPNEGO,其余机制会抛出"Mech ... is still unimplemented !"

可用性取决于服务器:不同服务器支持的机制不同,SICILYSASL_GSS_SPNEGO绝大多数情况下只在 Windows(Active Directory)环境中可用;其它标准服务器通常只支持SIMPLESASL_GSSAPI

NONE(匿名)

client.bind(LDAP_BIND_MECHS.NONE)

SIMPLE(简单绑定)

client.bind( LDAP_BIND_MECHS.SIMPLE, simple_username="Administrator", simple_password="Password1!", )

底层发送LDAP_BindRequestbind_name为用户名,authentication使用LDAP_Authentication_simple(上下文标签0x80)携带明文密码;若返回的resultCode != 0(非 success),抛出LDAP_Exception

SICILY — NTLM

ssp = NTLMSSP(UPN="Administrator", PASSWORD="Password1!") client.bind( LDAP_BIND_MECHS.SICILY, ssp=ssp, )

SICILY 是 [MS-ADTS] 定义的 Windows 专有绑定,源码实现为三步握手(scapy/layers/ldap.py#L2090-L2149):先是Package DiscoveryLDAP_Authentication_sicilyPackageDiscovery),再是NegotiateLDAP_Authentication_sicilyNegotiate携带 NTLMSSP NEGOTIATE 令牌),最后是ResponseLDAP_Authentication_sicilyResponse携带 NTLM AUTHENTICATE 令牌)。中间还会用target_name="ldap/" + self.host和通道绑定调用GSS_Init_sec_context

SASL_GSSAPI — Kerberos

ssp = KerberosSSP(UPN="Administrator@domain.local", PASSWORD="Password1!", SPN="ldap/dc1.domain.local") client.bind( LDAP_BIND_MECHS.SASL_GSSAPI, ssp=ssp, )

SASL_GSSAPI 分支要求 SSP 必须是KerberosSSP实例,否则抛ValueError。它的握手比 SICILY 更复杂:除标准的 SASL 凭据交换外,还需按 RFC 2222 第 7.2.1/7.2.2 节进行安全层协商——解析服务器返回的LDAP_SASL_GSSAPI_SsfCap(包含supported_security_layers的 INTEGRITY / CONFIDENTIALITY 标志与max_output_token_size),再回发客户端支持的安全层标志(scapy/layers/ldap.py#L2207-L2264)。

SASL_GSS_SPNEGO — NTLM / Kerberos

ssp = SPNEGOSSP([ NTLMSSP(UPN="Administrator", PASSWORD="Password1!"), KerberosSSP(UPN="Administrator@domain.local", PASSWORD="Password1!", SPN="ldap/dc1.domain.local"), ]) client.bind( LDAP_BIND_MECHS.SASL_GSS_SPNEGO, ssp=ssp, )

SPNEGO 允许将多个 SSP(NTLM + Kerberos)打包在一个SPNEGOSSP中,由双方协商最终选用的机制;在 Windows 上还支持通过 WinSSP 使用隐式凭据。值得注意的是,若最终协商结果为 NTLMSSP,源码会将self.sign强制置为 False(scapy/layers/ldap.py#L2267-L2271),因为 Windows 的 NTLM-over-LDAP 不支持"只签名不加密"。

bind() 的默认行为与校验

bind()有两个值得注意的默认值(scapy/layers/ldap.py#L2010-L2014):

  • 未显式指定encrypt时,SICILY 默认加密;
  • 未显式指定sign且未加密时,除 NONE / SIMPLE 外默认签名。

同时它做了严格的组合校验:

  • SICILY 要求 SSP 为NTLMSSP,且不允许"只签名不加密"
  • SASL_GSS_SPNEGO 要求 SSP 为SPNEGOSSP(Windows 下可为WinSSP);
  • NONE / SIMPLE 不允许携带 SSP,也不允许使用sign/encrypt

绑定成功后,若启用了签名或加密,套接字会被切换为StreamSocket(sock, LDAP_SASL_Buffer),后续所有 LDAP 报文都经 GSS_Wrap / GSS_Unwrap 保护(scapy/layers/ldap.py#L2273-L2277)。

签名 / 加密(SASL 层保护)

不使用 LDAPS的前提下,可以通过bind()signencrypt参数为 LDAP 流量启用签名或加密,这两者借助 GSSAPI 的 INTEGRITY / CONFIDENTIALITY 标志实现。使用时必须注意几个限制:

  • NONE 与 SIMPLE 模式不能使用这两个标志;
  • 在 SICILY 或 SASL_GSS_SPNEGO 中使用NTLMSSP时,无法只开sign而不开encrypt——因为 Windows 没有实现该组合(SICILY 分支会直接抛出ValueError)。

GSSAPI(Kerberos)模式下,若请求签名而服务器不支持 INTEGRITY,或请求加密而服务器不支持 CONFIDENTIALITY,绑定会在安全层协商阶段抛出RuntimeError。关于响应保护,test/scapy/layers/ldap.uts 中的 "Protected LDAP responses retain the requested message ID" 一节验证了:签名/加密响应解包后,messageID 必须与请求一致,否则抛ValueError("LDAP response message ID does not match request !")

查询数据:sr1 与 search

绑定完成后即可发起请求。最简单的用法是直接发送报文并展示结果:

client.sr1(LDAP_SearchRequest()).show()

使用 search() 高阶接口

更常用的是search(),它接受 base DN、RFC 2254 过滤字符串与 scope:

resp = client.search( "CN=Users,DC=domain,DC=local", "(objectCategory=person)", ["objectClass", "name", "description", "canonicalName"], scope=1, # children ) resp.show()

search()的完整签名与默认值(scapy/layers/ldap.py#L2286-L2297):

def search(self, baseObject="", filter="", scope=0, derefAliases=0, sizeLimit=300000, timeLimit=3000, attrsOnly=0, attributes=[], controls=[]):

scope 取值范围

名称语义
0baseObject只查询 base DN 自身的属性
1singleLevel查询 base DN 的直接子条目
2wholeSubtree查询 base DN 下整个子树

其它参数的语义与默认行为

  • derefAliases:别名解引用方式(0=neverDerefAliases、1=derefInSearching、2=derefFindingBaseObj、3=derefAlways),默认 0;
  • sizeLimit/timeLimit:服务端返回条数上限与处理时间上限,默认分别 300000 / 3000(毫秒);
  • attrsOnly:是否只取属性名不取值,默认 False;
  • baseObject"rootDSE"时会自动转为空 DN"",即查询根 DSA;
  • filter为空时默认使用(objectClass=*)LDAP_FilterPresent);
  • 绑定成功后,会自动追加分页控件(OID1.2.840.113556.1.4.319,每页 100 条,通过 cookie 循环取完所有结果),最终返回{dn: {attribute: [values]}}形式的字典。

search()的返回值是字典:键为条目的 DN,值为属性名到值列表的映射。OpenLDAP 集成测试 test/scapy/layers/ldapopenldap.uts 演示了完整流程与返回结构:

cli = LDAP_Client() cli.connect("127.0.0.1") cli.bind(LDAP_BIND_MECHS.SIMPLE, simple_username="cn=admin,dc=scapy,dc=net", simple_password="Bonjour1") res = cli.search("dc=scapy,dc=net", "(&(givenName=Another)(sn=Test))", scope=2) cli.close() # res == {'uid=another,ou=People,dc=scapy,dc=net': { # 'objectClass': ['top', 'person', 'inetOrgPerson'], # 'cn': ['Another Test'], 'uid': ['another'], 'sn': ['Test'], # 'givenName': ['Another'], 'userPassword': ['testing']}}

RFC 2254 过滤字符串解析

search()内部通过LDAP_Filter.from_rfc2254_string(filter)(scapy/layers/ldap.py#L603-L740)把字符串过滤条件解析为对应的 ASN.1 过滤器树。该解析器支持:

  • 组合操作符:&(LDAP_FilterAnd)、|(LDAP_FilterOr)、!(LDAP_FilterNot);
  • 比较操作符:=(EqualityMatch)、>=(GreaterOrEqual)、<=(LessOrEqual)、~=(ApproxMatch);
  • 子串过滤:attribute=initial*any*final(对应 LDAP_SubstringFilter 的 initial / any / final 三段);
  • 存在性过滤:attribute=*(LDAP_FilterPresent)。

已知限制:文档明确警告,当前 RFC 2254 解析器不支持 Extensible Match(扩展匹配attr:=rule:value,遇到:=会抛NotImplementedError("Extensible not implemented.");但过滤器结构类LDAP_FilterExtensibleMatch本身已在源码中定义,可手工构造报文使用。

等价的底层报文构造

为了透彻理解search()做了什么,原文档给出了完全等价的手工构造写法——search()的上述调用等价于以下sr1()调用:

resp = client.sr1( LDAP_SearchRequest( filter=LDAP_Filter( filter=LDAP_FilterEqual( attributeType=ASN1_STRING(b'objectCategory'), attributeValue=ASN1_STRING(b'person') ) ), attributes=[ LDAP_SearchRequestAttribute(type=ASN1_STRING(b'objectClass')), LDAP_SearchRequestAttribute(type=ASN1_STRING(b'name')), LDAP_SearchRequestAttribute(type=ASN1_STRING(b'description')), LDAP_SearchRequestAttribute(type=ASN1_STRING(b'canonicalName')) ], baseObject=ASN1_STRING(b'CN=Users,DC=domain,DC=local'), scope=ASN1_ENUMERATED(1), derefAliases=ASN1_ENUMERATED(0), sizeLimit=ASN1_INTEGER(1000), timeLimit=ASN1_INTEGER(60), attrsOnly=ASN1_BOOLEAN(0) ) )

LDAP_SearchRequest的字段布局(scapy/layers/ldap.py#L748-L771)为:baseObjectscope(ENUMERATED,0/1/2)、derefAliasessizeLimittimeLimitattrsOnlyfilter(LDAP_Filter)、attributes(SEQUENCE OF LDAP_SearchRequestAttribute)。这也是直接在报文物化层上定制搜索的唯一正确入口。

修改属性:modify / add / modifydn

modify()用于更改对象的属性,典型场景是替换displayName新增servicePrincipalName

client.modify( "CN=User1,CN=Users,DC=domain,DC=local", changes=[ LDAP_ModifyRequestChange( operation="replace", modification=LDAP_PartialAttribute( type="displayName", values=[ LDAP_AttributeValue(value="Lord User the 1st") ] ) ), LDAP_ModifyRequestChange( operation="add", modification=LDAP_PartialAttribute( type="servicePrincipalName", values=[ LDAP_AttributeValue(value="http/lorduser") ] ) ) ] )

LDAP_ModifyRequestChange.operation是 ASN1_ENUMERATED,取值见 scapy/layers/ldap.py#L822-L835:0=add1=delete2=replace,直接传字符串名即可。modify()内部发送LDAP_ModifyRequestobject+changes序列),若响应不是LDAP_ModifyResponseresultCode != 0则抛LDAP_Exception

LDAP_Client还提供另外两个写操作:

  • add(entry, attributes, controls=[]):新增条目,attributes支持两种格式——LDAP_Attribute(或LDAP_PartialAttribute)列表,或{属性名: [值列表]}字典(源码会自动转换为LDAP_Attribute);
  • modifydn(entry, newdn, deleteoldrdn=True, controls=[]):重命名/移动条目,自动从新旧 DN 推导 relative DN 与 newSuperior(若父级未变则省略 newSuperior 字段),遵循 RFC 4511 第 4.9 节。

所有写操作失败时都会抛出带resultCodediagnosticMessage属性的LDAP_Exception;当诊断消息形如8009030C: LdapErr: ... data 52e ...(Windows 域控错误)时,异常还会自动用 scapy/layers/windows/erref.py 中的STATUS_ERREF表把十六进制错误码翻译成可读文本。

LDAPHero:图形化 LDAP 浏览器

LDAPHero(法语昵称 LDAPéro,源码见 scapy/modules/ldaphero.py)是基于LDAP_Client的跨平台图形化封装(tkinter GUI),适用于希望可视化浏览目录树的场景。

启动方式:

>>> load_module("ticketer") >>> LDAPHero()

也可以在构造时传入 SSP,点击界面上的 "Bind" 按钮时就会使用它认证(例如 SICILY / NTLM):

>>> LDAPHero(mech=LDAP_BIND_MECHS.SICILY, ... ssp=NTLMSSP(UPN="Administrator@domain.local", PASSWORD="test"))

SSP 的用法与前面bind()章节完全一致。还可以传入连接参数,例如指定目标主机:

>>> LDAPHero(host="192.168.0.100")

从 scapy/modules/ldaphero.py#L153-L219 看,LDAPHero的构造参数还包括:mech(默认SASL_GSS_SPNEGO)、sign(默认 True)、encrypt(默认 False)、portssl,以及一组认证参数(UPNpasswordkerberos_requiredHashNtHashAes256Sha96HashAes128Sha96use_krb5ccnameuse_winssp);当传了host且未提供 SSP 时,会自动用这些参数构造SPNEGOSSP。GUI 提供目录树浏览(双击展开子树)、搜索、新增子条目、修改属性、修改 DN、查看并编辑安全描述符(通过 LDAP 控件1.2.840.113556.1.4.801读取nTSecurityDescriptor,并借助 DCE/RPCdrsuapi接口解析 SID)等能力,需要python3-tk(Debian 系apt install python3-tk)。

深入:协议细节与周边工具

报文物化层与操作码

ASN1_Class_LDAP(scapy/layers/ldap.py#L195-L218)定义了全部 LDAP 操作的应用标签:BindRequest0x60、BindResponse0x61、SearchRequest0x63、SearchResultEntry0x64、SearchResultDone0x65、ModifyRequest0x66、ModifyResponse0x67、AddRequest0x68、DelRequest0x4A、ModifyDNRequest0x6C、CompareRequest0x6E、AbandonRequest0x50、ExtendedResponse0x78等,这些标签正是 BER 编码中识别操作类型的依据。LDAPResult元组则把 resultCode 数值映射为语义(0=success、49=invalidCredentials、53=unwillingToPerform、32=noSuchObject 等),并包含matchedDNdiagnosticMessage及可选 referral 列表。

LDAP 控件(Controls)

LDAP_ControlcontrolType(OID)、可选的criticalitycontrolValue组成。源码维护了一张_LDAP_CONTROLS注册表(scapy/layers/ldap.py#L975-L989),可按 OID 自动把 controlValue 解包为专用结构,目前注册了两个:

  • 1.2.840.113556.1.4.319LDAP_realSearchControlValue(RFC 2696 分页结果控件,size+cookie),search()的分页功能即依赖它;
  • 1.2.840.113556.1.4.801LDAP_serverSDFlagsControl([MS-ADTS],OWNER/GROUP/DACL/SACL标志),LDAPHero 读取安全描述符时使用。

任何未注册 OID 的控件值都会以原始 ASN1_STRING 形式保留,不影响报文往返。

其它相关能力

  • CLDAP 与 DC 定位:UDP 389 上的 CLDAP(RFC 1798)同样实现了,并内置LdapPing_am应答机(ldappingd)以及dclocator命令(按 [MS-ADTS] 6.3.6 执行域控定位,支持nocheck/connect/ldap三种探测模式,源码 scapy/layers/ldap.py#L1479-L1653);
  • Windows 兼容性LDAP_ExtendedResponse.do_dissect专门兼容了 Windows 构造的"长度字段不含可选字段"的畸形包(scapy/layers/ldap.py#L959-L970);对微软报文整体使用conf.ASN1_default_long_size = 4可还原其定长编码风格;
  • 测试:test/scapy/layers/ldap.uts 覆盖了 BindRequest / BindResponse / SearchRequest / SearchResponse / UnbindRequest 的字节级解包-重建、TCP 会话重组、CLDAP、Microsoft LDAP 编码、SASL 保护响应等场景,可作为理解协议细节的补充阅读。

小结

Scapy 的 LDAP 支持覆盖了从"报文层"到"客户端"再到"图形界面"三个层次:底层是完整的 LDAPv2/v3 + CLDAP 的 ASN.1/BER 报文实现与自动 TCP/UDP 端口解包;中间层是LDAP_Client提供 connect / bind(匿名、简单、NTLM Sicily、Kerberos GSSAPI、SPNEGO)/ search(含分页与 RFC 2254 过滤解析)/ modify / add / modifydn / close 全套操作,并支持 SASL 签名加密与 LDAPS;上层则是面向交互式渗透测试与域环境管理的 LDAPHero 图形浏览器。无论是抓包调试 LDAP 协议、编写针对 Active Directory 的自动化脚本,还是验证自建 OpenLDAP 服务,scapy/layers/ldap.py 与本文所述的用法都是直接可用的起点。

  • 网络
  • 网络安全

【免费下载链接】scapy

Scapy: the Python-based interactive packet manipulation program & library.

项目地址:https://gitcode.com/gh_mirrors/sc/scapy
点击查看免费下载

相关推荐

上一篇:全国人口及GDP空间数据资源:助力多领域精准分析
下一篇:探秘UDP组播调试利器:C编写的高效调试工具

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询