fix(ssh,telnet): move PROMPT_COMMAND out of /root/.bashrc + pin readonly
ANTI flagged two regressions in the existing command-event capture: 1. **Tell**: PROMPT_COMMAND lived in /root/.bashrc, the FIRST file an attacker greps after landing root. The logger invocation sitting there is plain-text honeypot signage. 2. **Bypass**: even when missed, `export PROMPT_COMMAND=""` silently disables capture. ANTI personally bypasses this on engagements. Reshape: * Move the assignment to **/etc/environment** — read by pam_env at session open (sshd via /etc/pam.d/sshd, telnet via /etc/pam.d/login), before any shell rc file fires. Far less obvious than .bashrc; a casual `cat .bashrc` no longer surfaces the capture. * Define the helper as a function `__bash_history_sync` in **/etc/bash.bashrc** (system-wide bashrc, sourced by every interactive bash). Function name reads as generic bash housekeeping; no DECNET branding in the symbol. * Pin both the function and PROMPT_COMMAND **readonly** so `export PROMPT_COMMAND=""` fails with "readonly variable" instead of silently winning. Mitigation, not airtight — `bash --norc` still bypasses — but the passive `export` bypass is closed. The actual `logger --rfc5424 --msgid command ... CMD ...` invocation is preserved exactly; only its location and the readonly guard change. R0001–R0030 (command-rule pack) consume the same syslog shape as before. Three new tests assert: the value lands in /etc/environment, the function body lives in /etc/bash.bashrc, no PROMPT_COMMAND line remains in /root/.bashrc, and `readonly PROMPT_COMMAND` / `readonly -f __bash_history_sync` are both present. Mirror assertions added on the Telnet Dockerfile via test_config_schema.py.
This commit is contained in:
@@ -108,8 +108,24 @@ RUN echo 'alias ll="ls -alF"' >> /root/.bashrc && \
|
||||
echo 'alias la="ls -A"' >> /root/.bashrc && \
|
||||
echo 'alias l="ls -CF"' >> /root/.bashrc && \
|
||||
echo 'export HISTSIZE=1000' >> /root/.bashrc && \
|
||||
echo 'export HISTFILESIZE=2000' >> /root/.bashrc && \
|
||||
echo 'PROMPT_COMMAND='"'"'logger --rfc5424 --msgid command -p user.info -t bash "CMD uid=$UID user=$USER src=${SSH_CLIENT%% *} pwd=$PWD cmd=$(history 1 | sed "s/^ *[0-9]* *//")";'"'" >> /root/.bashrc
|
||||
echo 'export HISTFILESIZE=2000' >> /root/.bashrc
|
||||
|
||||
# Command-event capture. PROMPT_COMMAND is set in /etc/environment
|
||||
# (read by pam_env at session open, before any shell rc fires) and
|
||||
# pinned readonly via /etc/bash.bashrc — `export PROMPT_COMMAND=""`
|
||||
# fails with "readonly variable" instead of silently disabling the
|
||||
# capture. Function name is generic ("__bash_history_sync") so a
|
||||
# casual `set | grep PROMPT` doesn't surface DECNET branding; the
|
||||
# logger invocation looks like a stock bash housekeeping helper.
|
||||
RUN printf 'PROMPT_COMMAND=__bash_history_sync\n' >> /etc/environment \
|
||||
&& printf '%s\n' \
|
||||
'# bash history → syslog, system-wide.' \
|
||||
'__bash_history_sync() {' \
|
||||
' logger --rfc5424 --msgid command -p user.info -t bash "CMD uid=$UID user=$USER src=${SSH_CLIENT%% *} pwd=$PWD cmd=$(history 1 | sed '"'"'s/^ *[0-9]* *//'"'"')"' \
|
||||
'}' \
|
||||
'readonly -f __bash_history_sync 2>/dev/null || true' \
|
||||
'readonly PROMPT_COMMAND 2>/dev/null || true' \
|
||||
>> /etc/bash.bashrc
|
||||
|
||||
# Fake project files to look lived-in
|
||||
RUN mkdir -p /root/projects /root/backups /var/www/html && \
|
||||
|
||||
@@ -82,8 +82,21 @@ RUN mkdir -p /root/scripts /root/backups && \
|
||||
printf 'DB_HOST=10.0.0.5\nDB_USER=admin\nDB_PASS=changeme123\n' > /root/.env && \
|
||||
printf 'alias ll="ls -alF"\nalias la="ls -A"\nexport HISTSIZE=1000\n' >> /root/.bashrc
|
||||
|
||||
# Log bash commands via syslog
|
||||
RUN echo 'PROMPT_COMMAND='"'"'logger --rfc5424 --msgid command -p user.info -t bash "CMD uid=$UID pwd=$PWD cmd=$(history 1 | sed "s/^ *[0-9]* *//")";'"'" >> /root/.bashrc
|
||||
# Command-event capture. PROMPT_COMMAND is set in /etc/environment
|
||||
# (read by pam_env at /bin/login session open, before any shell rc
|
||||
# fires) and pinned readonly via /etc/bash.bashrc — `export
|
||||
# PROMPT_COMMAND=""` fails with "readonly variable" instead of
|
||||
# silently disabling capture. Function name is generic so a casual
|
||||
# `set | grep PROMPT` doesn't surface DECNET branding.
|
||||
RUN printf 'PROMPT_COMMAND=__bash_history_sync\n' >> /etc/environment \
|
||||
&& printf '%s\n' \
|
||||
'# bash history → syslog, system-wide.' \
|
||||
'__bash_history_sync() {' \
|
||||
' logger --rfc5424 --msgid command -p user.info -t bash "CMD uid=$UID pwd=$PWD cmd=$(history 1 | sed '"'"'s/^ *[0-9]* *//'"'"')"' \
|
||||
'}' \
|
||||
'readonly -f __bash_history_sync 2>/dev/null || true' \
|
||||
'readonly PROMPT_COMMAND 2>/dev/null || true' \
|
||||
>> /etc/bash.bashrc
|
||||
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
Reference in New Issue
Block a user