Last active
January 3, 2021 14:52
-
-
Save ckxng/236f7bba03320570bf482848791bbe29 to your computer and use it in GitHub Desktop.
emergency shell script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl -WT | |
# Using taint and strict. All variables must be declared and all input must be | |
# processed before use. The most aggressive settings are used for warnings. | |
# This script will fail if it is misused or perscribed conditions are not met. | |
use warnings FATAL => 'all'; | |
use strict; | |
=head1 NAME | |
emergency-shell | |
=cut | |
package Ckxng::EmergencyShell; | |
=head1 SYNOPSIS | |
% sudo emergency-shell | |
This shell is for emergency use only. | |
If you require routine access to run commands with elevated priviliges, please | |
update config management or open a request for the specific access required. | |
You are required to enter a ticket number related to your activities. This use | |
of the emergency shell will be logged if you continue. Ctrl-C to exit. | |
Ticket number (AAA-123 or INC123): JIRA-1234 | |
Script started, file is /var/log/eshell/history.username.2021-01-03.374910.JIRA-1234.typescript | |
JIRA-1234! root:/home/username# env | |
=head1 DESCRIPTION | |
This script safely creates an interactive shell which is logged, three | |
different ways: syslog (via. logger), disk (via. bash history), and full | |
session recording to disk (via. script). Logs are written to a common | |
directory, but posix permissions prevent users other than the effective user | |
from reading the logs on disk. | |
=head1 INSTALL | |
This script was designed for Linux systems, and has only been tested on Ubuntu | |
and CentOS operating systems. | |
The following binaries must be available: | |
=over 4 | |
=item * /bin/bash | |
=item * /usr/bin/stat | |
=item * /usr/bin/tty | |
=item * /usr/bin/logger | |
=item * /usr/bin/script | |
=back | |
The directory I</var/log/eshell> should be created with mode 1777. | |
mkdir /var/log/eshell | |
chmod 1777 /var/log/eshell | |
=head1 SUBROUTINES | |
=head2 B<prompt>() | |
Warn the user that this script is for emergency use only and collect the ticket | |
number. JIRA-type ticket numbers are accepted, as well as tickets beginning | |
with "INC" followed by a number. | |
If an invalid ticket is detected, or Ctrl-C is captured, then quit without | |
logging anything. | |
=cut | |
sub prompt { | |
print <<BANNER; | |
This shell is for emergency use only. | |
If you require routine access to run commands with elevated priviliges, please | |
update config management or open a request for the specific access required. | |
You are required to enter a ticket number related to your activities. This use | |
of the emergency shell will be logged if you continue. Ctrl-C to exit. | |
BANNER | |
print 'Ticket number (AAA-123 or INC123): '; | |
my $ticket; | |
if(<> =~ /^([a-zA-Z]+\-[0-9]+|[iI][nN][cC][0-9]+)$/) { | |
$ticket = $1; | |
} else { | |
print "Invalid ticket number. Quitting.\n"; | |
exit 1; | |
} | |
$ENV{SHELLTICKET} = $ticket; | |
} | |
=head2 B<envsetup>() | |
B<prompt>() must complete successfully before calling this subroutine. | |
Otherwise, blanks will be seen anywhere that SHELLTICKET is expected and perl | |
will complain. | |
Strip away most existing environment variapbles to prevent tampering and setup | |
the environment for the shell session. This is also where logging is | |
configured in bash and where the log prefix string is created for logger to | |
send to syslog. | |
=cut | |
sub envsetup { | |
# strip all environment variables except HOME or SHELLTICKET (which we set) | |
# to prevent leakage and tampering with shell logging mechanisms | |
for my $key(keys(%ENV)) { | |
delete $ENV{$key} unless $key =~ /^(HOME|SHELLTICKET)$/; | |
} | |
# must be set when in taint mode before using a subshell | |
$ENV{PATH} = '/bin:/sbin:/usr/bin:/usr/sbin'; | |
# discover the current time and save the values into the environment | |
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(); | |
$ENV{SHELLDATETIME} = sprintf('%04d-%02d-%02dT%02d:%02d:%02d', $year+1900, $mon+1, $mday, $hour, $min, $sec); | |
$ENV{SHELLDATE} = sprintf('%04d-%02d-%02d', $year+1900, $mon+1, $mday); | |
# discover the currnet owner of the tty, and set it if the value is compliant | |
# with POSIX standard IEEE Std 1003.1-2001 3.426 and 3.276 | |
my $user = `/usr/bin/stat -c %U \$(/usr/bin/tty)`; | |
if($user =~ /^([a-zA-Z_\.][a-zA-Z0-9\-_\.]*)$/) { | |
$ENV{SHELLUSER} = $1; | |
} else { | |
die "Unable to determine tty owner using stat and tty commands\n"; | |
} | |
# discover the current PID of this process, and use it as the shellid for | |
# logging purposes | |
$ENV{SHELLID} = $$; | |
# log the following essential information with each syslog message. (note | |
# that the tty user is already captured by default when using logger) | |
$ENV{SHELLLOGPREFIX} = sprintf('SHELL=%s TICKET=%s', $ENV{SHELLID}, $ENV{SHELLTICKET}); | |
# setup the environment for later use by bash | |
$ENV{PS1} = sprintf('%s! \u:\w\$ ', $ENV{SHELLTICKET}); | |
$ENV{HISTFILE} = sprintf('/var/log/eshell/history.%s.%s.%s.%s', $ENV{SHELLUSER}, $ENV{SHELLDATE}, $ENV{SHELLID}, $ENV{SHELLTICKET}); | |
$ENV{PROMPT_COMMAND} = sprintf('RETURN=$?; history -a; /usr/bin/logger "%s HISTORY: $(history 1)"', $ENV{SHELLLOGPREFIX}); | |
# set the umask before creating any files. this prevents users other than | |
# the effective user from reading logs | |
umask 0077; | |
} | |
=head2 B<openhistory>() | |
B<prompt>() and B<envsetup>() must complete sucessfully before calling this | |
subroutine. Otherwise, log files might be created in the current working | |
directory, or logfile creation might fail. Blanks will also appear in the | |
written log file, and perl will complain. | |
Due to a quirk in how the history command within bash operates, we have a | |
clever opportunity to log some extra metadata at the beginning of the history | |
session. When PROMPT_COMMAND executes for the first time, before the user has | |
actually executed a command, the embedded I<history 1> command will retrieve | |
the previous command and log it via. I<logger>. By creating our own history | |
file, and logging this line to it, we are able to inject this entry as the | |
first line logged. If we did not do this, a blank line would be logged as the | |
first entry instead. | |
=cut | |
sub openhistory { | |
# add an initial logging line to the history file | |
open HIST, sprintf('>%s', $ENV{HISTFILE}) or die sprintf('HISTFILE %s cannot be opened', $ENV{HISTFILE}); | |
printf HIST "# History for USER=%s DATETIME=%s %s\n", $ENV{SHELLUSER}, $ENV{SHELLDATETIME}, $ENV{SHELLLOGPREFIX}; | |
close HIST; | |
} | |
=head2 B<runshell>() | |
B<prompt>() and B<envsetup>() must complete sucessfully before calling this | |
subroutine, and B<openhistory>() is recommended. If this is not done, then | |
SHELLLOGPREFIX will be blank, and more importantly, so will HISTFILE, which | |
will cause script to write files to the local directory, or fail. Not running | |
B<envsetup>() will also prevent the I<umask> from being set correctly, which | |
will have security ramifications. | |
Run a I<bash> shell (without reading rc files) from within the context of the | |
I<script> command. This will log all input and output.If a user's input or | |
outut contains PII or PHI, then this file could be sensitive. It is imperitive | |
that B<envsetup> set the I<umask> prior to running these commands or else users | |
other than this effective user might be able to read the logs. | |
=cut | |
sub runshell { | |
# log this execution and open the shell | |
my $error = system '/usr/bin/logger', sprintf('%s Starting emergency shell', $ENV{SHELLLOGPREFIX}); | |
die "Failed to log using logger\n" if $error; | |
$error = system '/usr/bin/script', '-c', '/bin/bash --norc', '-f', sprintf('-t%s.timing', $ENV{HISTFILE}), sprintf('%s.typescript', $ENV{HISTFILE}); | |
die "Failed to run bash shell using script\n" if $error; | |
$error = system '/usr/bin/logger', sprintf('%s Stopping emergency shell', $ENV{SHELLLOGPREFIX}); | |
die "Failed to log using logger\n" if $error; | |
} | |
=head2 B<main>() | |
Run each of the subroutines in the correct sequence when this module is called | |
as a script. | |
=cut | |
sub main { | |
# run all subroutines | |
prompt(); | |
envsetup(); | |
openhistory(); | |
runshell(); | |
} | |
main() unless caller; | |
=head1 COPYRIGHT | |
Copyright (c) 2021. Cameron King. | |
All rights reserved. | |
Redistribution and use in source and binary forms, with or without | |
modification, are permitted provided that the following conditions are met: | |
1. Redistributions of source code must retain the above copyright notice, this | |
list of conditions and the following disclaimer. | |
2. Redistributions in binary form must reproduce the above copyright notice, | |
this list of conditions and the following disclaimer in the documentation | |
and/or other materials provided with the distribution. | |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | |
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
=head1 AUTHOR | |
Cameron King <http://cameronking.me> | |
=cut | |
1; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
NAME | |
emergency-shell | |
SYNOPSIS | |
% sudo emergency-shell | |
This shell is for emergency use only. | |
If you require routine access to run commands with elevated priviliges, please | |
update config management or open a request for the specific access required. | |
You are required to enter a ticket number related to your activities. This use | |
of the emergency shell will be logged if you continue. Ctrl-C to exit. | |
Ticket number (AAA-123 or INC123): JIRA-1234 | |
Script started, file is /var/log/eshell/history.username.2021-01-03.374910.JIRA-1234.typescript | |
JIRA-1234! root:/home/username# env | |
DESCRIPTION | |
This script safely creates an interactive shell which is logged, three | |
different ways: syslog (via. logger), disk (via. bash history), and full | |
session recording to disk (via. script). Logs are written to a common | |
directory, but posix permissions prevent users other than the effective | |
user from reading the logs on disk. | |
INSTALL | |
This script was designed for Linux systems, and has only been tested on | |
Ubuntu and CentOS operating systems. | |
The following binaries must be available: | |
* /bin/bash | |
* /usr/bin/stat | |
* /usr/bin/tty | |
* /usr/bin/logger | |
* /usr/bin/script | |
The directory */var/log/eshell* should be created with mode 1777. | |
mkdir /var/log/eshell | |
chmod 1777 /var/log/eshell | |
SUBROUTINES | |
prompt() | |
Warn the user that this script is for emergency use only and collect the | |
ticket number. JIRA-type ticket numbers are accepted, as well as tickets | |
beginning with "INC" followed by a number. | |
If an invalid ticket is detected, or Ctrl-C is captured, then quit | |
without logging anything. | |
envsetup() | |
prompt() must complete successfully before calling this subroutine. | |
Otherwise, blanks will be seen anywhere that SHELLTICKET is expected and | |
perl will complain. | |
Strip away most existing environment variapbles to prevent tampering and | |
setup the environment for the shell session. This is also where logging | |
is configured in bash and where the log prefix string is created for | |
logger to send to syslog. | |
openhistory() | |
prompt() and envsetup() must complete sucessfully before calling this | |
subroutine. Otherwise, log files might be created in the current working | |
directory, or logfile creation might fail. Blanks will also appear in | |
the written log file, and perl will complain. | |
Due to a quirk in how the history command within bash operates, we have | |
a clever opportunity to log some extra metadata at the beginning of the | |
history session. When PROMPT_COMMAND executes for the first time, before | |
the user has actually executed a command, the embedded *history 1* | |
command will retrieve the previous command and log it via. *logger*. By | |
creating our own history file, and logging this line to it, we are able | |
to inject this entry as the first line logged. If we did not do this, a | |
blank line would be logged as the first entry instead. | |
runshell() | |
prompt() and envsetup() must complete sucessfully before calling this | |
subroutine, and openhistory() is recommended. If this is not done, then | |
SHELLLOGPREFIX will be blank, and more importantly, so will HISTFILE, | |
which will cause script to write files to the local directory, or fail. | |
Not running envsetup() will also prevent the *umask* from being set | |
correctly, which will have security ramifications. | |
Run a *bash* shell (without reading rc files) from within the context of | |
the *script* command. This will log all input and output.If a user's | |
input or outut contains PII or PHI, then this file could be sensitive. | |
It is imperitive that envsetup set the *umask* prior to running these | |
commands or else users other than this effective user might be able to | |
read the logs. | |
main() | |
Run each of the subroutines in the correct sequence when this module is | |
called as a script. | |
COPYRIGHT | |
Copyright (c) 2021. Cameron King. All rights reserved. | |
Redistribution and use in source and binary forms, with or without | |
modification, are permitted provided that the following conditions are | |
met: | |
1. Redistributions of source code must retain the above copyright | |
notice, this list of conditions and the following disclaimer. | |
2. Redistributions in binary form must reproduce the above copyright | |
notice, this list of conditions and the following disclaimer in the | |
documentation and/or other materials provided with the distribution. | |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS | |
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | |
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | |
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
AUTHOR | |
Cameron King <http://cameronking.me> | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ubuntu@evergreenastronaut:~$ sudo ./emergency-shell | |
This shell is for emergency use only. | |
If you require routine access to run commands with elevated priviliges, please | |
update config management or open a request for the specific access required. | |
You are required to enter a ticket number related to your activities. This use | |
of the emergency shell will be logged if you continue. Ctrl-C to exit. | |
Ticket number (AAA-123 or INC123): JIRA-1234 | |
Script started, file is /var/log/eshell/history.ubuntu.2021-01-03.395451.JIRA-1234.typescript | |
JIRA-1234! root:/home/ubuntu# echo run a command | |
run a command | |
JIRA-1234! root:/home/ubuntu# echo run another command | |
run another command | |
JIRA-1234! root:/home/ubuntu# exit | |
exit | |
Script done, file is /var/log/eshell/history.ubuntu.2021-01-03.395451.JIRA-1234.typescript | |
ubuntu@evergreenastronaut:~$ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# History for USER=ubuntu DATETIME=2021-01-03T14:23:01 SHELL=395451 TICKET=JIRA-1234 | |
echo run a command | |
echo run another command | |
exit |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
0.003560 30 | |
3.033723 1 | |
0.061984 1 | |
0.076380 1 | |
0.046076 1 | |
0.223954 1 | |
0.208059 1 | |
0.114652 1 | |
0.051358 1 | |
0.211239 1 | |
0.100356 1 | |
0.117366 1 | |
0.157549 1 | |
0.089730 1 | |
0.176789 1 | |
0.139236 1 | |
0.106526 1 | |
0.086671 1 | |
0.124839 1 | |
0.135567 17 | |
0.001789 30 | |
0.605897 1 | |
0.038596 1 | |
0.755005 1 | |
0.047924 1 | |
0.233848 1 | |
0.165533 1 | |
0.066058 1 | |
0.057611 1 | |
0.185927 1 | |
0.099346 1 | |
0.092502 1 | |
0.061427 1 | |
0.085258 1 | |
0.119080 1 | |
0.057180 1 | |
0.054575 1 | |
0.119789 1 | |
0.102141 1 | |
0.148284 1 | |
0.201591 1 | |
0.069085 1 | |
0.082920 1 | |
0.116040 1 | |
0.152838 1 | |
0.055638 2 | |
0.000129 19 | |
0.000070 2 | |
0.002300 30 | |
0.603975 1 | |
0.217612 1 | |
0.121065 1 | |
0.138238 1 | |
0.126667 8 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Script started on 2021-01-03 14:23:01+00:00 [TTY="/dev/pts/0" COLUMNS="80" LINES="25"] | |
JIRA-1234! root:/home/ubuntu# echo run a command | |
run a command | |
JIRA-1234! root:/home/ubuntu# echo run another command | |
run another command | |
JIRA-1234! root:/home/ubuntu# exit | |
exit | |
Script done on 2021-01-03 14:23:11+00:00 [COMMAND_EXIT_CODE="0"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ubuntu@evergreenastronaut:~$ ls -l /var/log/eshell | |
total 12 | |
-rw------- 1 root root 134 Jan 3 14:23 history.ubuntu.2021-01-03.395451.JIRA-1234 | |
-rw------- 1 root root 599 Jan 3 14:23 history.ubuntu.2021-01-03.395451.JIRA-1234.timing | |
-rw------- 1 root root 339 Jan 3 14:23 history.ubuntu.2021-01-03.395451.JIRA-1234.typescript |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Logs begin at Sat 2020-10-31 06:10:59 UTC, end at Sun 2021-01-03 14:23:11 UTC. -- | |
Jan 03 14:22:57 evergreenastronaut sudo[395450]: ubuntu : TTY=pts/0 ; PWD=/home/ubuntu ; USER=root ; COMMAND=./emergency-shell | |
Jan 03 14:22:57 evergreenastronaut sudo[395450]: pam_unix(sudo:session): session opened for user root by ubuntu(uid=0) | |
Jan 03 14:23:01 evergreenastronaut ubuntu[395455]: SHELL=395451 TICKET=JIRA-1234 Starting emergency shell | |
Jan 03 14:23:01 evergreenastronaut ubuntu[395460]: SHELL=395451 TICKET=JIRA-1234 HISTORY: 1 # History for USER=ubuntu DATETIME=2021-01-03T14:23:01 SHELL=395451 TICKET=JIRA-1234 | |
Jan 03 14:23:06 evergreenastronaut ubuntu[395462]: SHELL=395451 TICKET=JIRA-1234 HISTORY: 2 echo run a command | |
Jan 03 14:23:10 evergreenastronaut ubuntu[395464]: SHELL=395451 TICKET=JIRA-1234 HISTORY: 3 echo run another command | |
Jan 03 14:23:11 evergreenastronaut ubuntu[395465]: SHELL=395451 TICKET=JIRA-1234 Stopping emergency shell | |
Jan 03 14:23:11 evergreenastronaut sudo[395450]: pam_unix(sudo:session): session closed for user root |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment