AS_REQ & AS_REP

0x00 前言

熟悉内网渗透的应该都对IPC,黄金票据,白银票据,ntlm relay,Ptt,Ptk 这些词汇再熟悉不够了,对其利用工具也了如指掌,但是有些人对里面使用的原理还不太了解,知其然不知其所以然,本系列文章将针对内网渗透的常见协议(如kerbeos,ntlm,smb,ldap等)进行协议分析,相关漏洞分析以及漏洞工具分析利用。

kerberos篇将从四个方面来阐述kerberos协议,分别是kerberos的两个基础认证模块AS_REQ & AS_REP,TGS_REQ & TGS_REP。以及微软扩展的两个认证模块S4U和PAC。这篇文章是kerberos篇的第一篇文章AS_REQ& AS_REP。

0x01 kerberos 协议概述

Kerberos是一种由MIT(麻省理工大学)提出的一种网络身份验证协议。它旨在通过使用密钥加密技术为客户端/服务器应用程序提供强身份验证。

在Kerberos协议中主要是有三个角色的存在:

  1. 访问服务的Client(以下表述为Client 或者用户)

  2. 提供服务的Server(以下表述为服务)

  3. KDC(Key Distribution Center)密钥分发中心 kerberos 测试工具介绍

其中KDC服务默认会安装在一个域的域控中,而Client和Server为域内的用户或者是服务,如HTTP服务,SQL服务。在Kerberos中Client是否有权限访问Server端的服务由KDC发放的票据来决定。

kerberos的简化认证认证过程如下图

  1. AS_REQ: Client向KDC发起AS_REQ,请求凭据是Client hash加密的时间戳

  2. AS_REP: KDC使用Client hash进行解密,如果结果正确就返回用krbtgt hash加密的TGT票据,TGT里面包含PAC,PAC包含Client的sid,Client所在的组。

  3. TGS_REQ: Client凭借TGT票据向KDC发起针对特定服务的TGS_REQ请求

  4. TGS_REP: KDC使用krbtgt hash进行解密,如果结果正确,就返回用服务hash 加密的TGS票据(这一步不管用户有没有访问服务的权限,只要TGT正确,就返回TGS票据)

  5. AP_REQ: Client拿着TGS票据去请求服务

  6. AP_REP: 服务使用自己的hash解密TGS票据。如果解密正确,就拿着PAC去KDC那边问Client有没有访问权限,域控解密PAC。获取Client的sid,以及所在的组,再根据该服务的ACL,判断Client是否有访问服务的权限。

0x02 kerberos 测试工具

在学习kerberos协议的过程中,一直以来都是利用工具发包,然后再通过wireshark抓包分析,这让用惯了Burp的我很不习惯,burp的repeater模块可以很方便的改包,发包,查看响应包。为了更方便得学习kerberos,简单得写了个测试工具,用于kerbreos协议的研究。

点击修改配置,支持明文密码以及hash

协议的各个字段将在本篇文章以及接下来的几篇文章里面详细阐述,配合此工具理解kerberos 字段,效果更佳。

0x03 AS_REQ

用户向KDC发起AS_REQ,请求凭据是用户 hash加密的时间戳。请求凭据放在PA_DATA里面。详情见以下每个字段的详细介绍。

1. pvno

kerberos 版本号

2. msg-type

类型,AS_REQ对应的就是KRB_AS_REQ(0x0a)

3. PA_DATA

主要是一些认证信息。一个列表,包含若干个认证消息用于认证,我们也可以Authenticator。每个认证消息有type和value。

type主要有以下一些

            NONE = 0,
​            TGS_REQ = 1,
​            AP_REQ = 1,
​            ENC_TIMESTAMP = 2,
​            PW_SALT = 3,
​            ENC_UNIX_TIME = 5,
​            SANDIA_SECUREID = 6,
​            SESAME = 7,
​            OSF_DCE = 8,
​            CYBERSAFE_SECUREID = 9,
​            AFS3_SALT = 10,
​            ETYPE_INFO = 11,
​            SAM_CHALLENGE = 12,
​            SAM_RESPONSE = 13,
​            PK_AS_REQ_19 = 14,
​            PK_AS_REP_19 = 15,
​            PK_AS_REQ_WIN = 15,
​            PK_AS_REQ = 16,
​            PK_AS_REP = 17,
​            PA_PK_OCSP_RESPONSE = 18,
​            ETYPE_INFO2 = 19,
​            USE_SPECIFIED_KVNO = 20,
​            SVR_REFERRAL_INFO = 20,
​            SAM_REDIRECT = 21,
​            GET_FROM_TYPED_DATA = 22,
​            SAM_ETYPE_INFO = 23,
​            SERVER_REFERRAL = 25,
​            TD_KRB_PRINCIPAL = 102,
​            PK_TD_TRUSTED_CERTIFIERS = 104,
​            PK_TD_CERTIFICATE_INDEX = 105,
​            TD_APP_DEFINED_ERROR = 106,
​            TD_REQ_NONCE = 107,
​            TD_REQ_SEQ = 108,
​            PA_PAC_REQUEST = 128,
​            S4U2SELF = 129,
​            PA_PAC_OPTIONS = 167,
​            PK_AS_09_BINDING = 132,
​            CLIENT_CANONICALIZED = 133

在AS_REQ阶段主要用到的有两个

  1. ENC_TIMESTAMP

    这个是预认证,就是用用户hash加密时间戳,作为value 发送给AS服务器。然后AS服务器那边有用户hash,使用用户hash进行解密,获得时间戳,如果能解密,且时间戳在一定的范围内,则证明认证通过

  2. PA_PAC_REQUEST

    这个是启用PAC支持的扩展。PAC(Privilege Attribute Certificate)并不在原生的kerberos里面,是微软引进的扩展。详细的内容之后将有一篇文章详细介绍PAC。PAC包含在AS_REQ的响应body(AS_REP)。这里的value对应的是include=true或者include=false(KDC根据include的值来判断返回的票据中是否携带PAC)。

4. REQ_BODY

  • kdc-options 一些flag 字段

            VALIDATE = 0x00000001,
​              RENEW = 0x00000002,
​              UNUSED29 = 0x00000004,
​              ENCTKTINSKEY = 0x00000008,
​              RENEWABLEOK = 0x00000010,
​              DISABLETRANSITEDCHECK = 0x00000020,
​              UNUSED16 = 0x0000FFC0,
​              CANONICALIZE = 0x00010000,
​              CNAMEINADDLTKT = 0x00020000,
​              OK_AS_DELEGATE = 0x00040000,
​              UNUSED12 = 0x00080000,
​              OPTHARDWAREAUTH = 0x00100000,
​              PREAUTHENT = 0x00200000,
​              INITIAL = 0x00400000,
​              RENEWABLE = 0x00800000,
​              UNUSED7 = 0x01000000,
​              POSTDATED = 0x02000000,
​              ALLOWPOSTDATE = 0x04000000,
​              PROXY = 0x08000000,
​              PROXIABLE = 0x10000000,
​              FORWARDED = 0x20000000,
​              FORWARDABLE = 0x40000000,
​              RESERVED = 0x80000000
  • cname

    PrincipalName 类型。PrincipalName包含type和value。

    • KRB_NT_PRINCIPAL = 1 means just the name of the principal 如dailker

    • KRB_NT_SRV_INST = 2 service and other unique instance (krbtgt) 如krbtgt,cifs

    • KRB_NT_ENTERPRISE_PRINCIPAL = 10 如 user@domain.com

    在AS_REQ里面cname 是请求的用户,这个用户名存在和不存在,返回的包有差异,可以用于枚举域内用户名。详情见相关的安全问题>用户名枚举

  • sname

    PrincipalName 类型

    在AS_REQ里面sname是krbtgt,类型是KRB_NT_SRV_INST

  • realm

    域名

  • from

    发送时间

  • till

    到期时间,rubeus和kekeo都是20370913024805Z,这个可以作为特征来检测工具。

  • nonce

    随机生成的一个数kekeo/mimikatz nonce是12381973,rubeus nonce是1818848256,这个也可以用来作为特征检测工具。

  • etype

    加密类型,有

                 des_cbc_crc = 1,
    ​             des_cbc_md4 = 2,
    ​             des_cbc_md5 = 3,
    ​             des3_cbc_md5 = 5,
    ​             des3_cbc_sha1 = 7,
    ​             dsaWithSHA1_CmsOID = 9,
    ​             md5WithRSAEncryption_CmsOID = 10,
    ​             sha1WithRSAEncryption_CmsOID = 11,
    ​             rc2CBC_EnvOID = 12,
    ​             rsaEncryption_EnvOID = 13,
    ​             rsaES_OAEP_ENV_OID = 14,
    ​             des_ede3_cbc_Env_OID = 15,
    ​             des3_cbc_sha1_kd = 16,
    ​             aes128_cts_hmac_sha1 = 17,
    ​             aes256_cts_hmac_sha1 = 18,
    ​             rc4_hmac = 23,
    ​             rc4_hmac_exp = 24,
    ​             subkey_keymaterial = 65

    这个地方要注意的是如果在配置里面选择用hash(不是plaintext)的话,hash的加密类型,要跟etype一样。因为KDC是按照etype类型选择用户对应加密方式的hash,如果是选择明文(plaintext),那么client 会按照etype里面的加密方式将明文加密成hash。

0x04 AS_REP

KDC使用用户 hash进行解密,如果结果正确返回用krbtgt hash加密的TGT票据,TGT里面包含PAC,PAC包含用户的sid,用户所在的组。

1. msg-type

AS_REQ的响应body对应的就是KRB_AS_REP(0x0b)

2. crealm

域名

3. cname

用户名

4. ticket

这个ticket用于TGS_REQ的认证。是加密的,用户不可读取里面的内容。在AS_REQ请求里面是,是使用krbtgt的hash进行加密的,因此如果我们拥有krbtgt的hash就可以自己制作一个ticket,既黄金票据。详情见相关的安全问题>黄金票据.

5. enc_part

这部分是可以解密的,key是用户hash,解密后得到Encryptionkey,Encryptionkey里面最重要的字段是session key,作为下阶段的认证密钥。

0x05 导出的票据

凭据里面最核心的东西是session-key和加密的ticket。

正常我们用工具生成的凭据是.ccache.kirbi后缀的,用mimikatz,kekeo,rubeus生成的凭据是以.kirbi后缀的。impacket 生成的凭据的后缀是.ccache。两种票据主要包含的都是session-key和加密的ticket,因此可以相互转化。

以kirbi为例介绍下该结构体。

 KRB-CRED::= [APPLICATION 22] SEQUENCE {
   pvno[0] INTEGER(5),
   msg-type[1] INTEGER(22),
   tickets[2] SEQUENCE OF Ticket,
   enc-part[3] EncryptedData -- EncKrbCredPart
}

其中ticket来自于KRB_AS_REP部分的ticket

EncKrbCredPart  ::= [APPLICATION 29] SEQUENCE {
   ticket-info     [0] SEQUENCE OF KrbCredInfo,  //这里就只用到这个
   nonce           [1] UInt32 OPTIONAL,
   timestamp       [2] KerberosTime OPTIONAL,
   usec            [3] Microseconds OPTIONAL,
   s-address       [4] HostAddress OPTIONAL,
   r-address       [5] HostAddress OPTIONAL
}

ticket-info部分的主要内容是session-key,来自于用户hash解密enc_part的部分

KrbCredInfo     ::= SEQUENCE {
  key             [0] EncryptionKey,      sessionKey
  prealm          [1] Realm OPTIONAL,  //对应的是realm
  pname           [2] PrincipalName OPTIONAL, // 对应的是cname
  flags           [3] TicketFlags OPTIONAL, 
  authtime        [4] KerberosTime OPTIONAL, //not require
  starttime       [5] KerberosTime OPTIONAL, // 
  endtime         [6] KerberosTime OPTIONAL,
  renew-till      [7] KerberosTime OPTIONAL,
  srealm          [8] Realm OPTIONAL, //对应的是realm
  sname           [9] PrincipalName OPTIONAL, // 对应的是sname
  caddr           [10] HostAddresses OPTIONAL
}

0x06 相关的安全问题

1. pass the hash 和 pass the key

在连接配置的时候允许使用hash进行认证,而不是只有账号密码才能认证。

就是由于在进行认证的时候,是用用户hash加密时间戳,即使在使用密码进行登录的情况下,也是先把密码加密成hash,再进行认证。因此在只有用户hash,没有明文密码的情况下也是可以进行认证的。不管是rubeus还是impacket里面的相关脚本都是支持直接使用hash进行认证。其中,如果hash的ntlm hash,然后加密方式是rc4,这种就算做是pass the hash,如果是hash是aes key(使用sekurlsa::ekeys导出来),就算是pass the key。在很多地方,不支持rc4加密方式的时候,使用pass the key不失为一种好方法。

2. 用户名枚举

看以下几种情况

用户名存在,密码错误的情况下

用户名不存在的情况下

通过这个比较就可以写脚本改变cname的值进行用户名枚举。在域内没有域账号的情况下进行用户名枚举,在有账号的情况的下通过LDAP查询就行。如果有域内机器的system权限,那那台机器也是个域账户,账户名是机器名$.

3. Password Spraying

在已有用户名的时候,可以尝试爆破密码。

密码正确的情况下:

密码错误的情况下:

这个时候就可以进行密码爆破了,但是在实践中,许多渗透测试人员和攻击者通常都会使用一种被称为“密码喷洒(Password Spraying)”的技术来进行测试和攻击。对密码进行喷洒式的攻击,这个叫法很形象,因为它属于自动化密码猜测的一种。这种针对所有用户的自动密码猜测通常是为了避免帐户被锁定,因为针对同一个用户的连续密码猜测会导致帐户被锁定。所以只有对所有用户同时执行特定的密码登录尝试,才能增加破解的概率,消除帐户被锁定的概率。普通的爆破就是用户名固定,爆破密码,但是密码喷洒,是用固定的密码去跑用户名。工具利用见部分相关的工具>DomainPasswordSpray

4. AS-REPRoasting

对于域用户,如果设置了选项”Do not require Kerberos preauthentication”,此时向域控制器的88端口发送AS_REQ请求,对收到的AS_REP内容(enc-part底下的ciper,因为这部分是使用用户hash加密session-key,我们通过进行离线爆破就可以获得用户hash)重新组合,能够拼接成”Kerberos 5 AS-REP etype 23”(18200)的格式,接下来可以使用hashcat对其破解,最终获得该用户的明文口令

我们没有用户hash,PA-DATA选择PA_PAC_REQUEST就行

点击鼠标右键获取AS_REP里面enc-part部分里面的ciper,然后组装成前面32位16进制字符+$+后面的16进制字符得到repHash,然后format("$krb5asrep$23${0}@{1}:{2}", userName, domain, repHash)得到字符串,交给hashcat 破解就行

这里面只做漏洞原理演示。方便的工具化的利用参见部分相关的工具

5. 黄金票据

在AS_REP里面的ticket的encpart是使用krbtgt的hash进行加密的,如果我们拥有krbtgt的hash,就可以给我们自己签发任意用户的TGT票据,这个票据也被称为黄金票据。

0x07 部分相关的工具

1. Rubeus

Rubeus跟AS_REQ有关的功能主要有两个。

  • asktgt

这个功能用于发送tgt请求包,并将凭据以base64打印出来。

可以通过powershell 解密base64并写入文件(注意回车换行)

  • As-repoasting

这个功能会通过LDAP查询域内用户设置了选项”Do not require Kerberos preauthentication”,然后发AS_REQ的包,直接生成hash或者john可破解的格式

2. impacket

Impact 里面跟AS_REQ相关的脚本主要有两个。

  • getTGT

给定密码,哈希或aesKey,此脚本将请求TGT并将其保存为ccache。

这里面需要注意的是用mimikatz,kekeo,rubeus生成的凭据是以.kirbi后缀的。impacket 生成的凭据的后缀是.ccache

可以通过https://github.com/rvazarkar/KrbCredExport.git里面的脚本转化为kirbi

  • GetNPUsers

此示例将尝试为那些设置了属性“不需要Kerberos预身份验证”(UF_DONT_REQUIRE_PREAUTH)的用户列出并获取TGT。输出与JtR兼容。

  • ticketer

该脚本将从零开始或基于模板(从KDC合法请求)创建Golden / Silver票据,允许您自定义PAC_LOGON_INFO结构中设置的一些参数,特别是组,ExtraSids,持续时间等,票据格式是ccache.

首先获取krbtgt的hash

获取域的sid

制作黄金票据

3. mimikatz

  • kerberos::golden

mimikatz的kerberos::golden模块可以用于制作黄金票据,票据格式是.kirbi

首先获取krbtgt的hash

获取域的sid

制作黄金票据

4. nmap NSE脚本

  1. krb5-enum-users

nmap 里面的这个脚本可以用来枚举域内用户

DomainPasswordSpray是用PowerShell编写的工具,用于对域用户执行密码喷洒攻击。默认情况下,它将利用LDAP从域中导出用户列表,然后扣掉被锁定的用户,再用固定密码进行密码喷洒。

最后更新于