Discovered a hidden register.php endpoint on the site.
After registering a new account, we can log in to the file management system.
IDOR
ID Enumeration
After accessing the file management system with our registered account, we upload a test file to probe functionality.
It responds with a download URL like http://file.era.htb/download.php?id=7638.
Tampering with the id parameter such as testing id=1 results in a clear rejection.
Classic IDOR fingerprint. Time to bring in BurpSuite Intruder or fuzz the id parameter manually with ffuf
File metadata resides in a SQLite files table, indexed by a fileid between 1–9999 making it a low-entropy IDOR target. Download links are served via the get_download_link() function.
The upload script accepts arbitrary file types, including .php and .phar, though current conditions prevent direct exploitation.
Uploaded files are placed in a non-executable /files/ directory, blocking .php execution. No LFI is present to trigger uploads, and no unserialize() calls on user-controlled phar:// paths have been identified yet.
Conclusion: while the upload mechanism is insecure by design, it remains non-exploitable in the current environment.
2.download.php
1
if (!isset($_GET['id'])) {
2
header('location: index.php'); // user loaded without requesting file by id
3
die();
4
}
5
6
if (!is_numeric($_GET['id'])) {
7
header('location: index.php'); // user requested non-numeric (invalid) file id
8
die();
9
}
10
11
$reqFile = $_GET['id'];
12
13
$fetched =contactDB("SELECT*FROM files WHERE fileid='$reqFile';", 1);
If the requested file exists, it proceeds to return it:
1
$realFile = (count($fetched) !=0); // Set realFile to true if we found the file id, false if we didn't find it
2
3
if (!$realFile) {
4
echodeliverTop("Era - Download");
5
6
echodeliverMiddle("File Not Found", "The file you requested doesn't exist on this server", "");
Although the dl=true parameter doesn’t appear in the URL, it is injected dynamically through the HTML source.
The intriguing section lies under the show=true branch (highlighted in purple), active only for the admin user (erauser === 1). This code contains a critical logic flaw.
1
// Check if it's a wrapper (://)
2
if (strpos($format, '://') !==false) {
3
// Treats it as a protocol wrapper
4
// e.g. http://, file://, php://, etc.
5
$wrapper = $format;
6
header('Content-Type: application/octet-stream');
7
} else {
8
$wrapper ='';
9
header('Content-Type: text/html');
10
}
11
12
try {
13
// Build the final file path
14
$file = $fetched[0];
15
// If a wrapper is set
16
// [!] This constructs an arbitrary protocol + file path.
The $wrapper string is entirely attacker-controlled. By specifying wrappers like file://, php://, or ssh2://, an admin user can access arbitrary resources via stream wrappers—exemplifying a classic Arbitrary Protocol File Read (APFR) vulnerability.
With ssh2.so and phar.so modules present and presumably enabled, this vulnerability paves the way for:
LFI via file://
PHP filter chain attacks using php://filter
SSRF or RCE through ssh2://
3. reset.php
Before leveraging the Arbitrary Protocol Execution, privilege escalation to the admin account is required.
Enter reset.php an unprotected IDOR vulnerability.
No safeguards exist to stop low-privileged users from modifying security question answers for any account, including the admin admin_ef01cab31aa. By resetting the admin’s answers and leveraging the previously identified /security_login.php endpoint, the admin account can be hijacked.
Attack Execution
With all elements aligned, we can now orchestrate a full attack chain to obtain Remote Code Execution (RCE):
1. IDOR
The attack starts by exploiting the IDOR vulnerability in reset.php. Using Burp Suite Repeater, capture the POST request and substitute the username with admin_ef01cab31aa.
2. Admin Impersonation
Once reset, use the security_login.php endpoint to impersonate the admin:
Once logged in, upload a dummy file to obtain a valid file ID. Then, capture the download request along with the admin session cookie using Burp Suite.
Send the request to Repeater and test the stream wrapper logic using the file:// protocol with an existing ID, such as 54 or 150.
This confirms successful access to the stream wrapper execution path with admin privileges.
3. Abuse SSH2 Stream
> PHP | ssh2://
Since ssh2.so is enabled (confirmed via the downloaded PHP config), we can leverage the ssh2.exec:// protocol, which opens an SSH connection and executes a remote command.
This strongly indicates that something noteworthy resides under /opt.
Terminal window
1
eric@era:~$ls-aRhl/opt
2
3
/opt:
4
total12K
5
drwxrwxr-x3rootroot4.0KJul2208:42.
6
drwxr-xr-x20rootroot4.0KJul2208:41..
7
drwxrwxr--3rootdevs4.0KJul2208:42AV
8
9
/opt/AV:
10
total12K
11
drwxrwxr--3rootdevs4.0KJul2208:42.
12
drwxrwxr-x3rootroot4.0KJul2208:42..
13
drwxrwxr--2rootdevs4.0KJul2708:22periodic-checks
14
15
/opt/AV/periodic-checks:
16
total32K
17
drwxrwxr--2rootdevs4.0KJul2708:22.
18
drwxrwxr--3rootdevs4.0KJul2208:42..
19
-rwxrw----1rootdevs17KJul2708:22monitor
20
-rw-rw----1rootdevs205Jul2708:22status.log
The monitor binary is owned by root, yet both it and status.log have group write permissions for the devs group, which includes eric presenting a clear avenue for privilege escalation.
The monitor binary runs with root privileges, but since the devs group has write access to its parent directories—and eric is part of that group we’re able to rename or replace it without restriction.
This creates a textbook case of binary replacement, allowing us to plant a payload that gets executed with elevated privileges.
2. Scheduled Task
Frequent updates to status.log suggest it’s actively maintained by the monitor binary.
Terminal window
1
eric@era:~$cat/opt/AV/periodic-checks/status.log
2
3
[*] System scan initiated...
4
[*] No threats detected. Shutting down...
5
[SUCCESS] No threats detected.
This suggests:
A scheduled task, likely executed by root, runs the monitor binary. With the ability to replace it, we effectively control what code is executed with root privileges.
3. Signature
Self Signed
Simply replacing monitor won’t suffice it’s guarded by a signature verification check. For instance, swapping it with a basic bash script would fail validation.
The status.log file logs the error from the most recent execution attempt.
1
eric@era:/opt/AV/periodic-checks$ cat status.log
2
3
[*] System scan initiated...
4
[*] No threats detected. Shutting down...
5
[SUCCESS] No threats detected.
6
objcopy: /opt/AV/periodic-checks/monitor: file format not recognized
7
[ERROR] Executable not signed. Tampering attempt detected. Skipping.
This reveals that the binary needs to be a properly signed ELF executable. Notably, the signature is embedded within the ELF itself—rather than provided as an external .sig or .pem file. We can verify this by inspecting custom ELF sections.
The ELF binary includes a custom section called .text_sig. When the system invokes the monitor binary—likely through something like initiate_monitoring.sh it uses objcopy to extract this section and verifies it against the contents of the .text segment.
Therefore, we can utilize objdump to examine the contents of the section.
The output reveals a standard ASN.1 DER-encoded format containing elements such as:
Era Inc. (Issuer)
ELF verification (Common Name)
yurivich@era.com (Email)
An extensive RSA signature block
This confirms the system validates binaries by extracting the .text_sig section and checking its integrity, rejecting any unsigned or altered binaries.
OpenSSL Config
Previously, we identified a signing mechanism located within the FTP share:
Terminal window
1
$treesigning
2
3
signing
4
├──key.pem
5
└──x509.genkey
Terminal window
1
[ req ]
2
default_bits=2048
3
distinguished_name=req_distinguished_name
4
prompt=no
5
string_mask=utf8only
6
x509_extensions=myexts
7
8
[ req_distinguished_name ]
9
O=EraInc.
10
CN=ELFverification
11
emailAddress=yurivich@era.com
12
13
[ myexts ]
14
basicConstraints=critical,CA:FALSE
15
keyUsage=digitalSignature
16
subjectKeyIdentifier=hash
17
authorityKeyIdentifier=keyid
This aligns with the signature details observed earlier.
The [ myexts ] section verifies that the certificate is meant solely for digital signatures, without any Certificate Authority capabilities.
…verifies that this is a valid RSA private key compatible with OpenSSL signing functions.
The private key matches the public key used in the signature verification process probably embedded in the script or retrieved from a secure store. This enables us to re-sign any custom ELF binary we create, as long as we maintain the .text_sig structure required by the verifier.
Exploit Overview
To hijack the privileged monitor binary, we first need to sign our malicious payload with the Era Inc. signature scheme.
Unlike typical Linux ELF binaries, which don’t include a .text_sig section by default, this custom section must have been appended after compilation.
The presence of .text_sig itself is a clue—it acts as a signature marker. After some research, we find that the binary is signed using linux-elf-binary-signer, a tool that embeds a cryptographic signature into a dedicated ELF section called .text_sig. This signature ensures the integrity of the .text segment.
With this understanding, the path forward is clear. Next, we’ll create a minimal SUID spawner: