[cs615asa] ctf notes

Jan Schaumann jschauma at stevens.edu
Mon May 9 11:52:32 EDT 2016


All,

Here's a review of the different levels of the CtF, and what I hope they
helped teach.  The CtF was similar to the ones I've run in the past,
with a few minor changes here and there.  As always, some of the levels
had solutions that I didn't anticipate, which is a great way to
illustrate that designing safe systems is incredibly difficult.

One of the things to keep in mind is that I do not have any special
privileges on linux-lab.cs.stevens.edu.  That is, all the tasks on those
systems were set up with privileges identical to yours.  You might find
it interesting to think about how to set this up yourself.

Level 0:

As explained in class, it is useful to be able to send and receive
encrypted emails.  The online tutorials are simple enough and easy to
follow, and even if fully understanding all aspects of PGP might take
some time and practice, I hope you're all off to a good start and will
begin using it.

By encrypting instructions for all members individually and requiring
you to submit signatures, I wanted to ensure that all members of the
team are at least marginally involved in the process and gain some
practice in decrypting/signing content.  If you did not fully understand
how any one level was solved by your team mates, I recommend that you
review the notes on your own time.

Note: you could have avoided a bottle-neck by sharing your private keys
with each other, thus allowing any one member to decrypt all messages or
to sign for all team members.  I hope you didn't do that, but especially
within the contet of a CtF it's useful to note the weaknesses of each
procedure.

Level 1:

The hash you received was quickly identified as a sha256 checksum.
Knowing that you can't reverse a hash, you did have to effectively
brute-force the input set.  Fortunately, that was small enough (a total
of 64 IP addresses).  I hope you were able to use ipcalc or similar
tools to easily determine the boundaries of the netblock given to you.
Iterating over the IP addresses and performing the reverse lookup is
something that could easily be scripted.

To find the file under /var/run, you could have tried to find any file
owned by me, or to review tany directories that allowed non-root users
to write to, or by last modification time, or...


Level 2:

The URL you were given didn't show the right password, but looking at
the source code, it included a hint to search for the sources of the
CGI.  Finding it in ~jschauma/cs_html/cgi-bin/ctf.cgi, you could then
inspect the source code, which included a commented out call to display
the file '/home/jschauma/tmp/level-3'.

That file was readable only by the 'www-data' user, that the web server
serving the site is running as.  You couldn't access this location using
your web browser, since it's outside of the ~/cs_html directory.

But by staging a symlink attack, you could cause it's disclosure:
~jschauma/cs_html/tmp/d was mode 777, meaning any user could remove or
create files in this directory.  By linking 'nope' to the desired file
~jschauma/tmp/level-3 you could the allow the web server to display the
contents of this file.

At least one team also figured out that they could run CGI's themselves
and copied the script into _their_ ~/cs_html/cgi-bin directory, thus
allowing them to display the file in question.


Level 3:

The IP address you were given was a decimal number.  Again, you had to
review a bit how IP addresses can be represented and convert the decimal
number into binary and then into quad-dotted decimals.  One way to do
this is by using the bc(1) command, which allows for easy conversion
between different bases:

$ bc
obase=2
2616613223
10011011111101100101100101100111
obase=10
ibase=2
1100111
103
^D
$

(There are of course a million other ways.  But it's worth noting that
there are solutions that do not require Google or access to the
internet.)

A neat little trick could allow you to avoid this math:

Some tools like ping(8) or telnet(1) accept IP addresses not only in
quad-dotted notation, but also as hexadecimal or decimal values.  Try to
run 'ping 2616613223' or 'telnet 0x9BF65967', for example.

Once you were on the system, you found that the program you were
instructed to run did not display the passphrase you needed.  If you
looked around in the directory the program was in, then you might have
found a file that you were not able to read, as it was mode 0400 and
owned by 'www-data'.  The program being setuid 'www-data' would be able
to read the file, but it didn't display the data you wanted.

By running strace(1) or strings(1) or perhaps even by guessing, you
could have realized that the program invokes the id(1) command.  Since
the program just ran "id" instead of using an absolute path, all you
needed to do was create a script called "id" that did what you needed it
to do (for example: "cat /var/tmp/ctf/whateverXXX"), add the directory
of where that script is stored to the beginning of your PATH variable
and run the command again.

This is a comman attack vector, as many programs shell out to execute
commands they expect to be in the user's PATH.  As a programmer, you
should be aware of this pattern and always defensively specify the full
path to an executable, explicitly set the PATH, or avoid shelling out
altogether.

One team then was clever enough to realize that they could change the
passphrase in question as well, thus throwing off any teams coming after
them.  That was well done, but not what I had in mind, so I had to
change the program to reset the file in question on each invocation
while at the same time not containing the passphrase itself in the
binary so that you couldn't get it from running strings(1), for example.


Level 4:

Having been given a password, it was easy to find that you could use
that to access a web interface for your account, which allowed you to
upload a file.  The file in question would then be placed in your home
directory.  All of you quickly found out that the form also contained a
second parameter allowing you to specify a sub directory, thus making it
possible for you to upload an ssh pubkey into ~/.ssh/authorized_keys,
thus granting you access to the system using your account.

In order to install the file in your home directory, I had used the cp(1)
program in your home directory.  At least one team realized that by
replacing that binary, they would have an arbitrary code execution path
for the 'www' user, which is not what I had intended, so I had to close
down that avenue of attack once you gained access to the system.

These changing circumstances are a good reflection of how these things
work in the so-called real world, too: things are in flux, systems
change, what once worked, stops and new methods arise.

Looking for the passphrase for level 4, you all looked for and wide, but
no team found it.  This really isn't a big deal, since the main
objective was for you to gain access to the system.  The passphrase for
level 4 was, as was stated in the instructions, found in your home
directory.  If you ran "ls -la" in your home directory, you might have
found a listing looking like this:

 ls -la
total 144
drwx------ 3 team user   4096 May  9 11:43 .
-rw------- 1 team user      4 May  9 11:43 . 
drwx------ 3 team user   4096 May  9 11:42 ..
drwx------ 2 team user   4096 May  9 11:43 .ssh
-rwx------ 1 team user 126032 May  9 11:43 cp

Note that there appear to be two entries for ".".  One of them is a
file, but the name is not actually ".", but ". ".  As repeatedly used in
this CtF, file names can be just about anything, including spaces.  The
file ". " in your home directory contained the passphrase.


Level 5:

This level had a number of steps.  You knew you had to take control of
the web server's index page, which you could find under
/usr/pkg/share/httpd/htdocs/index.html.  But that file was owned by the
'www' user.  You might have noticed that the time stamp on the file was
always recent: something was always updating it.

Looking for the 'www' user's crontab in /var/cron/tabs/www, you could
have found the following entry:

* * * * * /bin/reset-site

That is, 'www' was running the script /bin/reset-site every minute.
That script contained a line that, depending on the method used to
display it, may have looked a bit odd.  If you used 'cat -v', you might
have seen:

cp /var/tmp/d/^M/index.html /usr/pkg/share/httpd/htdocs/

The user copied the file from a funky looking directory to the website
root.  The directory name in question was "^M", which is the control
character used for a carriage-return.  You can enter the directory by
typing Ctrl+V followed by the return key.

That directory in turn was mode 777, meaning anybody could remove or
create files in there, regardless of ownership of the files themselves.
(Remember, removing or adding a file is just modifying the directory
it's in.)

That is, it was possible to take initial ownership of the flag without
gaining 'www' capabilities.  Surprisingly, none of you went down this
route (although severla of you later discovered and changed the crontab
once you did have ownership of the flag).


As many of you found, there was an odd process running: 'nc6 -6 -l -e
/bin/64sh'.  Or perhaps you found that there was something listening on
port 6666, but only via IPv6.

Looking at the manual page for nc6(1) and at the file /bin/64sh, you
would have found that this was a backdoor for the 'leaky' user that
requires no authentication, and that would execute any command so long
as it was base64 encoded.  That is, you were able to run any command as
'leaky' by, for example, running

echo 'ls -l' | base64 | nc6 ::1 6666

In the 'leaky' user's home directory, you would then find an executable
that was setuid root, only accessible to the 'leaky' user.  Trying to
run it, you'd find that if given a file, it claimed to have leaked it to
http://www.cs.stevens.edu/~jschauma/cgi-bin/leaky.cgi.  But that CGI
itself did not seem to do anything with the file, and there was no
obvious way to exploit the CGI itself.

However, since you are on the system from which the file is sent, and
since conveniently (and oddly) the tcpdump(8) program had been set
setuid, you were able to run tcpdump while running the 'leak' program.
Capturing all the packets, you'd also get all the data the program sent
-- meaning the contents of the file you gave it as an argument.

So now you had a way of seeing the contents of any file on the system.
Poking around the 'www' user's home directory, you should have found a
file called 'www', which did in fact contain the password for the
'www' user.  (The file 'password' became a decoy after one team
populated it with what looked like an entirely reasonable passphrase.)

Leaking that file to the CGI and extracting the data from the tcpdump
provided you with a method to log in as the 'www' user and thus capture
the flag.  From there, it was up to you to try to find ways to prevent
others from capturing the flag.

Many of you implemented a similar crontab as was originally in place; at
least one team wrote a (more efficient) program to monitor the flag file
and overwrite it with their contents whenever it changed.  Most of you
discovered the use of file flags (uchg, in particular) to make file
modifications a bit harder.

There were a number of different ways you could try to retain the flag
and keep others out.  Several of you blocked the nc6 service to prevent
others from using it; others tried to regularly kill all commands run by
the 'www' user.  As mentioned earlier, some of these defenses are
perhaps a bit noisy, as usually you want to remain stealthy when gaining
access to a system.


In the end, I'm glad that all teams managed to get to level 5, and that
we were able to run the CtF.   I hope you enjoyed it and learned a bit
about how the systems work from a more practical level.  Please do take
the time to reference the different lessons from the CtF with what we
covered in class.

-Jan


More information about the cs615asa mailing list