SSH Command Restrictions

When SSH command restrictions are set, users may only perform whitelisted commands. SSH command restrictions are configured as white-list glob or regular-expression patterns.

You can define whitelists per target SSH account. Each target SSH account may have:

  • A default whitelist. All users with access to the account may perform these whitelisted commands.
  • Additional role-based whitelists. Use these to allow users with certain roles to perform additional commands.

Users can perform any command that is allowed by the default whitelist, or by additional whitelists that match their roles.

High-level steps for enabling SSH command restrictions includes:

  1. Creating SSH command whitelists.
  2. Associating whitelists to SSH target accounts.

When SSH command restrictions are enabled for a host account, the restrictions control the following:

  • SSH shell: Shell channel is terminated at PrivX server's restricted shell where user input is parsed into sequences of shell commands and each command is verified. Allowed commands are executed on the target server.
  • SSH exec: The command sent in SSH protocol's exec request is verified and - if allowed then - executed on the target server.

During validation the executed command is first split into a set of normalized sub-commands. Every sub-command must match a whitelist pattern for the command to be allowed to execute.

The normalization step does the following:

  • Reconstructs the statement to a one line statement
  • Removes extra white space and adds white space where it is missing
  • Replaces the deprecated backtick syntax with command substitution syntax $()
  • Removes trailing shell comments

Complex statements like if statements, while loops, command substitutions, etc. result into a set of sub commands that always includes the whole normalized statement and then the individual commands within the statement. For examples about complex commands and whitelist patterns, see SSH Command Restrictions.

Both normalization and pattern matching are done in the context of the target user's login-shell variant. The shell variant is configured in the PrivX host account command restrictions. PrivX supports bash and posix shell variants.

Allowing and blocking execution of commands generates audit events based on the host account configuration.

When To Use SSH Command Restrictions

The recommended way to control what users are allowed to execute on target hosts is to implement proper access control and separation of duties using target system user accounts, groups, file system permissions and sudoer configurations. This ensures that user's permissions on the target host are same regardless of how the user connects to the target.

However, sometimes re-configuring the target server is not possible or - due to the temporary nature of the need for access - it is not feasible. In such cases the SSH command restrictions feature can be used to restrict the commands a user is allowed to execute when connecting to the target host through PrivX.

The feature can also be used when execution of commands should not be not restricted, but certain commands should trigger alerts. This can be achieved by forwarding audit events to an external SIEM system.

Managing Whitelists

You can manage SSH command whitelists under Administration→Deployment→SSH Command Whitelists.

A whitelist consists of:

  • A unique name
  • Pattern type: glob or regex
  • List of patterns
  • Optional comment

Glob Pattern Syntax

You can use glob patterns to specify whitelisted commands.

pattern:
    { term }

term:
    `*`         matches any sequence of non-separator characters
    `**`        matches any sequence of characters
    `?`         matches any single non-separator character
    `[` [ `!` ] { character-range } `]`
                character class (must be non-empty)
    `{` pattern-list `}`
                pattern alternatives
    c           matches character c (c != `*`, `**`, `?`, `\`, `[`, `{`, `}`)
    `\` c       matches character c

character-range:
    c           matches character c (c != `\\`, `-`, `]`)
    `\` c       matches character c
    lo `-` hi   matches character c for lo <= c <= hi

pattern-list:
    pattern { `,` pattern }
                comma-separated (without spaces) patterns

Regular Expression Syntax

Regular expressions provide a more complex and powerful language for specifying whitelist patterns.

Regular expression patterns follow the standard golang regexp rules:

When matching against commands, the regexp patterns return a match that begins as early as possible in the input (leftmost), and among those it chooses the one that a backtracking search would have found first. This so-called leftmost-first matching is the same semantics that Perl, Python, and other implementations use, although it is implemented without the expense of backtracking.

📘

Note

Regular-expression patterns for whitelists must start with the start anchor ^. Otherwise the patterns could match parts in the middle of commands, which leads to unwanted command-validation results.s

📘

Note

Regular expressions are inherently harder to get right than glob patterns. We recommend preferring glob patterns, and using regular expressions only for patterns that cannot be expressed with glob.

Pattern Testing

You should always verify that the patterns match only the required commands, and do not accidentally match any unwanted commands.

To test patterns, select a whitelist and expand Evaluate Patterns. Here you can specify the shell variant and type in a list of test commands. PrivX parses the whitelist patterns and evaluates the test commands. The evaluation result is displayed in the GUI.

For additional suggestions about whitelist patterns, see Common Pitfalls and Whitelist Pattern Cheat Sheet.

Enabling Command Restrictions On Host Accounts

Command restrictions are enabled per host account in the PrivX GUI, on Administration→Hosts→Host.

Command restrictions for an account in the target host:

  • Enable command restrictions: enable or disable command restrictions for the host account.
  • Command whitelist: specify the default whitelist.
  • Rshell variant: specify the target-account login-shell variant, bash or posix.
  • Rshell terminal banner: optional banner to be displayed in the SSH terminal.
  • Command policies
    • Allow unmatched commands: Allow execution of commands that do not match any whitelist patterns.
    • Audit matched commands: Generate an SSH-whitelisted-command-allowed (1801) sensitive audit event when a command matching a whitelist pattern is allowed to execute.
    • Audit unmatched commands: Generate a SSH-command-blocked (1803) sensitive audit event when a command is blocked or a SSH-non-whitelisted-command-allowed (1802) when a command not matching any whitelist pattern is allowed to execute.

📘

Note

All audit events containing SSH commands are generated with audit-exposure: sensitive. Default rsyslog configuration shipped in PrivX rpm will silently drop such audit events to avoid such sensitive SSH commands to be persisted to log files on the PrivX server.

For more information about sending sensitive audit events to SIEM, see Session Recording.

Differences To Normal SSH Shell

PrivX restricted-shell functionality is more restricted compared to a normal SSH shell.

Environment Variables

Environment variables do not persist over multiple commands:

rshell:[email protected]:/home/user$ export foo=bar
rshell:[email protected]:/home/user$ echo $foo

rshell:[email protected]:/home/user$

However they are available in all commands executed on one line:

rshell:[email protected]:/home/user$ export foo=bar; echo $foo
bar
rshell:[email protected]:/home/user$

Exit Status

Exit status of previous command is not available after the command has returned. However similar to environment variables, the exit status is available in $? in other commands executed on the same line:

rshell:[email protected]:/home/user$ /bin/false; echo $?
1
rshell:[email protected]:/home/user$

Background Processes

Processes cannot be started in the background, also processes cannot be intercepted and moved to background.

Command History And Command Completion

Target-server shell-command history is unavailable. However, the command history of ongoing SSH sessions can be browsed with up and down arrows.

Shell-command completion is unavailable.

Common Pitfalls

Testing Only Allowed Commands

When writing whitelist patterns you should always test that the patterns do not unintentionally allow commands that should be blocked.

Allowing Users To Launch Child Shell Processes

Command restrictions are applied only to the user's login shell or SSH exec command. If the whitelist allows the user to launch child shell process, then the command restrictions cannot be applied to any commands executed within the child shell process.

Ways for a user to launch a child shell process:

  • Explicit command: /bin/sh, /bin/bash, etc
  • Instruct a running program to open a shell: For example !sh in less, :shell in vi or M-x shell in emacs
  • Via su or sudo -i

📘

Note

Some programs can be started in a restricted mode which has disabled starting child shell processes. For example vi -Z and rview commands start vi in restricted mode where the :shell command is disabled.

Allowing Directory Traversal

Too open whitelist patterns may allow users to open or modify unintended files.

For example a regex pattern ^vi -Z /etc/rsyslog\.d/.*$ would allow the following commands:
vi -Z /etc/rsyslog.d/privx-syslog.conf
vi -Z /etc/rsyslog.d/../sudoers

📘

Note

In glob syntax the wildcard * never matches the directory separator, but ** does. In regular expression syntax [^/] matches all other characters except the directory separator /, but .* matches every character including the directory separator.

Allowing Command Substitutions

Command substitutions can be used for obfuscating commands.

For example the command $(echo "Y2F0IC9ldGMvcGFzc3dkCg==" | base64 -d) executes the shell command cat /etc/passwd. Therefore a whitelist that allows $(**), echo ** and base64 ** effectively allows executing any command.

Allowing User To Modify Scripts And Execute Them

Allowing commands to be executed from directories where the user has write permissions may enable the user to modify the command before executing it. This can happen for example in following ways:

  • User is allowed to execute commands that modify or overwrite other allowed scripts and commands
  • User is allowed to redirect command output to overwrite other allowed scripts and commands
  • User is allowed to upload files and overwrite other allowed scripts and commands

The PrivX host account service options can be used to disable file transfers.

📘

Note

Typical editors support opening files, creating files and saving to alternate files. Allowing user to launch an editor as a privileged user may enable the user to replace binaries and scripts on the target system.

Whitelist Pattern Cheat Sheet

Simple Commands

command-a; command-b

Each command is whitelisted separately.

Example Command

ls -la; rm /tmp/foo

Glob Pattern

ls**
rm /tmp/*

Regex Pattern

^ls.*$
^rm /tmp/[^/]+$

AND, OR, Command Pipelining

command-a && command-b
command-a || command-b
command-a | command-b

Commands on both sides of the operator are whitelisted separately.

Example Command

echo foo | tr 'f' 'b'

Glob Pattern

echo **
tr **

Regex Pattern

^echo .*$
^tr .*$

Redirection

command <input >output

Complete statement and command are whitelisted separately.

Example Command

base64 <input.txt >output.txt

Glob Pattern

base64
base64 <input.txt >output.txt

Regex Pattern

^base64$
^base64 <[^<>]*>[^<>]*$

📘

Note

Glob patterns cannot be used to express character sequences that exclude redirection characters > and <.

Conditional Statements

if cond-a; then command-a; elif cond-b; then command-b; else command-c; fi
case word in pattern) command-a;; *) command-b;; esac

Conditional statement is whitelisted separately. All conditions and commands within the body are whitelisted separately.

Example Command

if /bin/true; then
echo "yep"
elif /bin/false; then
echo "nope"
else
echo "unknown"
fi

Glob Pattern

if **; then **; elif **; then **; else **; fi
/bin/true
/bin/false
echo **

Regex Pattern

^if [^;]+; then .*; elif [^;]+; then .*; else .*; fi$
^/bin/true$
^/bin/false$
^echo .*$

While And Until Loops

while cond; do command-a; done
until cond; do command-a; done

Loop statement is whitelisted separately. The condition and all commands within the body are whitelisted separately.

Example Command

while /bin/true; do echo "foo"; done

Glob Pattern

while **; do **; done
/bin/true
echo **

Regex Pattern

^while [^;]+; do .*; done$
^/bin/true$
^echo .*$

For Loops

for name in word; do command-a; done

Loop statement is whitelisted separately. Commands within the body are whitelisted separately.

Example Command

for d in /tmp/ /etc/ /usr/local/; do echo $d; done

Glob Pattern

for **; do **; done
echo **

Regex Pattern

^for [^;]+; do .*; done$
^echo .*$

Bash C-Style For Loop

for (( expr1; expr2; expr3 )); do command-a; done

Loop statement is whitelisted separately. Arithmetic expression is whitelisted separately. Commands within the body are whitelisted separately.

Example Command

for (( i = 0; i < 10; i = i +1 )); do echo $i; done

Glob Pattern

for **; do **; done
((**))
echo **

Regex Pattern

^for [^;]+; do .*; done$
^\(\(.*\)\)$
^echo .*$

Conditional Constructs

[ command ]

Conditional construct is whitelisted separately.

Example Command

[ -n "$foo" ]

Glob Pattern

\[ ** \]

Regex Pattern

^\[ .* \]$

Bash style

[[ expression ]]

Conditional construct is whitelisted separately.

Example Command

[[ $foo -ge 0 ]]

Glob Pattern

\[\[ ** \]\]

Regex Pattern

^\[\[ .* \]\]$

Command Substitution

$(command)
`command`

Command substitution and all commands are whitelisted separately.

Example Command

$(echo "Y2F0IC9ldGMvcGFzc3dkCg==" | base64 -d)

Glob Pattern

$(**)
echo **
base64 -d

Regex Pattern

^\$\(.*\)$
^echo .*$
^base64 -d$

📘

Note

The normalization step converts deprecated backtick syntax to $() command substitution syntax. The whitelist patterns must always be written to match the $() syntax.


Did this page help you?