Introduction to the Course
When you click Start below, an embedded video lecture will automatically load!
As you watch it, the bar underneath will turn green.
If you skip any part of the lecture, that part of the bar will turn red or remain grey; seek back to it and watch it to turn it green.
Once the whole bar is green, at the end of the lecture, a flag will pop up!
Copy it (including the pwn.college{
beginning and }
end!) and paste it into the Flag
input box below to get the Participation grade for this lecture!
Do the same for the other lectures in the module (and the course!) and that'll make up your Participation grades.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
In this video, Yan said that this module is due Sunday, but it's actually due Tuesday as the calendar on [/cse365-f2025](the dojo page) says!
Apologies about the confusion.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Introduction to the Platform
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Introduction to Cybersecurity
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Interacting with the Dojo
Throughout your pwn.college journey, you will have countless interactions with the Linux terminal, colloquially termed the "shell".
If you don't yet know the Art of the Shell, fear not, you will!
For now, we'll just focus on launching it.
We make launching the terminal easy: when you start a challenge, we do it for you!
Just click ▶ Start
below, and this challenge will start.
Once it's loaded, the terminal will appear automatically right under this text, and you will be granted your first flag!
Flag?
As a reminder, this platform uses flags to track your progress.
Flags are cryptographic tokens that are given to you when you solve challenges.
Once you see it, copy-paste it into the submission box below and submit!
Then, once you get the confirmation that the flag was correct, move on to the next challenge!
Try it now: launch the terminal, copy the flag (drag-selecting it with your mouse will automatically copy it to your clipboard), and paste it into the Flag
textbox below!
NOTE:
Want more screen space?
You can click the "fullscreen" button (⛶) to full-screen the interface for more room.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
This challenge will teach you to use the Visual Studio Code workspace.
You can start this challenge using the Start button below.
When it starts, you'll probably see the Terminal, like the previous level.
This time, though, the challenge will refuse to give you the flag until you switch to vscode!
You can use the workspace selector on the bar below the Terminal (e.g., the button that says "Terminal") to select "Code" and bring up the Visual Studio Code interface in place of the terminal.
Again, you can use it as-is, or you can click the "fullscreen" button (⛶) to full-screen the interface for more room.
Once VSCode loads, launch a terminal (press Control-Shift-Backtick
or click the ☰
button in VSCode's left panel, and select the Terminal menu, and click New Terminal).
When we detect that you have launched the terminal in VSCode, we will give you the flag!
NOTE:
The pwn.college dojo will remember what the last workspace interface (Terminal, VSCode, etc.) you used, and will default to that, so the next challenge you run will now launch VSCode by default until you switch.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Next, we will explore the Desktop!
Start the challenge and use the workspace selector on the bar below Visual Studio Code (e.g., the button that says "Code") to select "Desktop".
This will launch up a Linux desktop for you to use!
This challenge requires you to open the terminal inside the Desktop, and we will give you the flag.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Next, we will learn to paste into the Desktop!
You will need this secret token: f8e5eb3178faf47ce5692f7f618e8f6f0e8769de7dd67ffe62b4375430a31e1b9d18a9574e8231e98572
.
Launch a terminal in the desktop for further directions!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Hacking is a contact sport.
There will be times when your attempts to hack through a level will result in irreparable damage to the workspace environment.
When this happens, don't panic, you can just restart the challenge!
This level will guide you through this concept.
On your first attempt, it will ask you for a password that you don't yet know.
When you get this password wrong, it will tell you what the right one is, but will then destroy the challenge and the flag file.
You'll need to restart the challenge (go back to this page and click the Start button below!) to try again.
Just start the terminal to give it a go.
Good luck!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
SENSAI is an LLM-powered assistant that can help you with your questions about the course.
It is totally optional to use; for more information, please see the course syllabus, and learn more about it in the "Getting Help" challenge here.
The Linux Luminarium
The rest of the material in this module will ensure that you understand Linux and can effectively reason about basic authentication and security concepts in Linux.
If scrolling through this page is annoying, you can access the challenges in a more structured way here.
However, you will still need to watch the lectures on this page.
Hello Hackers
This module will teach you the VERY basics of interacting with the command line!
The command line lets you execute commands.
When you launch a terminal, it will execute a command line "shell", which will look like this:
hacker@dojo:~$
This is called the "prompt", and it's prompting you to enter a command.
Let's take a look at what's going on here:
- The
hacker
in the prompt is the username of the current user.
In the pwn.college DOJO environment, this is "hacker".
- In the example above, the
dojo
part of the prompt is the hostname of the machine the shell is on (this reminder can be useful if you are a system administrator who deals with many machines on a daily basis, for example).
In the example above, the hostname is dojo
, but in pwn.college, it will be derived from the name of the challenge you're attempting.
- We will cover what
~
means later :-)
- The
$
at the end of the prompt signifies that hacker
is not an administrative user.
In much later modules in pwn.college, when you learn to use exploits to become the administrative user, you will see the prompt signify that by printing #
instead of $
, and you'll know that you've won!
Anyways, the prompt awaits your command.
Move on to the first challenge to learn how to actually execute commands!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
In this challenge, you will invoke your first command!
When you type a command and hit enter, the command will be invoked, as so:
hacker@dojo:~$ whoami
hacker
hacker@dojo:~$
Here, the user executed the whoami
command, which simply prints the username (hacker
) to the terminal.
When the command terminates, the shell once again displays the prompt, ready for the next command.
In this level, invoke the hello
command to get the flag!
Keep in mind: commands in Linux are case sensitive: hello
is different from HELLO
.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Let's try something more complicated: a command with arguments, which is what we call additional data passed to the command.
When you type a line of text and hit enter, the shell actually parses your input into a command and its arguments.
The first word is the command, and the subsequent words are arguments.
Observe:
hacker@dojo:~$ echo Hello
Hello
hacker@dojo:~$
In this case, the command was echo
, and the argument was Hello
.
echo
is a simple command that "echoes" all of its arguments back out onto the terminal, like you see in the session above.
Let's look at echo
with multiple arguments:
hacker@dojo:~$ echo Hello Hackers!
Hello Hackers!
hacker@dojo:~$
In this case, the command was echo
, and Hello
and Hackers!
were the two arguments to echo
.
Simple!
In this challenge, to get the flag, you must run the hello
command (NOT the echo
command) with a single argument of hackers
.
Try it now!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
You're going to type a lot of commands, and typing everything from scratch can be annoying.
Luckily, the shell saves a history of every command you invoke.
You can scroll through those saved commands with the up/down arrow keys, and we'll practice that in this challenge.
This challenge will inject the flag into your history.
Bring up a terminal, hit the up arrow, and grab it!
In other challenges, the history will contain the log of the commands you've run, so if you need to run a similar command again, you can use the arrow keys to scroll through and find it!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Pondering Paths
This module will teach you the basics of Linux file paths!
The Linux filesystem is a "tree".
That is, it has a root (written as /
).
The root of the filesystem is a directory, and every directory can contain other directories and files.
You refer to files and directories by their path.
A path from the root of the filesystem starts with /
(that is, the root of the filesystem), and describes the set of directories that must be descended into to find the file.
Every piece of the path is demarcated with another /
.
Armed with this knowledge, go forth and tackle the challenges below.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Alright, so the filesystem starts at /
.
Under that, there are a whole mess of other directories, configuration files, programs, and, most importantly, flags.
In this level, we've added a program right in /
, called pwn
, that will give you the flag.
All you need to do for this level is to invoke this program!
You can invoke a program by providing its path on the command line.
In this case, you'll be giving the exact path, starting from /
, so the path would be /pwn
.
This style of path, one that starts with the root directory, is referred to as an "absolute path".
Start the challenge, launch a terminal, invoke the pwn
program using its absolute path, and Capture that Flag!
Good luck!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Let's explore a slightly more complicated path!
Except for in the previous level, challenges in pwn.college are in the challenge
directory and the challenge
directory is, in turn, right in the root directory (/
).
The path to the challenge the directory is, thus, /challenge
.
The name of the challenge program in this level is run
, and it lives in the /challenge
directory.
Thus, the path to the run
challenge program is /challenge/run
.
This challenge again requires you to execute it by invoking its absolute path.
You'll want to execute the run
file that is in the challenge
directory that is, in turn, in the /
directory.
If you invoke the challenge correctly, it will give you the flag.
Good luck!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
The Linux filesystem has tons of directories with tons of files.
You can navigate around directories by using the cd
(c
hange d
irectory) command and passing a path to it as an argument, as so:
hacker@dojo:~$ cd /some/new/directory
hacker@dojo:/some/new/directory$
This affects the "current working directory" of your process (in this case, the bash shell).
Each process has a directory in which it's currently hanging out.
The reasons for this will become clear later in the module.
As an aside, now you can see what the ~
was in the prompt!
It shows the current path that your shell is located at.
This challenge will require you to execute the /challenge/run
program from a specific path (which it will tell you).
You'll need to cd
to that directory before rerunning the challenge program.
Good luck!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
The Linux filesystem has tons of directories with tons of files.
You can navigate around directories by using the cd
(c
hange d
irectory) command and passing a path to it as an argument, as so:
hacker@dojo:~$ cd /some/new/directory
hacker@dojo:/some/new/directory$
This affects the "current working directory" of your process (in this case, the bash shell).
Each process has a directory in which it's currently hanging out.
The reasons for this will become clear later in the module.
As an aside, now you can see what the ~
was in the prompt!
It shows the current path that your shell is located at.
This challenge will require you to execute the /challenge/run
program from a specific path (which it will tell you).
You'll need to cd
to that directory before rerunning the challenge program.
Good luck!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
The Linux filesystem has tons of directories with tons of files.
You can navigate around directories by using the cd
(c
hange d
irectory) command and passing a path to it as an argument, as so:
hacker@dojo:~$ cd /some/new/directory
hacker@dojo:/some/new/directory$
This affects the "current working directory" of your process (in this case, the bash shell).
Each process has a directory in which it's currently hanging out.
The reasons for this will become clear later in the module.
As an aside, now you can see what the ~
was in the prompt!
It shows the current path that your shell is located at.
This challenge will require you to execute the /challenge/run
program from a specific path (which it will tell you).
You'll need to cd
to that directory before rerunning the challenge program.
Good luck!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Now you're familiar with the concept of referring to absolute paths and changing directories.
If you put in absolute paths everywhere, then it really doesn't matter what directory you are in, as you likely found out in the previous three challenges.
However, the current working directory does matter for relative paths.
- A relative path is any path that does not start at root (i.e., it does not start with
/
).
- A relative path is interpreted relative to your current working directory (
cwd
).
- Your
cwd
is the directory that your prompt is currently located at.
This means how you specify a particular file, depends on where the terminal prompt is located.
Imagine we want to access some file located at /tmp/a/b/my_file
.
- If my
cwd
is /
, then a relative path to the file is tmp/a/b/my_file
.
- If my
cwd
is /tmp
, then a relative path to the file is a/b/my_file
.
- If my
cwd
is /tmp/a/b/c
, then a relative path to the file is ../my_file
. The ..
refers to the parent directory.
Let's try it here!
You'll need to run /challenge/run
using a relative path while having a current working directory of /
.
For this level, I'll give you a hint.
Your relative path starts with the letter c
😊
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Previously, your relative path was "naked": it directly specified the directory to descend into from the current directory.
In this level, we're going to explore more explicit relative paths.
In most operating systems, including Linux, every directory has two implicit entries that you can reference in paths: .
and ..
.
The first, .
, refers right to the same directory, so the following absolute paths are all identical to each other:
/challenge
/challenge/.
/challenge/./././././././././
/./././challenge/././
The following relative paths are also all identical to each other:
challenge
./challenge
./././challenge
challenge/.
Of course, if your current working directory is /
, the above relative paths are equivalent to the above absolute paths.
This challenge will get you using .
in your relative paths.
Get ready!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
In this level, we'll practice referring to paths using .
a bit more.
This challenge will need you to run it from the /challenge
directory.
Here, things get slightly tricky.
Linux explicitly avoids automatically looking in the current directory when you provide a "naked" path.
Consider the following:
hacker@dojo:~$ cd /challenge
hacker@dojo:/challenge$ run
This will not invoke /challenge/run.
This is actually a safety measure: if Linux searched the current directory for programs every time you entered a naked path, you could accidentally execute programs in your current directory that happened to have the same names as core system utilities!
As a result, the above commands will yield the following error:
bash: run: command not found
We'll explore the mechanisms behind this concept later, but in this challenge, we'll learn how to explicitly use relative paths to launch run
in this scenario.
The way to do this is to tell Linux that you explicitly want to execute a program in the current directory, using .
like in the previous levels.
Give it a try now!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Every user has a home directory, typically under /home
in the filesystem.
In the dojo, you are the hacker
user, and your home directory is /home/hacker
.
The home directory is typically where users store most of their personal files.
As you make your way through pwn.college, this is where you'll store most of your solutions.
Typically, your shell session will start with your home directory as your current working directory.
Consider the initial prompt:
hacker@dojo:~$
The ~
in this prompt is the current working directory, with ~
being shorthand for /home/hacker
.
Bash provides and uses this shorthand because, again, most of your time will be spent in your home directory.
Thus, whenever bash sees ~
provided as the start of an argument in a way consistent with a path, it will expand it to your home directory.
Consider:
hacker@dojo:~$ echo LOOK: ~
LOOK: /home/hacker
hacker@dojo:~$ cd /
hacker@dojo:/$ cd ~
hacker@dojo:~$ cd ~/asdf
hacker@dojo:~/asdf$ cd ~/asdf
hacker@dojo:~/asdf$ cd ~
hacker@dojo:~$ cd /home/hacker/asdf
hacker@dojo:~/asdf$
Note that the expansion of ~
is an absolute path, and only the leading ~
is expanded.
This means, for example, that ~/~
will be expanded to /home/hacker/~
rather than /home/hacker/home/hacker
.
Fun fact: cd
will use your home directory as the default destination:
hacker@dojo:~$ cd /tmp
hacker@dojo:/tmp$ cd
hacker@dojo:~$
Now it's your turn to play!
In this challenge, /challenge/run
will write a copy of the flag to any file you specify as an argument on the commandline, with these constraints:
- Your argument must be an absolute path.
- The path must be inside your home directory.
- Before expansion, your argument must be three characters or less.
Again, you must specify your path as an argument to /challenge/run
as so:
hacker@dojo:~$ /challenge/run YOUR_PATH_HERE
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Comprehending Commands
This module will expose you to some useful Linux commands that will serve you well for the rest of your journey here!
It is FAR from an exhaustive list, and we'll continue to expand this module, but this should be enough to get you started.
So, without further ado, let's learn some commands!
One of the most critical Linux commands is cat
.
cat
is most often used for reading out files, like so:
hacker@dojo:~$ cat /challenge/DESCRIPTION.md
One of the most critical Linux commands is `cat`.
`cat` is most often used for reading out files, like so:
cat
will concatenate (hence the name) multiple files if provided multiple arguments.
For example:
hacker@dojo:~$ cat myfile
This is my file!
hacker@dojo:~$ cat yourfile
This is your file!
hacker@dojo:~$ cat myfile yourfile
This is my file!
This is your file!
hacker@dojo:~$ cat myfile yourfile myfile
This is my file!
This is your file!
This is my file!
Finally, if you give no arguments at all, cat
will read from the terminal input and output it.
We'll explore that in later challenges...
In this challenge, I will copy the flag to the flag
file in your home directory (where your shell starts).
Go read it with cat
!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
In the last level, you did cat flag
to read the flag out of your home directory!
You can, of course, specify cat
's arguments as absolute paths:
hacker@dojo:~$ cat /challenge/DESCRIPTION.md
In the last level, you did `cat flag` to read the flag out of your home directory!
You can, of course, specify `cat`'s arguments as absolute paths:
...
In this directory, I will not copy it to your home directory, but I will make it readable.
You can read it with cat
at its absolute path: /flag
.
FUN FACT:
/flag
is where the flag always lives in pwn.college, but unlike in this challenge, you typically can't access that file directly.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
You can specify all sorts of paths as arguments to commands, and we'll practice some more with cat
.
In this level, I'll put the flag in some crazy directory, and I will not allow you to change directories with cd
, so no cat flag
for you.
You must retrieve the flag by absolute path, wherever it is.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Sometimes, the files that you might cat
out are too big.
Luckily, we have the grep
command to search for the contents we need!
We'll learn it in this challenge.
There are many ways to grep
, and we'll learn one way here:
hacker@dojo:~$ grep SEARCH_STRING /path/to/file
Invoked like this, grep
will search the file for lines of text containing SEARCH_STRING
and print them to the console.
In this challenge, I've put a hundred thousand lines of text into the /challenge/data.txt
file.
Grep it for the flag!
HINT: The flag always starts with the text pwn.college
.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
When looking for changes between similar files, eyeballing them might not be the most efficient approach!
This is where the diff
command becomes invaluable.
diff
compares two files line by line and shows you exactly what's different between them.
For example:
hacker@dojo:~$ cat file1
hello
world
hacker@dojo:~$ cat file2
hello
universe
hacker@dojo:~$ diff file1 file2
2c2
< world
---
> universe
The output tells us that line 2 changed (2c2
), with world
in the first file (<
) being replaced by universe
in the second file (>
).
Sometimes, when new lines are added, you'll see something like:
hacker@dojo:~$ cat old
pwn
hacker@dojo:~$ cat new
pwn
college
hacker@dojo:~$ diff old new
1a2
> college
This tells us that after line 1 in the first file, the second file has an additional line (1a2
means "after line 1 of file1, add line 2 of file2").
Now for your challenge!
There are two files in /challenge
:
/challenge/decoys_only.txt
contains 100 fake flags
/challenge/decoys_and_real.txt
contains all 100 fake flags plus the one real flag
Use diff
to find what's different between these files and get your flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
So far, we've told you which files to interact with.
But directories can have lots of files (and other directories) inside them, and we won't always be here to tell you their names.
You'll need to learn to list their contents using the ls
command!
ls
will list files in all the directories provided to it as arguments, and in the current directory if no arguments are provided.
Observe:
hacker@dojo:~$ ls /challenge
run
hacker@dojo:~$ ls
Desktop Downloads Pictures Templates
Documents Music Public Videos
hacker@dojo:~$ ls /home/hacker
Desktop Downloads Pictures Templates
Documents Music Public Videos
hacker@dojo:~$
In this challenge, we've named /challenge/run
with some random name!
List the files in /challenge
to find it.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Of course, you can also create files!
There are several ways to do this, but we'll look at a simple command here.
You can create a new, blank file by touching it with the touch
command:
hacker@dojo:~$ cd /tmp
hacker@dojo:/tmp$ ls
hacker@dojo:/tmp$ touch pwnfile
hacker@dojo:/tmp$ ls
pwnfile
hacker@dojo:/tmp$
It's that simple!
In this level, please create two files: /tmp/pwn
and /tmp/college
, and run /challenge/run
to get your flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Files are all around you.
Like candy wrappers, there'll eventually be too many of them.
In this level, we'll learn to clean up!
In Linux, you remove files with the rm
command, as so:
hacker@dojo:~$ touch PWN
hacker@dojo:~$ touch COLLEGE
hacker@dojo:~$ ls
COLLEGE PWN
hacker@dojo:~$ rm PWN
hacker@dojo:~$ ls
COLLEGE
hacker@dojo:~$
Let's practice.
This challenge will create a delete_me
file in your home directory!
Delete it, then run /challenge/check
, which will make sure you've deleted it and then give you the flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
You can also move files around with the mv
command.
The usage is simple:
hacker@dojo:~$ ls
my-file
hacker@dojo:~$ cat my-file
PWN!
hacker@dojo:~$ mv my-file your-file
hacker@dojo:~$ ls
your-file
hacker@dojo:~$ cat your-file
PWN!
hacker@dojo:~$
This challenge wants you to move the /flag
file into /tmp/hack-the-planet
(do it)!
When you're done, run /challenge/check
, which will check things out and give the flag to you.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Interestingly, ls
doesn't list all the files by default.
Linux has a convention where files that start with a .
don't show up by default in ls
and in a few other contexts.
To view them with ls
, you need to invoke ls
with the -a
flag, as so:
hacker@dojo:~$ touch pwn
hacker@dojo:~$ touch .college
hacker@dojo:~$ ls
pwn
hacker@dojo:~$ ls -a
.college pwn
hacker@dojo:~$
Now, it's your turn!
Go find the flag, hidden as a dot-prepended file in /
.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
With your knowledge of cd
, ls
, and cat
, we're ready to play a little game!
We'll start it out in /
.
Normally:
hacker@dojo:~$ cd /
hacker@dojo:/$ ls
bin challenge etc home lib32 libx32 mnt proc run srv tmp var
boot dev flag lib lib64 media opt root sbin sys usr
That's a lot of contents!
One day, you will be quite familiar with them, but already, you might recognize the flag
file and the challenge
directory.
In this challenge, I have hidden the flag!
Here, you will use ls
and cat
to follow my breadcrumbs and find it!
Here's how it'll work:
- Your first clue is in
/
. Head on over there.
- Look around with
ls
. There'll be a file named HINT or CLUE or something along those lines!
cat
that file to read the clue!
- Depending on what the clue says, head on over to the next directory (or don't!).
- Follow the clues to the flag!
Good luck!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
We can create files.
How about directories?
You make directories using the mkdir
command.
Then you can stick files in there!
Watch:
hacker@dojo:~$ cd /tmp
hacker@dojo:/tmp$ ls
hacker@dojo:/tmp$ ls
hacker@dojo:/tmp$ mkdir my_directory
hacker@dojo:/tmp$ ls
my_directory
hacker@dojo:/tmp$ cd my_directory
hacker@dojo:/tmp/my_directory$ touch my_file
hacker@dojo:/tmp/my_directory$ ls
my_file
hacker@dojo:/tmp/my_directory$ ls /tmp/my_directory/my_file
/tmp/my_directory/my_file
hacker@dojo:/tmp/my_directory$
Now, go forth and create a /tmp/pwn
directory and make a college
file in it!
Then run /challenge/run
, which will check your solution and give you the flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
So now we know how to list, read, and create files.
But how do we find them?
We use the find
command!
The find
command takes optional arguments describing the search criteria and the search location.
If you don't specify a search criteria, find
matches every file.
If you don't specify a search location, find
uses the current working directory (.
).
For example:
hacker@dojo:~$ mkdir my_directory
hacker@dojo:~$ mkdir my_directory/my_subdirectory
hacker@dojo:~$ touch my_directory/my_file
hacker@dojo:~$ touch my_directory/my_subdirectory/my_subfile
hacker@dojo:~$ find
.
./my_directory
./my_directory/my_subdirectory
./my_directory/my_subdirectory/my_subfile
./my_directory/my_file
hacker@dojo:~$
And when specifying the search location:
hacker@dojo:~$ find my_directory/my_subdirectory
my_directory/my_subdirectory
my_directory/my_subdirectory/my_subfile
hacker@dojo:~$
And, of course, we can specify the criteria!
For example, here, we filter by name:
hacker@dojo:~$ find -name my_subfile
./my_directory/my_subdirectory/my_subfile
hacker@dojo:~$ find -name my_subdirectory
./my_directory/my_subdirectory
hacker@dojo:~$
You can search the whole filesystem if you want!
hacker@dojo:~$ find / -name hacker
/home/hacker
hacker@dojo:~$
Now it's your turn.
I've hidden the flag in a random directory on the filesystem.
It's still called flag
.
Go find it!
Several notes. First, there are other files named flag
on the filesystem.
Don't panic if the first one you try doesn't have the actual flag in it.
Second, there're plenty of places in the filesystem that are not accessible to a normal user.
These will cause find
to generate errors, but you can ignore those; we won't hide the flag there!
Finally, find
can take a while; be patient!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
If you use Linux (or computers) for any reasonable length of time to do any real work, you will eventually run into some variant of the following situation: you want two programs to access the same data, but the programs expect that data to be in two different locations.
Luckily, Linux provides a solution to this quandary: links.
Links come in two flavors: hard and soft (also known as symbolic) links.
We'll differentiate the two with an analogy:
- A hard link is when you address your apartment using multiple addresses that all lead directly to the same place (e.g.,
Apt 2
vs Unit 2
).
- A soft link is when you move apartments and have the postal service automatically forward your mail from your old place to your new place.
In a filesystem, a file is, conceptually, an address at which the contents of that file live.
A hard link is an alternate address that indexes that data --- accesses to the hard link and accesses to the original file are completely identical, in that they immediately yield the necessary data.
A soft/symbolic link, instead, contains the original file name.
When you access the symbolic link, Linux will realize that it is a symbolic link, read the original file name, and then (typically) automatically access that file.
In most cases, both situations result in accessing the original data, but the mechanisms are different.
Hard links sound simpler to most people (case in point, I explained it in one sentence above, versus two for soft links), but they have various downsides and implementation gotchas that make soft/symbolic links, by far, the more popular alternative.
In this challenge, we will learn about symbolic links (also known as symlinks).
Symbolic links are created with the ln
command with the -s
argument, like so:
hacker@dojo:~$ cat /tmp/myfile
This is my file!
hacker@dojo:~$ ln -s /tmp/myfile /home/hacker/ourfile
hacker@dojo:~$ cat ~/ourfile
This is my file!
hacker@dojo:~$
You can see that accessing the symlink results in getting the original file contents!
Also, you can see the usage of ln -s
.
Note that the original file path comes before the link path in the command!
A symlink can be identified as such with a few methods.
For example, the file
command, which takes a filename and tells you what type of file it is, will recognize symlinks:
hacker@dojo:~$ file /tmp/myfile
/tmp/myfile: ASCII text
hacker@dojo:~$ file ~/ourfile
/home/hacker/ourfile: symbolic link to /tmp/myfile
hacker@dojo:~$
Okay, now you try it!
In this level the flag is, as always, in /flag
, but /challenge/catflag
will instead read out /home/hacker/not-the-flag
.
Use the symlink, and fool it into giving you the flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Digesting Documentation
This module will teach you one of the most important Linux skills: looking for help on how to use programs.
This skill will serve you quite well in your journey.
Dive in below!
The typical need you'll have for documentation is just to figure out how to use all these dang programs, and a specific case of that is figuring out what arguments to specify on the command line.
This module will mostly dig into that concept, as a proxy for figuring out how to use the programs in general.
Through the rest of the module, you'll go through various ways of asking the environment for help for the programs, but first, we'll dig into the concept of reading documentation.
The correct usage of programs depends, in a large part, in the proper specification of arguments to them.
Recall the -a
of ls -a
in the hidden files
challenge of the Basic Commands module: that -a
was an argument that told ls
to list out hidden files as well as non-hidden files.
Because we wanted to list out hidden files, invoking ls
with the -a
argument was the correct way to use it in our scenario.
The program for this challenge is /challenge/challenge
, and you'll need to invoke it properly in order for it to give you the flag.
Let's pretend that this is its documentation:
Welcome to the documentation for /challenge/challenge
! To properly run this program, you will need to pass it the argument of --giveflag
. Good luck!
Given that knowledge, go get the flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
While using most commands is straightforward, the usage of some commands can get quite complex.
For example, the arguments to commands like sed
and awk
, which we're definitely not getting into right now, are entire programs in an esoteric programming language!
Somewhere on the spectrum between cd
and awk
are commands that take arguments to their arguments...
This sounds crazy, but you've already encountered this with the find
level in Basic Commands.
find
has a -name
argument, and the -name
argument itself takes an argument specifying the name to search for.
Many other commands are analogous.
Here is this level's documentation for /challenge/challenge
:
Welcome to the documentation for /challenge/challenge
! This program allows you to print arbitrary files to the terminal, when given the --printfile
argument. The argument to the --printfile
argument is the path of the flag to read. For example, /challenge/challenge --printfile /challenge/DESCRIPTION.md
will print out the description of the level!
Given that documentation, go get the flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
This level introduces the man
command.
man
is short for manual
, and will display (if available) the manual of the command you pass as an argument.
For example, let's say we wanted to learn about the yes
command (yes, this is a real command):
hacker@dojo:~$ man yes
This will display the manual page for yes
, which will look something like this:
YES(1) User Commands YES(1)
NAME
yes - output a string repeatedly until killed
SYNOPSIS
yes [STRING]...
yes OPTION
DESCRIPTION
Repeatedly output a line with all specified STRING(s), or 'y'.
--help display this help and exit
--version
output version information and exit
AUTHOR
Written by David MacKenzie.
REPORTING BUGS
GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
Report any translation bugs to <https://translationproject.org/team/>
COPYRIGHT
Copyright © 2020 Free Software Foundation, Inc. License GPLv3+: GNU
GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
SEE ALSO
Full documentation <https://www.gnu.org/software/coreutils/yes>
or available locally via: info '(coreutils) yes invocation'
GNU coreutils 8.32 February 2022 YES(1)
The important sections are:
NAME(1) CATEGORY NAME(1)
NAME
This gives the name (and short description) of the command or
concept discussed by the page.
SYNOPSIS
This gives a short usage synopsis. These synopses have a standard
format. Typically, each line is a different valid invocation of the
command, and the lines can be read as:
COMMAND [OPTIONAL_ARGUMENT] SINGLE_MANDATORY_ARGUMENT
COMMAND [OPTIONAL_ARGUMENT] MULTIPLE_ARGUMENTS...
DESCRIPTION
Details of the command or concept, with detailed descriptions
of the various options.
SEE ALSO
Other man pages or online resources that might be useful.
COLLECTION DATE NAME(1)
You can scroll around the manpage with your arrow keys and PgUp/PgDn.
When you're done reading the manpage, you can hit q
to quit.
Manpages are stored in a centralized database.
If you're curious, this database lives in the /usr/share/man
directory, but you never need to interact with it directly: you just query it using the man
command.
The arguments to the man
command aren't file paths, but just the names of the entries themselves (e.g., you run man yes
to look up the yes
manpage, rather than man /usr/bin/yes
, which would be the actual path to the yes
program but would result in man
displaying garbage).
The challenge in this level has a secret option that, when you use it, will cause the challenge to print the flag.
You must learn this option through the man page for challenge
!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
You can scroll man pages with the arrow keys (and PgUp/PgDn) and search with /
.
After searching, you can hit n
to go to the next result and N
to go to the previous result.
Instead of /
, you can use ?
to search backwards!
Find the option that will give you the flag by reading the challenge
man page.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
This level is tricky: it hides the manpage for the challenge by randomizing its name.
Luckily, all of the man pages are gathered in a searchable database, so you'll be able to search the man page database to find the hidden challenge man page!
To figure out how to search for the right man page, read the man
page manpage by doing: man man
!
HINT 1: man man
teaches you advanced usage of the man
command itself, and you must use this knowledge to figure out how to search for the hidden manpage that will tell you how to use /challenge/challenge
HINT 2: though the man page is randomly named, you still actually use /challenge/challenge
to get the flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Some programs don't have a man page, but might tell you how to run them if invoked with a special argument.
Usually, this argument is --help
, but it can often be -h
or, in rare cases, -?
, help
, or other esoteric values like /?
(though that latter is more frequently encountered on Windows).
In this level, you will practice reading a program's documentation with --help
.
Try it out!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Some commands, rather than being programs with man pages and help options, are built into the shell itself.
These are called builtins.
Builtins are invoked just like commands, but the shell handles them internally instead of launching other programs.
You can get a list of shell builtins by running the builtin help
, as so:
hacker@dojo:~$ help
You can get help on a specific one by passing it to the help
builtin.
Let's look at a builtin that we've already used earlier, cd
!
hacker@dojo:~$ help cd
cd: cd [-L|[-P [-e]] [-@]] [dir]
Change the shell working directory.
Change the current directory to DIR. The default DIR is the value of the
HOME shell variable.
...
Some good information!
In this challenge, we'll practice using help
to look up help for builtins.
This challenge's challenge
command is a shell builtin, rather than a program.
Like before, you need to lookup its help to figure out the secret value to pass to it!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
File Globbing
Even just a few levels in, you might already be tired of typing out all these file paths.
Luckily, the shell has a solution: globbing!
That's what we'll learn in this module.
Before executing commands that you enter, the shell first performs expansions on them, and one of these expansions is globbing.
Globbing lets you reference files without typing them all out, or typing out their full paths.
Let's dig in!
The first glob we'll learn is *
.
When it encounters a *
character in any argument, the shell will treat it as "wildcard" and try to replace that argument with any files that match the pattern.
It's easier to show you than explain:
hacker@dojo:~$ touch file_a
hacker@dojo:~$ touch file_b
hacker@dojo:~$ touch file_c
hacker@dojo:~$ ls
file_a file_b file_c
hacker@dojo:~$ echo Look: file_*
Look: file_a file_b file_c
Of course, though in this case, the glob resulted in multiple arguments, it can just as simply match only one.
For example:
hacker@dojo:~$ touch file_a
hacker@dojo:~$ ls
file_a
hacker@dojo:~$ echo Look: file_*
Look: file_a
When zero files are matched, by default, the shell leaves the glob unchanged:
hacker@dojo:~$ touch file_a
hacker@dojo:~$ ls
file_a
hacker@dojo:~$ echo Look: nope_*
Look: nope_*
The *
matches any part of the filename except for /
or a leading .
character.
For example:
hacker@dojo:~$ echo ONE: /ho*/*ck*
ONE: /home/hacker
hacker@dojo:~$ echo TWO: /*/hacker
TWO: /home/hacker
hacker@dojo:~$ echo THREE: ../*
THREE: ../hacker
Now, practice this yourself!
Starting from your home directory, change your directory to /challenge
, but use globbing to keep the argument you pass to cd
to at most four characters!
Once you're there, run /challenge/run
for the flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Next, let's learn about ?
.
When it encounters a ?
character in any argument, the shell will treat it as a single-character wildcard.
This works like *
, but only matches one character.
For example:
hacker@dojo:~$ touch file_a
hacker@dojo:~$ touch file_b
hacker@dojo:~$ touch file_cc
hacker@dojo:~$ ls
file_a file_b file_cc
hacker@dojo:~$ echo Look: file_?
Look: file_a file_b
hacker@dojo:~$ echo Look: file_??
Look: file_cc
Now, practice this yourself!
Starting from your home directory, change your directory to /challenge
, but use the ?
character instead of c
and l
in the argument to cd
!
Once you're there, run /challenge/run
for the flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Next, we will cover []
.
The square brackets are, essentially, a limited form of ?
, in that instead of matching any character, []
is a wildcard for some subset of potential characters, specified within the brackets.
For example, [pwn]
will match the character p
, w
, or n
.
For example:
hacker@dojo:~$ touch file_a
hacker@dojo:~$ touch file_b
hacker@dojo:~$ touch file_c
hacker@dojo:~$ ls
file_a file_b file_c
hacker@dojo:~$ echo Look: file_[ab]
Look: file_a file_b
Try it here!
We've placed a bunch of files in /challenge/files
.
Change your working directory to /challenge/files
and run /challenge/run
with a single argument that bracket-globs into file_b
, file_a
, file_s
, and file_h
!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Globbing happens on a path basis, so you can expand entire paths with your globbed arguments.
For example:
hacker@dojo:~$ touch file_a
hacker@dojo:~$ touch file_b
hacker@dojo:~$ touch file_c
hacker@dojo:~$ ls
file_a file_b file_c
hacker@dojo:~$ echo Look: /home/hacker/file_[ab]
Look: /home/hacker/file_a /home/hacker/file_b
Now it's your turn.
Once more, we've placed a bunch of files in /challenge/files
.
Starting from your home directory, run /challenge/run
with a single argument that bracket-globs into the absolute paths to the file_b
, file_a
, file_s
, and file_h
files!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
So far, you've specified one glob at a time, but you can do more!
Bash supports the expansion of multiple globs in a single word.
For example:
hacker@dojo:~$ cat /*fl*
pwn.college{YEAH}
hacker@dojo:~$
What happens above is that the shell looks for all files in /
that start with anything (including nothing), then have an f
and an l
, and end in anything (including ag
, which makes flag
).
Now you try it.
We put a few happy, but diversely-named files in /challenge/files
.
Go cd
there and run /challenge/run
, providing a single argument: a short (3 characters or less) globbed word with two *
globs in it that covers every word that contains the letter p
.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Now, let's put the previous levels together!
We put a few happy, but diversely-named files in /challenge/files
.
Go cd
there and, using the globbing you've learned, write a single, short (6 characters or less) glob that (when passed as an argument to /challenge/run
) will match the files "challenging", "educational", and "pwning"!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Sometimes, you want to filter out files in a glob!
Luckily, []
helps you do just this.
If the first character in the brackets is a !
or (in newer versions of bash) a ^
, the glob inverts, and that bracket instance matches characters that aren't listed.
For example:
hacker@dojo:~$ touch file_a
hacker@dojo:~$ touch file_b
hacker@dojo:~$ touch file_c
hacker@dojo:~$ ls
file_a file_b file_c
hacker@dojo:~$ echo Look: file_[!ab]
Look: file_c
hacker@dojo:~$ echo Look: file_[^ab]
Look: file_c
hacker@dojo:~$ echo Look: file_[ab]
Look: file_a file_b
Armed with this knowledge, go forth to /challenge/files
and run /challenge/run
with all files that don't start with p
, w
, or n
!
NOTE: The !
character has a different special meaning in bash when it's not the first character of a []
glob, so keep that in mind if things stop making sense! ^
does not have this problem, but is also not compatible with older shells.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
As tempting as it might be, using *
to shorten what must be typed on the commandline can lead to mistakes.
Your glob might expand to unintended files, and you might not spot it until the rm
command is already running!
No one is safe from this style of error.
A safer alternative when you are trying to specify a specific target is tab completion.
If you hit tab in the shell, it'll try to figure out what you're going to type and automatically complete it.
Auto-completion is super useful, and this challenge will explore its use in specifying files.
This challenge has copied the flag into /challenge/pwncollege
, and you can freely cat
that file.
But you can't type the filename: we used some serious trickery to make sure that you must tab-complete it.
Try it out!
hacker@dojo:~$ ls /challenge
DESCRIPTION.md pwncollege
hacker@dojo:~$ cat /challenge/pwncollege
cat: /challenge/pwncollege: No such file or directory
hacker@dojo:~$ cat /challenge/pwn<TAB>
pwn.college{HECK YEAH}
hacker@dojo:~$
When you hit that tab key, the name will expand and you'll be able to read the file.
Good luck!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Consider the following situation:
hacker@dojo:~$ ls
flag flamingo flowers
hacker@dojo:~$ cat f<TAB>
There are multiple options!
What happens?
What happens varies based on the specific shell and its options.
By default bash
will auto-expand until the first point when there are multiple options (in this case, fl
).
When you hit tab a second time, it'll print out those options.
Other shells and configurations, instead, will cycle through the options.
This challenge has a /challenge/files
directory with a bunch of files starting with pwncollege
.
Tab-complete from /challenge/files/p
or so, and make your way to the flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Tab completion is for more than files!
You can also tab-complete commands.
This level has a command that starts with pwncollege
, and it'll give you the flag.
Type pwncollege
and hit the tab key to auto-complete it!
NOTE:
You can auto-complete any command, but be careful: callous auto-completes without double-checking the result can wreak havoc in your shell if you accidentally run the wrong commands!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Practicing Piping
You may have observed that some commands output data onto your terminal when you run them.
So far, this has printed you many flags, but like many things, the technology goes much deeper.
The mechanisms behind the handling of input and output on the commandline contribute to the commandline's power.
This module will teach you about input and output redirection.
Simply put, every process in Linux has three initial, standard channels of communication:
- Standard Input is the channel through which the process takes input. For example, your shell uses Standard Input to read the commands that you input.
- Standard Output is the channel through which processes output normal data, such as the flag when it is printed to you in previous challenges or the output of utilities such as
ls
.
- Standard Error is the channel through which processes output error details. For example, if you mistype a command, the shell will output, over standard error, that this command does not exist.
Because these three channels are used so frequently in Linux, they are known by shorter names: stdin
, stdout
, stderr
.
This module will teach you how to redirect, chain, block, and otherwise mess with these channels.
Good luck!
First, let's look at redirecting stdout to files.
You can accomplish this with the >
character, as so:
hacker@dojo:~$ echo hi > asdf
This will redirect the output of echo hi
(which will be hi
) to the file asdf
.
You can then use a program such as cat
to output this file:
hacker@dojo:~$ cat asdf
hi
In this challenge, you must use this input redirection to write the word PWN
(all uppercase) to the filename COLLEGE
(all uppercase).
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Aside from redirecting the output of echo
, you can, of course, redirect the output of any command.
In this level, /challenge/run
will once more give you a flag, but only if you redirect its output to the file myflag
.
Your flag will, of course, end up in the myflag
file!
You'll notice that /challenge/run
will still happily print to your terminal, despite you redirecting stdout.
That's because it communicates its instructions and feedback over standard error, and only prints the flag over standard out!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
A common use-case of output redirection is to save off some command results for later analysis.
Often times, you want to do this in aggregate: run a bunch of commands, save their output, and grep through it later.
In this case, you might want all that output to keep appending to the same file, but >
will create a new output file every time, deleting the old contents.
You can redirect input in append mode using >>
instead of >
, as so:
hacker@dojo:~$ echo pwn > outfile
hacker@dojo:~$ echo college >> outfile
hacker@dojo:~$ cat outfile
pwn
college
hacker@dojo:$
To practice, run /challenge/run
with an append-mode redirect of the output to the file /home/hacker/the-flag
.
The practice will write the first half of the flag to the file, and the second half to stdout
if stdout
is redirected to the file.
If you properly redirect in append-mode, the second half will be appended to the first, but if you redirect in truncation mode (>
), the second half will overwrite the first and you won't get the flag!
Go for it now!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Just like standard output, you can also redirect the error channel of commands.
Here, we'll learn about File Descriptor numbers.
A File Descriptor (FD) is a number that describes a communication channel in Linux.
You've already been using them, even though you didn't realize it.
We're already familiar with three:
- FD 0: Standard Input
- FD 1: Standard Output
- FD 2: Standard Error
When you redirect process communication, you do it by FD number, though some FD numbers are implicit.
For example, a >
without a number implies 1>
, which redirects FD 1 (Standard Output).
Thus, the following two commands are equivalent:
hacker@dojo:~$ echo hi > asdf
hacker@dojo:~$ echo hi 1> asdf
Redirecting errors is pretty easy from this point.
If you have a command that might produce data via standard error (such as /challenge/run
), you can do:
hacker@dojo:~$ /challenge/run 2> errors.log
That will redirect standard error (FD 2) to the errors.log
file.
Furthermore, you can redirect multiple file descriptors at the same time!
For example:
hacker@dojo:~$ some_command > output.log 2> errors.log
That command will redirect output to output.log
and errors to errors.log
.
Let's put this into practice!
In this challenge, you will need to redirect the output of /challenge/run
, like before, to myflag
, and the "errors" (in our case, the instructions) to instructions
.
You'll notice that nothing will be printed to the terminal, because you have redirected everything!
You can find the instructions/feedback in instructions
and the flag in myflag
when you successfully pull this off!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Just like you can redirect output from programs, you can redirect input to programs!
This is done using <
, as so:
hacker@dojo:~$ echo yo > message
hacker@dojo:~$ cat message
yo
hacker@dojo:~$ rev < message
oy
You can do interesting things with a lot of different programs using input redirection!
In this level, we will practice using /challenge/run
, which will require you to redirect the PWN
file to it and have the PWN
file contain the value COLLEGE
!
To write that value to the PWN
file, recall the prior challenge on output redirection from echo
!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
You know how to run commands, how to redirect their output (e.g., >
), and how to search through the resulting file (e.g., grep
).
Let's put this together!
In preparation for more complex levels, we want you to:
- Redirect the output of
/challenge/run
to /tmp/data.txt
.
- This will result in a hundred thousand lines of text, with one of them being the flag, in
/tmp/data.txt
.
- Grep that for the flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
It turns out that you can "cut out the middleman" and avoid the need to store results to a file, like you did in the last level.
You can do this by using the |
(pipe) operator.
Standard output from the command to the left of the pipe will be connected to (piped into) the standard input of the command to the right of the pipe.
For example:
hacker@dojo:~$ echo no-no | grep yes
hacker@dojo:~$ echo yes-yes | grep yes
yes-yes
hacker@dojo:~$ echo yes-yes | grep no
hacker@dojo:~$ echo no-no | grep no
no-no
Now try it for yourself! /challenge/run
will output a hundred thousand lines of text, including the flag.
Grep for the flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
You know how to redirect errors to a file, and you know how to pipe output to another program, such as grep.
But what if you wanted to grep through errors directly?
The >
operator redirects a given file descriptor to a file, and you've used 2>
to redirect fd 2, which is standard error.
The |
operator redirects only standard output to another program, and there is no 2|
form of the operator!
It can only redirect standard output (file descriptor 1).
Luckily, where there's a shell, there's a way!
The shell has a >&
operator, which redirects a file descriptor to another file descriptor.
This means that we can have a two-step process to grep through errors: first, we redirect standard error to standard output (2>& 1
) and then pipe the now-combined stderr and stdout as normal (|
)!
Try it now!
Like the last level, this level will overwhelm you with output, but this time on standard error.
Grep through it to find the flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
The grep
command has a very useful option: -v
(invert match).
While normal grep
shows lines that MATCH a pattern, grep -v
shows lines that do NOT match a pattern:
hacker@dojo:~$ cat data.txt
hello hackers!
hello world!
hacker@dojo:~$ cat data.txt | grep -v world
hello hackers!
hacker@dojo:~$
Sometimes, the only way to filter to just the data you want is to filter out the data you don't want.
In this challenge, /challenge/run
will output the flag to stdout, but it will also output over 1000 decoy flags (containing the word DECOY
somehwere in the flag) mixed in with the real flag.
You'll need to filter out the decoys while keeping the real flag!
Use grep -v
to filter out all the lines containing "DECOY" and reveal the real flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
When you pipe data from one command to another, you of course no longer see it on your screen.
This is not always desired: for example, you might want to see the data as it flows through between your commands to debug unintended outcomes (e.g., "why did that second command not work???").
Luckily, there is a solution!
The tee
command, named after a "T-splitter" from plumbing pipes, duplicates data flowing through your pipes to any number of files provided on the command line.
For example:
hacker@dojo:~$ echo hi | tee pwn college
hi
hacker@dojo:~$ cat pwn
hi
hacker@dojo:~$ cat college
hi
hacker@dojo:~$
As you can see, by providing two files to tee
, we ended up with three copies of the piped-in data: one to stdout, one to the pwn
file, and one to the college
file.
You can imagine how you might use this to debug things going haywire:
hacker@dojo:~$ command_1 | command_2
Command 2 failed!
hacker@dojo:~$ command_1 | tee cmd1_output | command_2
Command 2 failed!
hacker@dojo:~$ cat cmd1_output
Command 1 failed: must pass --succeed!
hacker@dojo:~$ command_1 --succeed | command_2
Commands succeeded!
Now, you try it!
This process' /challenge/pwn
must be piped into /challenge/college
, but you'll need to intercept the data to see what pwn
needs from you!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Sometimes you need to compare the output of two commands rather than two files.
You might think to save each output to a file first:
hacker@dojo:~$ command1 > file1
hacker@dojo:~$ command2 > file2
hacker@dojo:~$ diff file1 file2
But there's a more elegant way! Linux follows the philosophy that "everything is a file".
That is, the system strives to provide file-like access to most resources, including the input and output of running programs!
The shell follows this philosophy, allowing you to, for example, use any utility that takes file arguments on the command line and hook it up to the output of programs, as you learned in the previous few levels.
Interestingly, we can go further, and hook input and output of programs to arguments of commands.
This is done using Process Substitution.
For reading from a command (input process substitution), use <(command)
.
When you write <(command)
, bash will run the command and hook up its output to a temporary file that it will create.
This isn't a real file, of course, it's what's called a named pipe, in that it has a file name:
hacker@dojo:~$ echo <(echo hi)
/dev/fd/63
hacker@dojo:~$
Where did /dev/fd/63
come from?
bash
replaced <(echo hi)
with the path of the named pipe file that's hooked up to the command's output!
While the command is running, reading from this file will read data from the standard output of the command.
Typically, this is done using commands that take input files as arguments:
hacker@dojo:~$ cat <(echo hi)
hi
hacker@dojo:~$
Of course, you can specify this multiple time:
hacker@dojo:~$ echo <(echo pwn) <(echo college)
/dev/fd/63 /dev/fd/64
hacker@dojo:~$ cat <(echo pwn) <(echo college)
pwn
college
hacker@dojo:~$
Now for your challenge!
Recall what you learned in the diff
challenge from Comprehending Commands.
In that challenge, you diffed two files.
Now, you'll diff two sets of command outputs: /challenge/print_decoys
, which will print a bunch of decoy flags, and /challenge/print_decoys_and_flag
which will print those same decoys plus the real flag.
Use process substitution with diff
to compare the outputs of these two programs and find your flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Now you've learned that process substitution can make command output appear as files for reading with <(command)
.
But you can also use process substitution for writing to commands!
You can duplicate data to two files with tee
:
hacker@dojo:~$ echo HACK | tee THE > PLANET
hacker@dojo:~$ cat THE
HACK
hacker@dojo:~$ cat PLANET
HACK
hacker@dojo:~$
And you've used tee
to duplicate data to a file and a command:
hacker@dojo:~$ echo HACK | tee THE | cat
HACK
hacker@dojo:~$ cat THE
HACK
hacker@dojo:~$
But what about duplicating to two commands?
As tee
says in its manpage, it's designed to write to files and to standard output:
TEE(1) User Commands TEE(1)
NAME
tee - read from standard input and write to standard output and files
But wait! You just learned that bash can make commands look like files using process substitution!
For writing to a command (output process substitution), use >(command)
.
If you write an argument of >(rev)
, bash will run the rev
command (this command reads data from standard input, reverses its order, and writes it to standard output!), but hook up its input to a temporary named pipe file.
When commands write to this file, the data goes to the standard input of the command:
hacker@dojo:~$ echo HACK | rev
KCAH
hacker@dojo:~$ echo HACK | tee >(rev)
HACK
KCAH
Above, the following sequence of events took place:
bash
started up the rev
command, hooking a named pipe (presumably /dev/fd/63
) to rev
's standard input
bash
started up the tee
command, hooking a pipe to its standard input, and replacing the first argument to tee
with /dev/fd/63
. tee
never even saw the argument >(rev)
; the shell substituted it before launching tee
bash
used the echo
builtin to print HACK
into tee
's standard input
tee
read HACK
, wrote it to standard output, and then wrote it to /dev/fd/63
(which is connected to rev
's stdin)
rev
read HACK
from its standard input, reversed it, and wrote KCAH
to standard output
Now it's your turn!
In this challenge, we have /challenge/hack
, /challenge/the
, and /challenge/planet
.
Run the /challenge/hack
command, and duplicate its output as input to both the /challenge/the
and the /challenge/planet
commands!
Scroll back through the previous challenges "Duplicating piped data with tee" and "Process substitution for input" if you need a refresher on this method.
Trivia!
The observant learner will realize that the following are equivalent:
hacker@dojo:~$ echo hi | rev
ih
hacker@dojo:~$ echo hi > >(rev)
ih
hacker@dojo:~$
More than one way to pipe data!
Of course, the second route is way harder to read and also harder to expand.
For example:
hacker@dojo:~$ echo hi | rev | rev
hi
hacker@dojo:~$ echo hi > >(rev | rev)
hi
hacker@dojo:~$
That's just silly!
The lesson here is that, while Process Substitution is a powerful tool in your toolbox, it's a very specialized tool; don't use it for everything!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Now, let's put your knowledge together.
You must master the ultimate piping task: redirect stdout to one program and stderr to another.
The challenge here, of course, is that the |
operator links the stdout of the left command with the stdin of the right command.
Of course, you've used 2>&1
to redirect stderr into stdout and, thus, pipe stderr over, but this then mixes stderr and stdout.
How to keep it unmixed?
You will need to combine your knowledge of >()
, 2>
, and |
.
How to do it is a task I'll leave to you.
In this challenge, you have:
/challenge/hack
: this produces data on stdout and stderr
/challenge/the
: you must redirect hack
's stderr to this program
/challenge/planet
: you must redirect hack
's stdout to this program
Go get the flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
You've learned about pipes using |
, and you've seen that process substitution creates temporary named pipes (like /dev/fd/63
).
You can also create your own persistent named pipes that stick around on the filesystem!
These are called FIFOs, which stands for First (byte) In, First (byte) Out.
You create a FIFO using the mkfifo
command:
hacker@dojo:~$ mkfifo my_pipe
hacker@dojo:~$ ls -l my_pipe
prw-r--r-- 1 hacker hacker 0 Jan 1 12:00 my_pipe
-rw-r--r-- 1 hacker hacker 0 Jan 1 12:00 some_file
hacker@dojo:~$
Notice the p
at the beginning of the permissions - that indicates it's a pipe!
That's markedly different than the -
that's at the beginning of normal files, such as some_file
in the above example.
Unlike the automatic named pipes from process substitution:
- You control where FIFOs are created
- They persist until you delete them
- Any process can write to them by path (e.g.,
echo hi > my_pipe
)
- You can see them with
ls
and examine them like files
One problem with FIFOs is that they'll "block" any operations on them until both the read side of the pipe and the write side of the pipe are ready.
For example, consider this:
hacker@dojo:~$ mkfifo myfifo
hacker@dojo:~$ echo pwn > myfifo
To service echo pwn > myfifo
, bash will open the myfifo
file in write mode.
However, this operation will hang until something also opens the file in read mode (thus completing the pipe).
That can be in a different console:
hacker@dojo:~$ cat myfifo
pwn
hacker@dojo:~$
What happened here?
When we ran cat myfifo
, the pipe had both sides of the connection all set, and unblocked, allowing echo pwn > myfifo
to run, which sent pwn
into the pipe, where it was read by cat
.
Of course, this can somewhat be done by normal files: you've learned how to echo
stuff into them and cat
them out.
Why use a FIFO instead?
Here are key differences:
- No disk storage: FIFOs pass data directly between processes in memory - nothing is saved to disk
- Ephemeral data: Once data is read from a FIFO, it's gone (unlike files where data persists)
- Automatic synchronization: Writers block until the readers are ready, and vice-versa. This is actually useful! It provides automatic synchronization. Consider the example above: with a FIFO, it doesn't matter if
cat myfifo
or echo pwn > myfifo
is executed first; each would just wait for the other. With files, you need to make sure to execute the writer before the reader.
- Complex data flows: FIFOs are useful for facilitating complex data flows, merging and splitting data in flexible ways, and so on. For example, FIFOs support multiple readers and writers.
This challenge will be a simple introduction to FIFOs.
You'll need to create a /tmp/flag_fifo
file and redirect the stdout of /challenge/run
to it.
If you're successful, /challenge/run
will write the flag into the fifo!
Go do it!
HINT:
The blocking behavior of FIFOs makes it hard to solve this challenge in a single terminal.
You may want to use the Desktop or VSCode mode for this challenge so that you can launch two terminals.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Shell Variables
The Linux command line interface is actually a sophisticated programming language with which you can write actual programs!
Because the command line interface is colloquially referred to as a "shell", programs written in this language are referred to as "shell scripts".
When you're using the command line, you are basically writing a shell script line by line!
Like most programming languages, the shell supports variables.
This module will get you familiar with setting, printing, and using these variables!
Let's start with printing variables out.
The /challenge/run
program will not, and cannot, give you the flag, but that's okay, because the flag has been put into the variable called "FLAG"!
Just have your shell print it out!
You can accomplish this using a number of ways, but we'll start with echo
.
This command just prints stuff.
For example:
hacker@dojo:~$ echo Hello Hackers!
Hello Hackers!
You can also print out variables with echo
, by prepending the variable name with a $
.
For example, there is a variable, PWD
, that always holds the current working directory of the current shell.
You print it out as so:
hacker@dojo:~$ echo $PWD
/home/hacker
Now it's your turn.
Have your shell print out the FLAG
variable and solve this challenge!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Naturally, as well as reading values stored in variables, you can write values to variables.
This is done, as with many other languages, using =
.
To set variable VAR
to value 1337
, you would use:
hacker@dojo:~$ VAR=1337
Note that there are no spaces around the =
!
If you put spaces (e.g., VAR = 1337
), the shell won't recognize a variable assignment and will, instead, try to run the VAR
command (which does not exist).
Also note that this uses VAR
and not $VAR
: the $
is only prepended to access variables.
In shell terms, this prepending of $
triggers what is called variable expansion, and is, surprisingly, the source of many potential vulnerabilities (if you're interested in that, check out the Art of the Shell dojo when you get comfortable with the command line!).
After setting variables, you can access them using the techniques you've learned previously, such as:
hacker@dojo:~$ echo $VAR
1337
To solve this level, you must set the PWN
variable to the value COLLEGE
.
Be careful: both the names and values of variables are case-sensitive!
PWN
is not the same as pwn
and COLLEGE
is not the same as College
.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
In this level, you will learn about quoting.
Spaces have special significance in the shell, and there are places where you can't use them spuriously.
Recall our variable setting:
hacker@dojo:~$ VAR=1337
That sets the VAR
variable to 1337
, but what if you wanted to set it to 1337 SAUCE
?
You might try the following:
hacker@dojo:~$ VAR=1337 SAUCE
This looks reasonable, but it does not work, for similar reasons to needing to have no spaces around the =
.
When the shell sees a space, it ends the variable assignment and interprets the next word (SAUCE
in this case) as a command.
To set VAR
to 1337 SAUCE
, you need to quote it:
hacker@dojo:~$ VAR="1337 SAUCE"
Here, the shell reads 1337 SAUCE
as a single token, and happily sets that value to VAR
.
In this level, you'll need to set the variable PWN
to COLLEGE YEAH
.
Good luck!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
By default, variables that you set in a shell session are local to that shell process.
That is, other commands you run won't inherit them.
You can experiment with this by simply invoking another shell process in your own shell, like so:
hacker@dojo:~$ VAR=1337
hacker@dojo:~$ echo "VAR is: $VAR"
VAR is: 1337
hacker@dojo:~$ sh
$ echo "VAR is: $VAR"
VAR is:
In the output above, the $
prompt is the prompt of sh
, a minimal shell implementation that invoked as a child of the main shell process.
And it does not receive the VAR
variable!
This makes sense, of course.
Your shell variables might have sensitive or weird data, and you don't want it leaking to other programs you run unless it explicitly should.
How do you mark that it should?
You export your variables.
When you export your variables, they are passed into the environment variables of child processes.
You'll encounter the concept of environment variables in other challenges, but you'll observe their effects here.
Here is an example:
hacker@dojo:~$ VAR=1337
hacker@dojo:~$ export VAR
hacker@dojo:~$ sh
$ echo "VAR is: $VAR"
VAR is: 1337
Here, the child shell received the value of VAR and was able to print it out!
You can also combine those first two lines.
hacker@dojo:~$ export VAR=1337
hacker@dojo:~$ sh
$ echo "VAR is: $VAR"
VAR is: 1337
In this challenge, you must invoke /challenge/run
with the PWN
variable exported and set to the value COLLEGE
, and the COLLEGE
variable set to the value PWN
but not exported (e.g., not inherited by /challenge/run
).
Good luck!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
There are multiple ways to access variables in bash.
echo
was just one of them, and we'll now learn at least one more in this challenge.
Try the env
command: it'll print out every exported variable set in your shell, and you can look through that output to find the FLAG
variable!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
In the course of working with the shell, you will often want to store the output of some command into a variable.
Luckily, the shell makes this quite easy using something called Command Substitution!
Observe:
hacker@dojo:~$ FLAG=$(cat /flag)
hacker@dojo:~$ echo "$FLAG"
pwn.college{blahblahblah}
hacker@dojo:~$
Neat!
Now, you practice.
Read the output of the /challenge/run
command directly into a variable called PWN
, and it will contain the flag!
Trivia:
You can also use backticks instead of $()
: FLAG=`cat /flag`
instead of FLAG=$(cat /flag)
in the example above.
This is an older format, and has some disadvantages (for example, imagine if you wanted to nest command substitutions.
How would you do $(cat $(find / -name flag))
with backticks?
The official stance of pwn.college is that you should use $(blah)
instead of `blah`
.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
We'll start with reading input from the user (you).
That's done using the aptly named read
builtin, which reads input into a variable!
Here is an example using the -p
argument, which lets you specify a prompt (otherwise, it would be hard for you, reading this now, to separate input from output in the example below):
hacker@dojo:~$ read -p "INPUT: " MY_VARIABLE
INPUT: Hello!
hacker@dojo:~$ echo "You entered: $MY_VARIABLE"
You entered: Hello!
Keep in mind, read
reads data from your standard input!
The first Hello!
, above, was inputted rather than outputted.
Let's try to be more explicit with that.
Here, we annotated the beginning of each line with whether the line represents INPUT
from the user or OUTPUT
to the user:
INPUT: hacker@dojo:~$ echo $MY_VARIABLE
OUTPUT:
INPUT: hacker@dojo:~$ read MY_VARIABLE
INPUT: Hello!
INPUT: hacker@dojo:~$ echo "You entered: $MY_VARIABLE"
OUTPUT: You entered: Hello!
In this challenge, your job is to use read
to set the PWN
variable to the value COLLEGE
.
Good luck!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Often, when shell users want to read a file into an environment variable, they do something like:
hacker@dojo:~$ echo "test" > some_file
hacker@dojo:~$ VAR=$(cat some_file)
hacker@dojo:~$ echo $VAR
test
This works, but it represents what grouchy hackers call a "Useless Use of Cat".
That is, running a whole other program just to read the file is a waste.
It turns out that you can just use the powers of the shell!
Previously, you read
user input into a variable.
You've also previously redirected files into command input!
Put them together, and you can read files with the shell.
hacker@dojo:~$ echo "test" > some_file
hacker@dojo:~$ read VAR < some_file
hacker@dojo:~$ echo $VAR
test
What happened there?
The example redirects some_file
into the standard input of read
, and so when read
reads into VAR
, it reads from the file!
Now, use that to read /challenge/read_me
into the PWN
environment variable, and we'll give you the flag!
The /challenge/read_me
will keep changing, so you'll need to read it right into the PWN
variable with one command!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Data Manipulation
You've learned to pipe data, specify input, and so on.
Let's start putting things together!
In this module, you'll learn a number of commands for manipulating data that will help you achieve great results on the shell.
One of the purposes of piping data is to modify it.
Many Linux commands will help you modify data in really cool ways.
One of these is tr
, which tr
anslates characters it receives over standard input and prints them to standard output.
In its most basic usage, tr
translates the character provided in its first argument to the character provided in its second argument:
hacker@dojo:~$ echo OWN | tr O P
PWN
hacker@dojo:~$
It can also handle multiple characters, with the characters in different positions of the first argument replaced with associated characters in the second argument.
hacker@dojo:~$ echo PWM.COLLAGE | tr MA NE
PWN.COLLEGE
hacker@dojo:~$
Now, you try it!
In this level, /challenge/run
will print the flag but will swap the casing of all characters (e.g., A
will become a
and vice-versa).
Can you undo it with tr
and get the flag?
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
tr
can also translate characters to nothing (i.e., delete them).
This is done via a -d
flag and an argument of what characters to delete:
hacker@dojo:~$ echo PAWN | tr -d A
PWN
hacker@dojo:~$
Pretty simple!
Now you give it a try.
I'll intersperse some decoy characters (specifically: ^
and %
) among the flag characters.
Use tr -d
to remove them!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
A common class of characters to remove is a line separator.
This happens when you have a stream of data that you want to turn into a single line for further processing.
You can specify newlines almost like any other character, by escaping them:
hacker@dojo:~$ echo "hello_world!" | tr _ "\n"
hello
world!
hacker@dojo:~$
Here, the backslash (\
) signifies that the character that follows it is a standin for a character that's hard to input into the shell normally.
The newline, of course, is hard to input because when you typically hit Enter
, you'll run the command itself.
\n
is a standin for this newline, and it must be in quotes to prevent the shell interpreter itself from trying to interpret it and pass it to tr
instead.
Now, let's combine this with deletion.
In this challenge, we'll inject a bunch of newlines into the flag.
Delete them with tr
's -d
flag and the escaped newline specification!
Fun fact!
Want to actually replace a backslash (\
) character?
Because \
is the escape character, you gotta escape it!
\\
will be treated as a backslash by tr
.
This isn't relevant to this challenge, but is a fun fact nonetheless!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
In your Linux journey, you'll experience situations where you need to grab just the early output of very verbose programs.
For this, you'll reach for head
!
The head
command is used to display the first few lines of its input:
hacker@dojo:~$ cat /something/very/long | head
this
is
just
the
first
ten
lines
of
the
file
hacker@dojo:~$
By default, it shows the first 10 lines, but you can control this with the -n
option:
hacker@dojo:~$ cat /something/very/long | head -n 2
this
is
hacker@dojo:~$
This challenge's /challenge/pwn
outputs a bunch of data, and you'll need to pipe it through head
to grab just the first 7 lines and then pipe them onwards to /challenge/college
, which will give you the flag if you do this right!
Your solution will be a long composite command with two pipes connecting three commands.
Good luck!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Sometimes, you want to grab specific columns of data, such as the first column, the third column, or the 42nd column.
For this, there"s the cut
command.
For example, imagine that you have the following data file:
hacker@dojo:~$ cat scores.txt
hacker 78 99 67
root 92 43 89
hacker@dojo:~$
You could use cut
to extract specific columns:
hacker@dojo:~$ cut -d " " -f 1 scores.txt
hacker
root
hacker@dojo:~$ cut -d " " -f 2 scores.txt
78
92
hacker@dojo:~$ cut -d " " -f 3 scores.txt
99
43
hacker@dojo:~$
The -d
argument specifies the column delimiter (how columns are separated).
In this case, it"s a space character.
Of course, it has to be in quotes here so that the shell knows that the space is an argument rather than a space separating other arguments!
The -f
argument specifies the field number (which column to extract).
In this challenge, the /challenge/run
program will give you a bunch of lines with random numbers and single characters (characters of the flag) as columns.
Use cut
to extract the flag characters, then pipe them to tr -d "\n"
(like the previous level!) to join them together into a single line.
Your solution will look something like /challenge/run | cut ??? | tr ???
, with the ???
filled out.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Files (or output lines of commands) aren't always in the order you need them!
The sort
command helps you organize data.
It reads lines from input (or files) and outputs them in sorted order:
hacker@dojo:~$ cat names.txt
hack
the
planet
with
pwn
college
hacker@dojo:~$ sort names.txt
college
hack
planet
pwn
the
with
hacker@dojo:~$
By default, sort
orders lines alphabetically.
Arguments can change this:
-r
: reverse order (Z to A)
-n
: numeric sort (for numbers)
-u
: unique lines only (remove duplicates)
-R
: random order!
In this challenge, there's a file at /challenge/flags.txt
containing 100 fake flags, with the real flag mixed among them.
When sorted alphabetically, the real flag will be at the end (we made sure of this when generating fake flags).
Go get it!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Processes and Jobs
Computers execute software to get stuff done.
In modern computing, this software is split into two categories: operating system kernels (about which we will learn much later) and processes, which we will discuss here.
When Linux starts up, it launches an init (short for initializer) process that, in turn, launches a bunch of other processes which launch more processes until, eventually, you are looking at your command line shell, which is also a process!
The shell, of course, launches processes in response to the commands you enter.
In this module, we will learn to view and interact with processes in a number of exciting ways!
First, we will learn to list running processes using the ps
command.
Depending on whom you ask, ps
either stands for "process snapshot" or "process status", and it lists processes.
By default, ps
just lists the processes running in your terminal, which honestly isn't very useful:
hacker@dojo:~$ ps
PID TTY TIME CMD
329 pts/0 00:00:00 bash
349 pts/0 00:00:00 ps
hacker@dojo:~$
In the above example, we have the shell (bash
) and the ps
process itself, and that's all that's running on that specific terminal.
We also see that each process has a numerical identifier (the Process ID, or PID), which is a number that uniquely identifies every running process in a Linux environment.
We also see the terminal on which the commands are running (in this case, the designation pts/0
), and the total amount of cpu time that the process has eaten up so far (since these processes are very undemanding, they have yet to eat up even 1 second!).
In the majority of cases, this is all that you'll see with a default ps
.
To make it useful, we need to pass a few arguments.
As ps
is a very old utility, its usage is a bit of a mess.
There are two ways to specify arguments.
"Standard" Syntax: in this syntax, you can use -e
to list "every" process and -f
for a "full format" output, including arguments.
These can be combined into a single argument -ef
.
"BSD" Syntax: in this syntax, you can use a
to list processes for all users, x
to list processes that aren't running in a terminal, and u
for a "user-readable" output.
These can be combined into a single argument aux
.
These two methods, ps -ef
and ps aux
result in slightly different, but cross-recognizable output.
Let's try it in the dojo:
hacker@dojo:~$ ps -ef
UID PID PPID C STIME TTY TIME CMD
hacker 1 0 0 05:34 ? 00:00:00 /sbin/docker-init -- /bin/sleep 6h
hacker 7 1 0 05:34 ? 00:00:00 /bin/sleep 6h
hacker 102 1 1 05:34 ? 00:00:00 /usr/lib/code-server/lib/node /usr/lib/code-server --auth=none -
hacker 138 102 11 05:34 ? 00:00:07 /usr/lib/code-server/lib/node /usr/lib/code-server/out/node/entr
hacker 287 138 0 05:34 ? 00:00:00 /usr/lib/code-server/lib/node /usr/lib/code-server/lib/vscode/ou
hacker 318 138 6 05:34 ? 00:00:03 /usr/lib/code-server/lib/node --dns-result-order=ipv4first /usr/
hacker 554 138 3 05:35 ? 00:00:00 /usr/lib/code-server/lib/node /usr/lib/code-server/lib/vscode/ou
hacker 571 554 0 05:35 pts/0 00:00:00 /usr/bin/bash --init-file /usr/lib/code-server/lib/vscode/out/vs
hacker 695 571 0 05:35 pts/0 00:00:00 ps -ef
hacker@dojo:~$
You can see here that there are processes running for the initialization of the challenge environment (docker-init
), a timeout before the challenge is automatically terminated to preserve computing resources (sleep 6h
to timeout after 6 hours), the VSCode environment (several code-server
helper processes), the shell (bash
), and my ps -ef
command.
It's basically the same thing with ps aux
:
hacker@dojo:~$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
hacker 1 0.0 0.0 1128 4 ? Ss 05:34 0:00 /sbin/docker-init -- /bin/sleep 6h
hacker 7 0.0 0.0 2736 580 ? S 05:34 0:00 /bin/sleep 6h
hacker 102 0.4 0.0 723944 64660 ? Sl 05:34 0:00 /usr/lib/code-server/lib/node /usr/lib/code-serve
hacker 138 3.3 0.0 968792 106272 ? Sl 05:34 0:07 /usr/lib/code-server/lib/node /usr/lib/code-serve
hacker 287 0.0 0.0 717648 53136 ? Sl 05:34 0:00 /usr/lib/code-server/lib/node /usr/lib/code-serve
hacker 318 3.3 0.0 977472 98256 ? Sl 05:34 0:06 /usr/lib/code-server/lib/node --dns-result-order=
hacker 554 0.4 0.0 650560 55360 ? Rl 05:35 0:00 /usr/lib/code-server/lib/node /usr/lib/code-serve
hacker 571 0.0 0.0 4600 4032 pts/0 Ss 05:35 0:00 /usr/bin/bash --init-file /usr/lib/code-server/li
hacker 1172 0.0 0.0 5892 2924 pts/0 R+ 05:38 0:00 ps aux
hacker@dojo:~$
There are many commonalities between ps -ef
and ps aux
: both display the user (USER
column), the PID, the TTY, the start time of the process (STIME
/START
), the total utilized CPU time (TIME
), and the command (CMD
/COMMAND
).
ps -ef
additionally outputs the Parent Process ID (PPID
), which is the PID of the process that launched the one in question, while ps aux
outputs the percentage of total system CPU and Memory that the process is utilizing.
Plus, there's a bunch of other stuff we won't get into right now.
Anyways!
Let's practice.
In this level, I have once again renamed /challenge/run
to a random filename, and this time made it so that you cannot ls
the /challenge
directory!
But I also launched it, so you can find it in the running process list, figure out the filename, and relaunch it directly for the flag!
Good luck!
NOTE: Both ps -ef
and ps aux
truncate the command listing to the width of your terminal (which is why the examples above line up so nicely on the right side of the screen.
If you can't read the whole path to the process, you might need to enlarge your terminal (or redirect the output somewhere to avoid this truncating behavior)!
Alternatively, you can pass the w
option twice (e.g., ps -efww
or ps auxww
) to disable the truncation.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
You've launched processes, you've viewed processes, now you will learn to terminate processes!
In Linux, this is done using the aggressively-named kill
command.
With default options (which is all we'll cover in this level), kill
will terminate a process in a way that gives it a chance to get its affairs in order before ceasing to exist.
Let's say you had a pesky sleep
process (sleep
is a program that simply hangs out for the number of seconds specified on the commandline, in this case, 1337 seconds) that you launched in another terminal, like so:
hacker@dojo:~$ sleep 1337
How do we get rid of it?
You use kill
to terminate it by passing the process identifier (the PID
from ps
) as an argument, like so:
hacker@dojo:~$ ps -e | grep sleep
342 pts/0 00:00:00 sleep
hacker@dojo:~$ kill 342
hacker@dojo:~$ ps -e | grep sleep
hacker@dojo:~$
Now, it's time to terminate your first process!
In this challenge, /challenge/run
will refuse to run while /challenge/dont_run
is running!
You must find the dont_run
process and kill
it.
If you fail, pwn.college
will disavow all knowledge of your mission.
Good luck.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
You've learned how to kill other processes with the kill
command, but sometimes you just want to get rid of the process that's clogging up your terminal!
Luckily, terminals have a hotkey for this: Ctrl-C
(e.g., holding down the Ctrl
key and pressing C
) sends an "interrupt" to whatever application is waiting on input from the terminal and, typically, this causes the application to cleanly exit.
Try it here!
/challenge/run
will refuse to give you the flag until you interrupt it.
Good luck!
For the very interested, check out this article about terminals and "control codes" (such as Ctrl^C
).
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Sometimes, misbehaving processes can interfere with your work.
These processes might need to be killed...
In this challenge, there's a decoy process that's hogging a critical resource - a named pipe (FIFO) at /tmp/flag_fifo
into which (like in the Practicing Piping FIFO challenge) /challenge/run
wants to write your flag.
You need to kill
this process.
Your general workflow should be:
- Check what processes are running.
- Find
/challenge/decoy
in the list and figure out its process ID.
kill
it.
- Run
/challenge/run
to get the flag without being overwhelmed by decoys (you don't need to redirect its output; it'll write to the FIFO on its own).
Good luck!
NOTE:
You might see a few decoy flags show up even after killing the decoy process.
This happens because Linux pipes are buffered: conceptually, they have a sort of length through which data flows, and you might kill the decoy process while data is in the pipe.
That data, having already entered the pipe, will proceed to the other end (your cat
).
If you wait a second, you'll see the decoys stop, and then you can /challenge/run
and win!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
You have learned to interrupt processes with Ctrl-C
, but there are less drastic measures you can use to get your terminal back!
You can suspend processes to the background with Ctrl-Z
.
In this level, we'll explore how this works and, in the next level, we'll figure out how to resume those suspended processes!
This level's run
wants to see another copy of itself running and using the same terminal.
How?
Use the terminal to launch it, then suspend it, then launch another copy while the first is suspended!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Usually, when you suspend processes, you'll want to resume them at some point.
Otherwise, why not just terminate them?
To resume processes, your shell provides the fg
command, a builtin that takes the suspended process, resumes it, and puts it back in the foreground of your terminal.
Go try it out!
This challenge's run
needs you to suspend it, then resume it.
Good luck!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
You've resumed processes in the foreground with the fg
command.
You can also resume processes in the background with the bg
command!
This will allow the process to keep running, while giving you your shell back to invoke more commands in the meantime.
This level's run
wants to see another copy of itself running, not suspended, and using the same terminal.
How?
Use the terminal to launch it, then suspend it, then background it with bg
and launch another copy while the first is running in the background!
ARCANUM:
If you're interested in some deeper details, check out how to view the differences between suspended and backgrounded properties!
Allow me to demonstrate.
First, let's suspend a sleep
:
hacker@dojo:~$ sleep 1337
^Z
[1]+ Stopped sleep 1337
hacker@dojo:~$
The sleep
process is now suspended in the background.
We can see this with ps
by enabling the stat
column output with the -o
option:
hacker@dojo:~$ ps -o user,pid,stat,cmd
USER PID STAT CMD
hacker 702 Ss bash
hacker 762 T sleep 1337
hacker 782 R+ ps -o user,pid,stat,cmd
hacker@dojo:~$
See that T
?
That means that the process is suspended due to our Ctrl-Z
.
The S
in bash
's STAT
column means that bash
is sleeping while waiting for input.
the R
in ps
's column means that it's actively running, and the +
means that it's in the foreground!
Watch what happens when we resume sleep
in the background:
hacker@dojo:~$ bg
[1]+ sleep 1337 &
hacker@dojo:~$ ps -o user,pid,stat,cmd
USER PID STAT CMD
hacker 702 Ss bash
hacker 762 S sleep 1337
hacker 1224 R+ ps -o user,pid,stat,cmd
hacker@dojo:~$
Boom!
The sleep
now has an S
.
It's sleeping while, well, sleeping, but it's not suspended!
It's also in the background and thus doesn't have the +
.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Imagine that you have a backgrounded process, and you want to mess with it some more.
What do you do?
Well, you can foreground a backgrounded process with fg
just like you foreground a suspended process!
This level will walk you through that!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Of course, you don't have to suspend processes to background them: you can start them backgrounded right off the bat!
It's easy; all you have to do is append a &
to the command, like so:
hacker@dojo:~$ sleep 1337 &
[1] 1771
hacker@dojo:~$ ps -o user,pid,stat,cmd
USER PID STAT CMD
hacker 1709 Ss bash
hacker 1771 S sleep 1337
hacker 1782 R+ ps -o user,pid,stat,cmd
hacker@dojo:~$
Here, sleep
is actively running in the background, not suspended.
Now it's your turn to practice!
Launch /challenge/run
backgrounded for the flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Every shell command, including every program and every builtin, exits with an exit code when it finishes running and terminates,
This can be used by the shell, or the user of the shell (that's you!) to check if the process succeeded in its functionality (this determination, of course, depends on what the process is supposed to do in the first place).
You can access the exit code of the most recently-terminated command using the special ?
variable (don't forget to prepend it with $
to read its value!):
hacker@dojo:~$ touch test-file
hacker@dojo:~$ echo $?
0
hacker@dojo:~$ touch /test-file
touch: cannot touch '/test-file': Permission denied
hacker@dojo:~$ echo $?
1
hacker@dojo:~$
As you can see, commands that succeed typically return 0
and commands that fail typically return a non-zero value, most commonly 1
but sometimes an error code that identifies a specific failure mode.
In this challenge, you must retrieve the exit code returned by /challenge/get-code
and then run /challenge/submit-code
with that error code as an argument.
Good luck!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Untangling Users
Did you think you, hacker
, are alone in the workspace?
There are MANY users on a typical Linux system!
The full list of users on a Linux system is specified in the /etc/passwd
file (named so for historical reasons --- it doesn't actually hold passwords anymore).
Here is an example from the dojo container:
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
systemd-timesync:x:101:101:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
systemd-network:x:102:103:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:103:104:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
mysql:x:104:105:MySQL Server,,,:/nonexistent:/bin/false
messagebus:x:105:106::/nonexistent:/usr/sbin/nologin
sshd:x:106:65534::/run/sshd:/usr/sbin/nologin
hacker:x:1000:1000::/home/hacker:/bin/bash
A lot of users here, and a lot of info!
Each line contains, separated by :
s, the username, an x
as a placeholder for where the password used to be (we'll cover where it actually is later), the numerical user ID, the numerical default group ID, long-form user details, the home directory, and the default shell.
We can see the hacker
user at the bottom.
That's you!
Most of the rest of these users are either there for historical reasons, are service accounts to support various installed software, or some are "utility" accounts (e.g., the nobody
user is used to ensure that, e.g., some programs run without any special privileges).
One important user is root
: the system administrator.
The system administrator has obvious security implications: a hacker
user that can somehow, through various functionalities of Linux, become the root
user would be able to wreak havoc on the system.
A very frequent goal of hackers breaking into systems is to escalate to root
, and thus root
must be defended at all cost!
In this module, we'll explore various user shenanigans, learn the intended ways to switch users to administer the system, and have fun along the way!
It's not just hackers that need to become root
.
Oftentimes, you, as the owner of your computer, needs to use root
access to administer it.
Becoming root is a fairly common action that Linux users take, and there are two utilities that exist for this purposes: su
and sudo
.
In this challenge, we will cover the older one, su
(the switch user command).
This is not typically used to elevate to root access anymore, but it is an elegant utility from a more civilized time, and we'll cover it first.
su
is a setuid binary:
hacker@dojo:~$ ls -l /usr/bin/su
-rwsr-xr-x 1 root root 232416 Dec 1 11:45 /usr/bin/su
hacker@dojo:~$
Because it has the SUID bit set, su
runs as root.
Running as root, it can start a root shell!
Of course, su
is discerning: before allowing the user to elevate privileges to root, it checks to make sure that the user knows the root password:
hacker@dojo:~$ su
Password:
su: Authentication failure
hacker@dojo:~$
This check against the root password is what obsoletes su
.
Modern systems very rarely have root passwords, and different mechanisms (that we will learn later) are used to grant administrative access.
But THIS challenge (and only this challenge) does have a root password.
That password is hack-the-planet
, and you must provide it to su
to become root!
Go do that, and read the flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
With no arguments, su
will start a root shell (after authenticating with root's password).
However, you can also give a username as an argument to switch to that user instead of root.
For example:
hacker@dojo:~$ su some-user
Password:
some-user@dojo:~$
Awesome!
In this level, you must switch to the zardus
user and then run /challenge/run
.
Zardus' password is dont-hack-me
.
Good luck!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
When you enter a password for su
, it compares it against the stored password for that user.
These passwords used to be stored in /etc/passwd
, but because /etc/passwd
is a globally-readable file, this is not good for passwords, these were moved to /etc/shadow
.
Here is the example /etc/shadow
from the previous level:
root:$6$s74oZg/4.RnUvwo2$hRmCHZ9rxX56BbjnXcxa0MdOsW2moiW8qcAl/Aoc7NEuXl2DmJXPi3gLp7hmyloQvRhjXJ.wjqJ7PprVKLDtg/:19921:0:99999:7:::
daemon:*:19873:0:99999:7:::
bin:*:19873:0:99999:7:::
sys:*:19873:0:99999:7:::
sync:*:19873:0:99999:7:::
games:*:19873:0:99999:7:::
man:*:19873:0:99999:7:::
lp:*:19873:0:99999:7:::
mail:*:19873:0:99999:7:::
news:*:19873:0:99999:7:::
uucp:*:19873:0:99999:7:::
proxy:*:19873:0:99999:7:::
www-data:*:19873:0:99999:7:::
backup:*:19873:0:99999:7:::
list:*:19873:0:99999:7:::
irc:*:19873:0:99999:7:::
gnats:*:19873:0:99999:7:::
nobody:*:19873:0:99999:7:::
_apt:*:19873:0:99999:7:::
systemd-timesync:*:19901:0:99999:7:::
systemd-network:*:19901:0:99999:7:::
systemd-resolve:*:19901:0:99999:7:::
mysql:!:19901:0:99999:7:::
messagebus:*:19901:0:99999:7:::
sshd:*:19901:0:99999:7:::
hacker::19916:0:99999:7:::
zardus:$6$bEFkpM0w/6J0n979$47ksu/JE5QK6hSeB7mmuvJyY05wVypMhMMnEPTIddNUb5R9KXgNTYRTm75VOu1oRLGLbAql3ylkVa5ExuPov1.:19921:0:99999:7:::
Separated by :
s, the first field of each line is the username and the second is the password.
A value of *
or !
functionally means that password login for the account is disabled, a blank field means that there is no password (a not-uncommon misconfiguration that allows password-less su
in some configurations), and the long string such as Zardus' $6$bEFkpM0w/6J0n979$47ksu/JE5QK6hSeB7mmuvJyY05wVypMhMMnEPTIddNUb5R9KXgNTYRTm75VOu1oRLGLbAql3ylkVa5ExuPov1.
is the result of one-way-encrypting (hashing) Zardus' password from the last level (in this case, dont-hack-me
).
Other fields in this file have other meanings, and you can read more about them here.
When you input a password into su
, it one-way-encrypts (hashes) it and compares the result against the stored value.
If the result matches, su
grants you access to the user!
But what if you don't know the password?
If you have the hashed value of the password, you can crack it!
Even though /etc/shadow
is, by default, only readable by root, leaks can happen!
For example, backups are often stored, unencrypted and insufficiently protected, on file servers, and this has led to countless data disclosures.
If a hacker gets their hands on a leaked /etc/shadow
, they can start cracking passwords and wreaking havoc.
The cracking can be done via the famous John the Ripper, as so:
hacker@dojo:~$ john ./my-leaked-shadow-file
Loaded 1 password hash (crypt, generic crypt(3) [?/64])
Will run 32 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
password1337 (zardus)
1g 0:00:00:22 3/3 0.04528g/s 10509p/s 10509c/s 10509C/s lykys..lank
Use the "--show" option to display all of the cracked passwords reliably
Session completed
hacker@dojo:~$
Here, John the Ripper cracked Zardus' leaked password hash to find the real value of password1337
.
Poor Zardus!
This level simulates this story, giving you a leak of /etc/shadow
(in /challenge/shadow-leak
).
Crack it (this could take a few minutes), su
to zardus
, and run /challenge/run
to get the flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
In the olden days, a typical Linux system had a root password that administrators would use to su
to root (after logging into their account with their normal account password).
But root passwords are a pain to maintain, they (or their hashes!) can leak, and they don't lend themselves well to larger environments (e.g., fleets of servers).
To address this, in recent decades, the world has moved from administration via su
to administration via sudo
(superuser do).
Unlike su
, which defaults to launching a shell as a specified user, sudo
defaults to running a command as root:
hacker@dojo:~$ whoami
hacker
hacker@dojo:~$ sudo whoami
root
hacker@dojo:~$
Or, more relevant to getting flags:
hacker@dojo:~$ grep hacker /etc/shadow
grep: /etc/shadow: Permission denied
hacker@dojo:~$ sudo grep hacker /etc/shadow
hacker:$6$Xro.e7qB3Q2Jl2sA$j6xffIgWn9xIxWUeFzvwPf.nOH2NTWNJCU5XVkPuONjIC7jL467SR4bXjpVJx4b/bkbl7kyhNquWtkNlulFoy.:19921:0:99999:7:::
hacker@dojo:~$
Unlike su
, which relies on password authentication, sudo
checks policies to determine whether the user is authorized to run commands as root.
These policies are defined in /etc/sudoers
, and though it's mostly out of scale for our purposes, there are plenty of resources for learning about this!
So, the world has moved to sudo
and has (for the purposes of system administration) left su
behind.
In fact, even pwn.college's Practice Mode works by giving you sudo
access to elevate privileges!
In this level, we will give you sudo
access, and you will use it to read the flag.
Nice and easy!
NOTE:
After this level, we will enable Practice Mode!
When you launch a challenge in Practice Mode (by clicking the Practice
button instead of the Start
button), the resulting container will give you full sudo
access to allow you to introspect and debug to your heart's content, but of course with a placeholder flag.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Perceiving Permissions
This module will expose you to Linux permissions, which is one of the most important parts of your journey going ahead, and mediates the access to files across different users.
In Linux, files have different permissions or file modes.
You can check out a permissions of a file or directory using ls -l
.
Let's make some files and look at their permissions:
hacker@dojo:~$ mkdir pwn_directory
hacker@dojo:~$ touch college_file
hacker@dojo:~$ ls -l
total 4
-rw-r--r-- 1 hacker hacker 0 May 22 13:42 college_file
drwxr-xr-x 2 hacker hacker 4096 May 22 13:42 pwn_directory
hacker@dojo:~$
Lots of information, there, and we'll learn about a lot of it in this module!
For now, let's look at the output above at a high level:
The File Type
The first character of each line represents the file type.
In pwn_directory
's case, the d
indicates that it's a directory, and in college_file
's case, the -
represents that it's a normal file.
There are other types as well, and you will encounter some of them later in your pwn.college journey.
The Permissions
The next nine characters are the actual access permissions of the file or directory, split into 3 characters denoting the permissions that the user who owns the file (termed the "owner") has to the file, 3 characters denoting the permissions that the group that owns the file (termed the "group") has to the file, and 3 characters denoting the permissions that all other access (e.g., by other users and other groups) has to the file.
We will learn all about these later in the module.
Ownership Information
There are two columns showing the user that owns the file (in this case, user hacker
) and then the group that owns the file (in this case, also group hacker
).
You'll mess around with that here!
In this module, you will practice perceiving permissions.
Let's get started!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
First things first: file ownership.
Every file in Linux is owned by a user on the system.
Most often, in your day-to-day life, that user is the user you log in as every day.
On a shared system (such as in a computer lab), there might be many people with different user accounts, all with their own files in their own home directories.
But even on a non-shared system (such as your personal PC), Linux still has many "service" user accounts for different tasks.
The two most important user accounts are:
- Your user account! On pwn.college, this is the
hacker
user, regardless of what your username is.
root
. This is the administrative account and, in most security situations, the ultimate prize. If you take over the root
user, you've almost certainly achieved your hacking objective!
So what?
Well, it turns out that the way that we prevent you from just doing cat /flag
is by having /flag
owned by the root user, configure its permissions so that no other user can read it (you will learn how to do that later), and configure the actual challenge to run as the root
user (you will learn how to do this later as well).
The result is that when you do cat /flag
, you get:
hacker@dojo:~$ ls -l /flag
-r-------- 1 root root 53 Jul 4 04:47 /flag
hacker@dojo:~$ cat /flag
cat: /flag: Permission denied
hacker@dojo:~$
Here, you can see that the flag is owned by the root user (the first root
in that line) and the root group (the second root
in that line).
When we try to read it as the hacker
user, we are denied.
However, if we were root
(a hacker's dream!), we would have no problem reading this file:
root@dojo:~# cat /flag
pwn.college{demo_flag}
root@dojo:~#
Interestingly, we can change the ownership of files!
This is done via the chown
(change owner) command:
chown [username] [file]
Typically, chown
can only be invoked by the root
user.
Let's pretend that we're root again (that never gets old!), and watch a typical use of chown
:
root@dojo:~# mkdir pwn_directory
root@dojo:~# touch college_file
root@dojo:~# ls -l
total 4
-rw-r--r-- 1 root root 0 May 22 13:42 college_file
drwxr-xr-x 2 root root 4096 May 22 13:42 pwn_directory
root@dojo:~# chown hacker college_file
root@dojo:~# ls -l
total 4
-rw-r--r-- 1 hacker root 0 May 22 13:42 college_file
drwxr-xr-x 2 root root 4096 May 22 13:42 pwn_directory
root@dojo:~#
college_file
's owner has been changed to the hacker
user, and now hacker
can do with it whatever root
had been able to do with it!
If this was the /flag
file, that means that the hacker
user would be able to read it!
In this level, we will practice changing the owner of the /flag
file to the hacker
user, and then read the flag.
For this challenge only, I made it so that you can use chown to your heart's content as the hacker
user (again, typically, this requires you to be root
).
Use this power wisely and chown away!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Sharing is caring, and sharing is built into Linux's design.
Files have both an owning user and group.
A group can have multiple users in it, and a user can be a member of multiple groups.
You can check what groups you are part of with the id
command:
hacker@dojo:~$ id
uid=1000(hacker) gid=1000(hacker) groups=1000(hacker)
hacker@dojo:~$
Here, the hacker
user is only in the hacker
group.
The most common use-case for groups is to control access to different system resources.
For example, "Practice Mode" in pwn.college grants you root access to allow better debugging and so on.
This is handled by giving you an extra group when you launch in practice mode:
hacker@dojo:~$ id
uid=1000(hacker) gid=1000(hacker) groups=1000(hacker),27(sudo)
hacker@dojo:~$
A typical main user of a typical Linux desktop has a lot of groups.
For example, this is Zardus' desktop:
zardus@yourcomputer:~$ id
uid=1000(zardus) gid=1000(zardus) groups=1000(zardus),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),100(users),106(netdev),114(bluetooth),117(lpadmin),120(scanner),995(docker)
zardus@yourcomputer:~$
All these groups give Zardus the ability to read CDs and floppy disks (who does that anymore?), administer the system, play music, draw to the video monitor, use bluetooth, and so on.
Often, this access control happens via group ownership on the filesystem!
For example, graphical output can be done via the special /dev/fb0
file:
zardus@yourcomputer:~$ ls -l /dev/fb0
crw-rw---- 1 root video 29, 0 Jun 30 23:42 /dev/fb0
zardus@yourcomputer:~$
This file is a special device file (type c
means it is a "character device"), and interacting with it results in changes to the display output (rather than changes to disk storage, as for a normal file!).
Zardus' user account on his machine can interact with it because the file has a group ownership of video
, and Zardus is a member of the video
group.
No such luck for the /flag
file in the dojo, though!
Consider the following:
hacker@dojo:~$ id
uid=1000(hacker) gid=1000(hacker) groups=1000(hacker)
hacker@dojo:~$ ls -l /flag
-r--r----- 1 root root 53 Jul 4 04:47 /flag
hacker@dojo:~$ cat /flag
cat: /flag: Permission denied
hacker@dojo:~$
Here, the flag file is owned by the root user and the root group, and the hacker
user is neither the root
user nor a member of the root
group, so the file cannot be accessed.
Luckily, group ownership can be changed with the chgrp
(change group) command!
Unless you have write access to the file and membership in the new group, this typically requires root access, so let's check it out as root:
root@dojo:~# mkdir pwn_directory
root@dojo:~# touch college_file
root@dojo:~# ls -l
total 4
-rw-r--r-- 1 root root 0 May 22 13:42 college_file
drwxr-xr-x 2 root root 4096 May 22 13:42 pwn_directory
root@dojo:~# chgrp hacker college_file
root@dojo:~# ls -l
total 4
-rw-r--r-- 1 root hacker 0 May 22 13:42 college_file
drwxr-xr-x 2 root root 4096 May 22 13:42 pwn_directory
root@dojo:~#
In this level, I have made the flag readable by whatever group owns it, but this group is currently root
.
Luckily, I have also made it possible for you to invoke chgrp
as the hacker
user!
Change the group ownership of the flag file, and read the flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
In the previous levels, you may have noticed that your hacker
user is a member of the hacker
group, and that zardus
is a member of the zardus
group.
There is a convention in Linux that every user has their own group, but this does not have to be the case.
For example, many computer labs will put all of their users into a single, shared users
group.
The point is, you've used hacker
for the group before, but in this level, that is not going to work.
I'll still allow you to use chgrp
, but I have randomized the name of the group that your user is in.
You will need to use the id
command to figure that name out, then chgrp
to victory!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
So now we're well-versed in ownership.
Let's talk about the other side of the coin: file permissions.
Recall our example:
hacker@dojo:~$ mkdir pwn_directory
hacker@dojo:~$ touch college_file
hacker@dojo:~$ ls -l
total 4
-rw-r--r-- 1 hacker hacker 0 May 22 13:42 college_file
drwxr-xr-x 2 hacker hacker 4096 May 22 13:42 pwn_directory
hacker@dojo:~$
As a reminder, the first character there is the file type.
The next nine characters are the actual access permissions of the file or directory, split into 3 characters denoting permissions for the owning user (now you understand this!), 3 characters denoting the permissions for the owning group (now you understand this as well!), and 3 characters denoting the permissions that all other access (e.g., by other users and other groups) has to the file.
Each character of the three represent permission for a different type:
r - user/group/other can read the file (or list the directory)
w - user/group/other can modify the files (or create/delete files in the directory)
x - user/group/other can execute the file as a program (or can enter the directory, e.g., using `cd`)
- - nothing
For college_file
above, the rw-r--r--
permissions entry decodes to:
r
: the user that owns the file (user hacker
) can read it
w
: the user that owns the file (user hacker
) can write to it
-
: the user that owns the file (user hacker
) cannot execute it
r
: users in the group that owns the file (group hacker
) can read it
-
: users in the group that owns the file (group hacker
) cannot write to it
-
: users in the group that owns the file (group hacker
) cannot execute it
r
: all other users can read it
-
: all other users cannot write to it
-
: all other users cannot execute it
Now, let's look at the default permissions of /flag
:
hacker@dojo:~$ ls -l /flag
-r-------- 1 root root 53 Jul 4 04:47 /flag
hacker@dojo:~$
Here, there is only one bit set: the r
ead permission for the owning user (in this case, root).
Members of the owning group (the root
group) and all other users have no access to the file.
You might be wondering how the chgrp
levels worked, if there is no group access to the file.
Well, for those levels, I set the permissions differently:
hacker@dojo:~$ ls -l /flag
-r--r----- 1 root root 53 Jul 4 04:47 /flag
hacker@dojo:~$
The group had access!
That is why chgrp
ing the file enabled you to read the file.
Anyways!
Like ownership, file permissions can also be changed.
This is done with the chmod
(change mode) command.
The basic usage for chmod is:
chmod [OPTIONS] MODE FILE
You can specify the MODE
in two ways: as a modification of the existing permissions mode, or as a completely new mode to overwrite the old one.
In this level, we will cover the former: modifying an existing mode.
chmod
allows you to tweak permissions with the mode format of WHO
+/-WHAT
, where WHO
is user/group/other and WHAT
is read/write/execute.
For example, to add read access for the owning user, you would specify a mode of u+r
.
w
rite and ex
ecute access for the g
roup and the o
ther (or a
ll the modes) are specified the same way.
More examples:
u+r
, as above, adds read access to the user's permissions
g+wx
adds write and execute access to the group's permissions
o-w
removes write access for other users
a-rwx
removes all permissions for the user, group, and world
So:
root@dojo:~# mkdir pwn_directory
root@dojo:~# touch college_file
root@dojo:~# ls -l
total 4
-rw-r--r-- 1 root root 0 May 22 13:42 college_file
drwxr-xr-x 2 root root 4096 May 22 13:42 pwn_directory
root@dojo:~# chmod go-rwx *
root@dojo:~# ls -l
total 4
-rw------- 1 hacker root 0 May 22 13:42 college_file
drwx------ 2 root root 4096 May 22 13:42 pwn_directory
root@dojo:~#
In this challenge, you must change the permissions of the /flag
file to read it!
Typically, you need to have write access to the file in order to change its permissions, but I have made the chmod
command all-powerful for this level, and you can chmod
anything you want even though you are the hacker
user.
This is an ultimate power.
The /flag
file is owned by root, and you can't change that, but you can make it readable.
Go and solve this!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
So far, you have mostly been dealing with read permissions.
This makes sense, because you have been making the /flag
file readable to read it.
In this level, we will explore execute permissions.
When you invoke a program, such as /challenge/run
, Linux will only actually execute it if you have execute-access to the program file.
Consider:
hacker@dojo:~$ ls -l /challenge/run
-rwxr-xr-x 1 root root 0 May 22 13:42 /challenge/run
hacker@dojo:~$ /challenge/run
Successfully ran the challenge!
hacker@dojo:~$
In this case, /challenge/run
runs because it is executable by the hacker
user.
Because the file is owned by the root
user and root
group, this requires that the execute bit is set on the other
permissions.
If we remove these permissions, the execution will fail!
hacker@dojo:~$ chmod o-x /challenge/run
hacker@dojo:~$ ls -l /challenge/run
-rwxr-xr-- 1 root root 0 May 22 13:42 /challenge/run
hacker@dojo:~$ /challenge/run
bash: /challenge/run: Permission denied
hacker@dojo:~$
In this challenge, the /challenge/run
program will give you the flag, but you must first make it executable!
Remember your chmod
, and get /challenge/run
to tell you the flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
You think you can chmod
?
Let's practice!
This challenge will ask you to change the permissions of the /challenge/pwn
file in specific ways a few times in a row.
If you get the permissions wrong, the game will reset and you can try again.
If you get the permissions right eight times in a row, the challenge will let you chmod
/flag
to make it readable for yourself :-)
Launch /challenge/run
to get started!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
In addition to adding and removing permissions, as in the previous level, chmod
can also simply set permissions altogether, overwriting the old ones.
This is done by using =
instead of -
or +
.
For example:
u=rw
sets read and write permissions for the user, and wipes the execute permission
o=x
sets only executable permissions for the world, wiping read and write
a=rwx
sets read, write, and executable permissions for the user, group, and world!
But what if you want to change user permissions in a different way as group permissions?
Say, you want to set rw
for the owning user, but only r
for the owning group?
You can achieve this by chaining multiple modes to chmod with ,
!
chmod u=rw,g=r /challenge/pwn
will set the user permissions to read and write, and the group permissions to read-only
chmod a=r,u=rw /challenge/pwn
will set the user permissions to read and write, and the group and world permissions to read-only
Additionally, you can zero out permissions with -
:
chmod u=rw,g=r,o=- /challenge/pwn
will set the user permissions to read and write, the group permissions to read-only, and the world permissions to nothing at all
Keep in mind, that -
, appearing after =
is in a different context than if it appeared directly after the u
, g
, or o
(in which case, it would cause specific bits to be removed, not everything).
This level extends the previous level by requesting more radical permission changes, which you will need =
and ,
-chaining to achieve.
Good luck!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
As you explored in the previous module, there are many cases in which non-root users need elevated access to do certain system tasks.
The system admin can't be there to give them the password every time a user wanted to do a task that only root/sudoers can do.
Instead, the "Set User ID" (SUID) permissions bit allows the user to run a program as the owner of that program's file.
This is actually the exact mechanism used to let the challenge programs you run read the flag or, outside of pwn.college, to enable system administration tools such as su
, sudo
, and so on.
The permissions of a file with SUID look like this:
hacker@dojo:~$ ls -l /usr/bin/sudo
-rwsr-xr-x 1 root root 232416 Dec 1 11:45 /usr/bin/sudo
hacker@dojo:~$
The s
part in place of the executable bit means that the program is executable with SUID.
It means that, regardless of what user runs the program (as long as they have executable permissions), the program will execute as the owner user (in this case, the root
user).
As the owner of a file, you can set a file's SUID bit by using chmod:
chmod u+s [program]
But be careful!
Giving the SUID bit to an executable owned by root can give attackers a possible attack vector to become root.
You will learn more about this in the Program Misuse module.
Now, we are going to let you add the SUID bit to the /challenge/getroot
program in order to spawn a root shell for you to cat
the flag yourself!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Chaining Commands
In the piping module, you've explored the concept of using several commands, with data flowing between them via pipes, to accomplish something slightly more complex than the individual commands can do.
Of course, this concept also applies independent of the data transfer: sometimes, you might want to run several commands in quick succession to achieve some cumulative effect.
This module will cover a few ways, aside from piping, that commands can be chained.
By the end, you'll be on your way to writing shell scripts!
The easiest way to chain commands is ;
.
In most contexts, ;
separates commands in a similar way to how Enter separates lines.
So, this:
hacker@dojo:~$ echo COLLEGE > pwn
hacker@dojo:~$ cat pwn
COLLEGE
hacker@dojo:~$
Is roughly the same as this:
hacker@dojo:~$ echo COLLEGE > pwn; cat pwn
COLLEGE
hacker@dojo:~$
Basically, when you hit Enter, your shell executes your typed command and, after that command terminates, gives you the prompt to input another command.
The semicolon is analogous, just without the prompt and with you entering both commands before anything is executed.
Give it a try now! In this level, you must run /challenge/pwn
and then /challenge/college
, chaining them with a semicolon.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
You learned about exit codes in the Processes module.
Now let's use them to chain commands together!
The &&
operator allows you to run a second command only if the first command succeeds (in Linux convention, this means it exited with code 0).
This is called the "AND" operator because both conditions must be true: the first command must succeed AND then the second command will run.
That's super useful for complex commandline workflows where certain actions depend on the success of other actions.
Here's the syntax:
hacker@dojo:~$ command1 && command2
This means: "Run command1, and IF it succeeds, then run command2."
Some examples:
hacker@dojo:~$ touch /home/hacker/file && echo "this will run"
success
this will run
hacker@dojo:~$ touch /file && echo "this will NOT run"
touch: cannot touch '/file': Permission denied
hacker@dojo:~$
That second invocation of touch
failed because the hacker user does not have write access to /file
, so the echo
did not run.
In this challenge, you need to chain the programs /challenge/first-success
and /challenge/second
using the &&
operator.
Try running each command separately first to see what happens (which is that you will not get the flag).
But if you chain them with &&
, the flag will appear!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
You just learned about the &&
operator, which runs the second command only if the first succeeds.
Now let's learn about its opposite: the ||
operator allows you to run a second command only if the first command fails (exits with a non-zero code).
This is called the "OR" operator because either the first command succeeds OR the second command will run.
Here's the syntax:
hacker@dojo:~$ command1 || command2
This means: "Run command1, and IF it fails, then run command2."
Some examples:
hacker@dojo:~$ touch /file || echo "touch failed, so this runs"
touch: cannot touch '/file': Permission denied
touch failed, so this runs
hacker@dojo:~$ touch /home/hacker/file || echo "this will NOT run"
hacker@dojo:~$
The ||
operator is super useful for providing fallback commands or error handling!
In this challenge, you need to chain /challenge/first-failure
and /challenge/second
using the ||
operator.
Go for it!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
As you combine more and more commands to achieve complex effects, the length of the combined prompt quickly gets really annoying to deal with.
When this happens, you can put these commands in a file, called a shell script, and run them by executing the file!
For example, consider our semicolon technique:
hacker@dojo:~$ echo COLLEGE > pwn; cat pwn
COLLEGE
hacker@dojo:~$
We can create a shell script called pwn.sh
(by convention, shell scripts are frequently named with a sh
suffix):
echo COLLEGE > pwn
cat pwn
And then we can execute by passing it as an argument to a new instance of our shell (bash
)!
When a shell is invoked like this, rather than taking commands from the user, it reads commands from the file.
hacker@dojo:~$ ls
hacker@dojo:~$ bash pwn.sh
COLLEGE
hacker@dojo:~$ ls
pwn
hacker@dojo:~$
You can see that the shell script executed both commands, creating and printing the pwn
file.
Now, it's your turn!
Same as last level, run /challenge/pwn
and then /challenge/college
, but this time in a shell script called x.sh
, then run it with bash
!
NOTE: We haven't yet talked about Linux's amazing array of competent command line file editors.
For now, feel free to use the Text Editor
application in Desktop mode (Applications->Accessories->Text Editor
) or the default editor in the VSCode Workspace!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Let's try something a bit trickier!
You've piped output between programs with |
, but so far, this has just been between one command's output and a different command's input.
But what if you wanted to send the output of several programs to one command?
There are a few ways to do this, and we'll explore a simple one here: redirecting output from your script!
As far as the shell is concerned, your script is just another command.
That means you can redirect its input and output just like you did for commands in the Piping module!
For example, you can write it to a file:
hacker@dojo:~$ cat script.sh
echo PWN
echo COLLEGE
hacker@dojo:~$ bash script.sh > output
hacker@dojo:~$ cat output
PWN
COLLEGE
hacker@dojo:~$
All of the various redirection methods work: >
for stdout, 2>
for stderr, <
for stdin, >>
and 2>>
for append-mode redirection, >&
for redirecting to other file descriptors, and |
for piping to another command.
In this level, we will practice piping (|
) from your script to another program.
Like before, you need to create a script that calls the /challenge/pwn
command followed by the /challenge/college
command, and pipe the output of the script into a single invocation of the /challenge/solve
command!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
You have written your first shell script, but calling it via bash script.sh
is a pain.
Why do you need that bash
?
When you invoke bash script.sh
, you are, of course launching the bash
command with the script.sh
argument.
This tells bash to read its commands from script.sh
instead of standard input, and thus your shell script is executed.
It turns out that you can avoid the need to manually invoke bash
.
If your shell script file is executable (recall File Permissions), you can simply invoke it via its relative or absolute path!
For example, if you create script.sh
in your home directory and make it executable, you can invoke it via /home/hacker/script.sh
or ~/script.sh
or (if your working directory is /home/hacker
) ./script.sh
.
Try that here!
Make a shellscript that will invoke /challenge/solve
, make it executable, and run it without explicitly invoking bash
!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
You're well on your way to your new life as a shell scripter!
However, so far, your shellscripts can only be launched from the shell.
Things worked great in the previous level (because you were invoking your script from the bash
shell), but they won't work if your script was being invoked by, say, a program written in Python (or any other language).
When a program is invoked in Linux, the Linux kernel first inspects the file to determine how it should be run.
This does NOT use the extension (which is why you don't have to name your shell scripts with a .sh
extension, or your Python scripts with a .py
extension, or so on).
Rather, Linux looks at the first few bytes of the file for this information.
There are a bunch of different types of programs, but if the program file starts with the characters #!
(often termed a "shebang"), Linux treats the file as an interpreted program, and the contents of the rest of the line as the path to the interpreter.
It then invokes the interpreter with the path to the program file as its only argument.
Consider this shell script:
#!/bin/bash
echo "Hello Hackers!"
This can be executed as:
hacker@dojo:~$ chmod a+x script.sh
hacker@dojo:~$ ./script.sh
Hello Hackers!
hacker@dojo:~$
When ./script.sh
was executed, Linux opened the file, read the first line, extracted /bin/bash
as the interpreter, and executed /bin/bash ./script.sh
to launch the script!
Note, the shebang line must be the VERY FIRST line of the file - no blank lines or spaces before it!
For this challenge, create a script at /home/hacker/solve.sh
that has a proper shebang and outputs "hack the planet".
Remember to make it executable, then run /challenge/run
to verify your script works correctly!
FUN FACT:
Common shebangs you might see:
#!/bin/bash
for bash scripts
#!/usr/bin/python3
for Python scripts
#!/bin/sh
for POSIX shell scripts --- this is a more primitive predecessor to bash
with fewer features, but more compatibility to non-Linux systems!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
You've learned how to make shell scripts, but so far they've just been lists of commands.
Scripts become much more powerful when they can accept arguments!
This might look like:
hacker@dojo:~$ bash myscript.sh hello world
The script can access these arguments using special variables:
$1
contains the first argument ("hello")
$2
contains the second argument ("world")
$3
would contain the third argument (if there had been one)
- ...and so on
Here's a simple example:
hacker@dojo:~$ cat myscript.sh
#!/bin/bash
echo "First argument: $1"
echo "Second argument: $2"
hacker@dojo:~$ bash myscript.sh hello world
First argument: hello
Second argument: world
hacker@dojo:~$
For this challenge, you need to write a script at /home/hacker/solve.sh
that:
- Takes two arguments
- Outputs them in REVERSE order (second argument first, then the first argument)
For example:
hacker@dojo:~$ bash /home/hacker/solve.sh pwn college
college pwn
hacker@dojo:~$
Once your script works correctly, run /challenge/run
to get your flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Now that you can use arguments in scripts, let's make them smarter with conditional logic!
In bash, you can use if
statements to make decisions:
if [ "$1" == "ping" ]
then
echo "pong"
fi
The above, in English, is if the first argument is "ping", print out "pong"
.
The syntax is somewhat unforgiving for a few reasons.
First, you must have spaces after if
(if you're used to a language like C, this is different), after [
, and before ]
.
Second, if
, then
, and fi
must all be on different lines (or separated by semicolons); you can't lump them into the same statement.
It's also a bit weird: instead of endif
or end
or something like that, the terminator of the if
statement is fi
(if
backwards).
Just something you have to remember.
For this challenge, write a script at /home/hacker/solve.sh
that:
- Takes one argument
- If the argument is "pwn", output "college"
- For any other input, output nothing
Example:
hacker@dojo:~$ bash /home/hacker/solve.sh pwn
college
hacker@dojo:~$ bash /home/hacker/solve.sh foo
hacker@dojo:~$
Once your script works correctly, run /challenge/run
to get your flag!
NOTE:
Interested in what else you can check in a condition, other than string equality?
Read all about it with help test
!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Your if
statements so far have handled specific cases, but what about everything else?
That's where else
comes in!
The else
clause executes when the if
condition is false:
if [ "$1" == "hello" ]
then
echo "Hi there!"
else
echo "I don't understand"
fi
Note that the else
doesn't have a condition --- it catches everything that didn't match previously.
It also doesn't have a then
statement.
Finally, the fi
goes after the else
block to denote the end of the whole complex statement!
It is also optional: you didn't have it in the previous level, and you only need it if the logic you're trying to achieve demands it.
Here's a practical example:
if [ "$1" == "start" ]
then
echo "Starting the service..."
else
echo "Unknown command. Use 'start' to begin."
fi
For this challenge, write a script at /home/hacker/solve.sh
that:
- Takes one argument
- If the argument is "pwn", output "college"
- For any other input, output "nope"
Example:
hacker@dojo:~$ bash /home/hacker/solve.sh pwn
college
hacker@dojo:~$ bash /home/hacker/solve.sh hack
nope
hacker@dojo:~$ bash /home/hacker/solve.sh anything
nope
hacker@dojo:~$
Once your script works correctly, run /challenge/run
to get your flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
You've learned how to use a single if
statement to check a condition.
But what if you need to check multiple conditions?
You can use elif
(short for else if
):
if [ "$1" == "one" ]
then
echo "1"
elif [ "$1" == "two" ]
then
echo "2"
elif [ "$1" == "three" ]
then
echo "3"
else
echo "unknown"
fi
Note that you do need a then
after the elif, just like the if
.
As before the else
at the end catches everything that didn't match.
For this challenge, write a script at /home/hacker/solve.sh
that:
- Takes one argument
- If the argument is "hack", output "the planet"
- If the argument is "pwn", output "college"
- If the argument is "learn", output "linux"
- For any other input, output "unknown"
Example:
hacker@dojo:~$ bash /home/hacker/solve.sh hack
the planet
hacker@dojo:~$ bash /home/hacker/solve.sh pwn
college
hacker@dojo:~$ bash /home/hacker/solve.sh learn
linux
hacker@dojo:~$ bash /home/hacker/solve.sh foo
unknown
hacker@dojo:~$
Once your script works correctly, run /challenge/run
to get your flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Terminal Multiplexing
Ever had an SSH connection drop and lose all your work?
Ever wanted to run multiple terminals without opening a dozen windows?
Enter the world of terminal multiplexing!
Let's dive right in!
screen
is a program that creates virtual terminals inside your terminal.
It's somewhat like having multiple browser tabs, but for your command line!
Starting screen is super simple:
hacker@dojo:~$ screen
That's it!
You're now inside a screen session.
It looks exactly like a terminal, but there are new capabilities there, waiting to be discovered.
For this challenge, we've hooked things up so that just launching screen will get you the flag.
Easy!
NOTE:
When you're done with your command line, type exit
or press Ctrl-D
to leave the screen session.
Then screen will terminate and return you to your original shell.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Now we'll start digging in with the magic of detaching!
Imagine you're working on something important over a remote connection, and your connection drops.
With a normal terminal (outside of this awesome dojo environment), everything's gone.
With screen, your work keeps running, and you can reattach later!
You can also detach on purpose, which we'll do in this challenge.
You detach by pressing Ctrl-A
, followed by d
(for detach).
This leaves your session running in the background while you return to your normal terminal.
hacker@dojo:~$ screen
[doing some work...]
[Press Ctrl-A, then d]
[detached from 12345.pts-0.hostname]
hacker@dojo:~$
To reattach, you can use the -r
argument to screen
:
hacker@dojo:~$ screen -r
For this challenge, you'll need to:
- Launch screen
- Detach from it.
- Run
/challenge/run
(this will secretly send the flag to your detached session!)
- Reattach to see your prize
FUN FACT:
Ctrl-A
is screen
's activation key for all of its shortcuts in its default configuration.
All screen
functionality is activated by some command combination starting with Ctrl-A
.
HINT:
Remember: Hold Ctrl and press A, then release both and press d.
HINT:
If you see [detached from...]
, you did it right!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Time for some screen detective work!
If you become an avid screen user, you will inevitably end up with multiple sessions running.
How do you find the right one to reattach to?
Well, we can list them:
hacker@dojo:~$ screen -ls
There are screens on:
23847.mysession (Detached)
23851.goodwork (Detached)
23855.morework (Detached)
3 Sockets in /run/screen/S-hacker.
The identifiers of the sessions are the PID of each respective screen process, a dot, and the name of the screen session.
To attach to a specific one, you use its name or its PID by giving it as an argument to screen -r
.
hacker@dojo:~$ screen -r goodwork
In this challenge, we've created three screen sessions for you.
One of them contains the flag.
The other two are decoys!
You'll need to check each one until you find it.
Don't forget to detach (Ctrl-A d) before trying the next session!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Okay, so far, screen
is just a weird sort of terminal-with-a-terminal.
But it can be much more!
Inside a single screen session, you can have multiple windows, like your browser has multiple tabs.
This can be super handy for organizing different tasks!
These windows are handled with different keyboard shortcuts, all starting with Ctrl-A
:
Ctrl-A c
- Create a new window
Ctrl-A n
- Next window
Ctrl-A p
- Previous window
Ctrl-A 0
through Ctrl-A 9
- Jump directly to window 0-9
Ctrl-A "
- bring up a selection menu of all of the windows
For this challenge, we've set up a screen session with two windows:
- Window 0 has... well, you'll have to switch there to find out!
- Window 1 has a welcome message
Attach to the session with screen -r
, then use one of the key combinations above to switch to Window 1.
Go get that flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Let's try the same thing with tmux
!
tmux
(terminal multiplexer) is screen's younger, more modern cousin.
It does all the same things but with some different key bindings.
The biggest difference?
Instead of Ctrl-A
, tmux uses Ctrl-B
as its command prefix.
So to detach from tmux, you press Ctrl-B
followed by d
.
hacker@dojo:~$ tmux
[doing some work...]
[Press Ctrl-B, then d]
[detached (from session 0)]
hacker@dojo:~$
The commands also differ:
tmux ls
- List sessions
tmux attach
or tmux a
- Reattach to session
For this challenge:
- Launch tmux
- Detach from it.
- Run
/challenge/run
(this will send the flag to your detached session!)
- Reattach to see your prize
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Let's learn to navigate windows in tmux!
Just like screen, tmux has windows.
The key combos are different, but the concept is the same:
Ctrl-B c
- Create a new window
Ctrl-B n
- Next window
Ctrl-B p
- Previous window
Ctrl-B 0
through Ctrl-B 9
- Jump to window 0-9
Ctrl-B w
- See a nice window picker
Tmux shows your windows at the bottom in a status bar that looks like:
[0] 0:bash* 1:bash
The *
shows your current window, and each entry also shows the process that the window was created to run.
We've created a tmux session with two windows:
- Window 1 has the flag!
- Window 0 has your warm welcome.
Go get that flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Pondering PATH
Thus far, you have invoked commands in several ways:
- Through an absolute path (e.g.,
/challenge/run
).
- Through a relative path (e.g.,
./run
).
- Through a bare command name (e.g.,
ls
).
The first two cases, the absolute and the relative path case, are straightforward: the run
file lives in the /challenge
directory, and both cases refer to it (provided, of course, that the relative path is invoked with a current working directory of /challenge
).
But what about the last one?
Where is the ls
program located?
How does the shell know to search for it there?
In this module, we will pull back the veil and answer this question!
Stay with us.
It turns out that the answer to "How does the shell find ls
?" is fairly simple.
There is a special shell variable, called PATH
, that stores a bunch of directory paths in which the shell will search for programs corresponding to commands.
If you blank out the variable, things go badly:
hacker@dojo:~$ ls
Desktop Downloads Pictures Templates
Documents Music Public Videos
hacker@dojo:~$ PATH=""
hacker@dojo:~$ ls
bash: ls: No such file or directory
hacker@dojo:~$
Without a PATH, bash cannot find the ls
command.
In this level, you will disrupt the operation of the /challenge/run
program.
This program will DELETE the flag file using the rm
command.
However, if it can't find the rm
command, the flag will not be deleted, and the challenge will give it to you!
Thus, you must make it so that /challenge/run
also can't find the rm
command!
Keep in mind: /challenge/run
will be a child process of your shell, so you must apply the concepts you learned in Shell Variables to mess with its PATH
variable!
If you don't succeed, and the flag gets deleted, you will need to restart the challenge to try again!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Okay, so things break when you blank out PATH
.
But what about doing something useful with PATH
?
Let's explore how we would, for example, add a new directory of programs to our command repertoire.
Recall that PATH
stores a list of directories to find commands in and, for commands in nonstandard places, we must typically execute them via their path:
hacker@dojo:~$ ls /home/hacker/scripts
goodscript badscript okayscript
hacker@dojo:~$ goodscript
bash: goodscript: command not found
hacker@dojo:~$ /home/hacker/scripts/goodscript
YEAH! This is the best script!
hacker@dojo:~$
If you maintain useful scripts that you want to be able to launch by bare name, this is annoying.
However, by adding directories to or replacing directories in this list, you can expose these programs to be launched using their bare name!
For example:
hacker@dojo:~$ PATH=/home/hacker/scripts
hacker@dojo:~$ goodscript
YEAH! This is the best script!
hacker@dojo:~$
Let's practice.
This level's /challenge/run
will run the win
command via its bare name, but this command exists in the /challenge/more_commands/
directory, which is not initially in the PATH.
The win
command is the only thing that /challenge/run
needs, so you can just overwrite PATH
with that one directory.
Good luck!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
When you type the name of a command, something inside one of the many directories listed in your $PATH
variable is what actually gets executed (of course, unless the command is a builtin!).
But which file, precisely?
You can find out with the aptly-named which
command:
hacker@dojo:~$ which cat
/bin/cat
hacker@dojo:~$ /bin/cat /flag
YEAH
hacker@dojo:~$
Mirroring what the shell does when searching for commands, which
looks at each directory in $PATH
in order and prints the first file it finds whose name matches the argument you passed.
In this challenge, we added a win
command somewhere in your $PATH
, but it won't give you the flag.
Instead, it's in the same directory as a flag
file that we made readable by you!
You must find win
(with the which
command), and cat
the flag out of that directory!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Recall our example from the previous level:
hacker@dojo:~$ ls /home/hacker/scripts
goodscript badscript okayscript
hacker@dojo:~$ PATH=/home/hacker/scripts
hacker@dojo:~$ goodscript
YEAH! This is the best script!
hacker@dojo:~$
What we see here, of course, is the hacker
making the shell more useful for themselves by bringing their own commands to the party.
Over time, you might amass your own elegant tools.
Let's start with win
!
Previously, the win
command that /challenge/run
executed was stored in /challenge/more_commands
.
This time, win
does not exist!
Recall the final level of Chaining Commands, and make a shell script called win
, add its location to the PATH
, and enable /challenge/run
to find it!
Hint:
/challenge/run
runs as root and will call win
. Thus, win
can simply cat the flag file.
Again, the win
command is the only thing that /challenge/run
needs, so you can just overwrite PATH
with that one directory.
But remember, if you do that, your win
command won't be able to find cat
.
You have three options to avoid that:
- Figure out where the
cat
program is on the filesystem. It must be in a directory that lives in the PATH
variable, so you can print the variable out (refer to Shell Variables to remember how!), and go through the directories in it (recall that the different entries are separated by :
), find which one has cat
in it, and invoke cat
by its absolute path.
- Set a
PATH
that has the old directories plus a new entry for wherever you create win
.
- Use
read
(again, refer to Shell Variables) to read /flag
. Since read
is a builtin functionality of bash
, it is unaffected by PATH
shenanigans.
Now, go and win
!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Armed with your knowledge, you can now carry out some shenanigans.
This challenge is almost the same as the first challenge in this module.
Again, this challenge will delete the flag using the rm
command.
But unlike before, it will not print anything out for you.
How can you solve this?
You know that rm
is searched for in the directories listed in the PATH
variable.
You have experience creating the win
command when the previous challenge needed it.
What else can you create?
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Silly Shenanigans
This module will deepen your knowledge of Linux through some shenanigans.
Understanding how features of a system impact its security is a great way to understand its inner workings.
When your shell starts up, it looks for .bashrc
file in your home directory and executes it as a startup script.
You can customize your /home/hacker/.bashrc
with useful things, such as setting environment variables, tweaking your shell configuration, and so on.
You can also use it for evil!
An unwitting victim's .bashrc
is a common target for shenanigans.
Imagine sneaking onto your friend's computer and adding a echo "Hackers were here!"
at the end of their .bashrc
.
That's funny, but the same capability can be used for much more nefarious purposes.
Malicious software, for example, often targets startup scripts such as .bashrc
to maintain persistence into the future!
In this challenge, we'll pretend that you've broken into a victim user's machine!
That user is named zardus
, with a home directory of /home/zardus
.
You, as the hacker
user, have write access to his .bashrc
, and zardus
has read-access to /flag
.
The victim is simulated by the script /challenge/victim
, and you can launch this script at any time to observe the victim logging into the computer.
Can you get the flag?
HINT:
Like the scripts you explored in Chaining Commands, the .bashrc
script is just a shell script.
Adding a new line with a command on it (e.g., echo Hello Hackers
) will get that command executed, so all you really need to think about is what command will get you the flag!
NOTE:
The victim's /home/zardus/.bashrc
will have a lot of stuff already in it: the shell's startup is a complex affair.
Don't panic --- just add your payload to the end and hope for the best!
HINT:
Need to poke around as zardus
to debug your solution?
In practice mode, you can use sudo su --login zardus
to drop into a Zardus session!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
In the previous level, you abused Zardus's ~/.bashrc
to make him run commands for you.
This time, Zardus doesn't keep the flag lying around in a readable file after he logs in.
Instead he'll run a command named flag_checker
, manually typing the flag into it for verification.
Your mission is to use your continued write access to Zardus's .bashrc
to intercept this flag.
Remember how you hijacked commands in the Pondering PATH module?
Can you use that capability to hijack the flag_checker
?
HINT:
Is Zardus getting spooked by your hijack?
He's careful --- he checks for the flag_checker
prompt of Type the flag
.
Make sure your hijack also prints this prompt (e.g., echo "Type the flag"
).
Other than printing that prompt, your fake flag_checker
can either just a) cat
Zardus's input to stdout (e.g., cat with no arguments
) or b) read
it into a variable and echo
it out.
Up to you!
HINT:
Don't forget to make your fake flag_checker
executable, like you learned in the Perceiving Permissions module!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Alright, Zardus has wised up --- why would he have a writable .bashrc
, anyways?
But a more common scenario is that users on the same system, to make it easier to collaborate, will make their home directories world writable.
What's the problem here?
The problem is that a subtlety of Linux file/directory permissions is that anyone with write access to a directory can move and delete files in it.
For example, let's say that Zardus has a world-writable directory for collaboration:
zardus@dojo:~$ mkdir /tmp/collab
zardus@dojo:~$ chmod a+w /tmp/collab
zardus@dojo:~$ echo "do pwn.college" > /tmp/collab/todo-list
And then a hacker comes along and does the following, despite not owning the todo-list file!
hacker@dojo:~$ ls -l /tmp/collab/todo-list
-rw-r--r-- 1 zardus zardus 15 Jun 6 13:12 /tmp/collab/todo-list
hacker@dojo:~$ rm /tmp/collab/todo-list
rm: remove write-protected regular file '/tmp/collab/todo-list'? y
hacker@dojo:~$ echo "send hacker money" > /tmp/collab/todo-list
hacker@dojo:~$ ls -l /tmp/collab/todo-list
-rw-r--r-- 1 hacker hacker 18 Jun 6 13:12 /tmp/collab/todo-list
hacker@dojo:~$
This might seem counterintuitive: hacker
has no write access to the todo-list
but the end result is that they can change the content.
But think about it this way: a file's connection to a directory lives in the directory in the end, and users with write access to that directory can mess with it.
Of course, this has security implications when important directories are world-writable.
In this challenge, for convenience, Zardus opened up his home directory:
zardus@dojo:~$ chmod a+w /home/zardus
As you know, there are lots of sensitive files in that directory such as .bashrc
!
Can you replicate the previous attack with write access to /home/zardus
instead of /home/zardus/.bashrc
?
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Okay, Zardus has wised up!
No more sharing the home directory: despite the reduced convenience, Zardus has moved to sharing /tmp/collab
.
He's made that directory world-readable and has started a list of evil commands to remember!
zardus@dojo:~$ mkdir /tmp/collab
zardus@dojo:~$ chmod a+w /tmp/collab
zardus@dojo:~$ echo "rm -rf /" > /tmp/collab/evil-commands.txt
In this challenge, when you run /challenge/victim
, Zardus will add cat /flag
to that list of commands:
hacker@dojo:~$ /challenge/victim
Username: zardus
Password: **********
zardus@dojo:~$ echo "cat /flag" >> /tmp/collab/evil-commands.txt
zardus@dojo:~$ exit
logout
hacker@dojo:~$
Recall from the previous level that, having write access to /tmp/collab
, the hacker
user can replace that evil-commands.txt
file.
Also remember from Comprehending Commands that files can link to other files.
What happens if hacker
replaces evil-commands.txt
with a symbolic link to some sensitive file that zardus
can write to?
Chaos and shenanigans!
You know the file to link to.
Pull off the attack, and get /flag
(which, for this level, Zardus can read again!).
HINT:
You'll need to run /challenge/victim
twice: once to get cat /flag
written to where you want, and once to trigger it!
Is /tmp
dangerous to use???
Despite the attack shown here, /tmp
can be used safely.
The directory is world-writable, but has a special permission bit set:
hacker@dojo:~$ ls -ld /tmp
drwxrwxrwt 29 root root 1056768 Jun 6 14:06 /tmp
hacker@dojo:~$
That t
bit at the end is the sticky bit.
The sticky bit means that the directory only allows the owners of files to rename or remove files in the directory.
It's designed to prevent this exact attack!
The problem in this challenge, of course, was that Zardus did not enable the sticky bit on /tmp/collab
.
This would have closed the hole in this specific case:
zardus@dojo:~$ chmod +t /tmp/collab
Of course, shared resources like world-writable directories are still dangerous.
Much later, in the Race Conditions of the Green Belt material, you'll see many ways in which such resources can cause security issues!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Poor Zardus; you've hacked him pretty heavily.
But he's wisened up and secured his home directory!
Game over?
Not quite!
One of the things that people often don't think about when there are multiple accounts on one computer is what kind of data their command invocations leak.
Remember, when you do ps aux
, you get:
hacker@dojo:~$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
hacker 1 0.0 0.0 1128 4 ? Ss 05:34 0:00 /sbin/docker-init -- /bin/sleep 6h
hacker 7 0.0 0.0 2736 580 ? S 05:34 0:00 /bin/sleep 6h
hacker 102 0.4 0.0 723944 64660 ? Sl 05:34 0:00 /usr/lib/code-server/lib/node /usr/lib/code-serve
hacker 138 3.3 0.0 968792 106272 ? Sl 05:34 0:07 /usr/lib/code-server/lib/node /usr/lib/code-serve
hacker 287 0.0 0.0 717648 53136 ? Sl 05:34 0:00 /usr/lib/code-server/lib/node /usr/lib/code-serve
hacker 318 3.3 0.0 977472 98256 ? Sl 05:34 0:06 /usr/lib/code-server/lib/node --dns-result-order=
hacker 554 0.4 0.0 650560 55360 ? Rl 05:35 0:00 /usr/lib/code-server/lib/node /usr/lib/code-serve
hacker 571 0.0 0.0 4600 4032 pts/0 Ss 05:35 0:00 /usr/bin/bash --init-file /usr/lib/code-server/li
hacker 1172 0.0 0.0 5892 2924 pts/0 R+ 05:38 0:00 ps aux
hacker@dojo:~$
But what would happen if one of the arguments of one of those commands was something sensitive, like the flag or a password?
This happens, and nefarious users sharing the same machine (or somehow otherwise listing processes on it) can steal that data and use it!
That's what this challenge explores.
Zardus is using an automation script, passing his account password to it as an argument.
Zardus is also allowed to use sudo
(and, thus, to sudo cat /flag
!).
Steal the password, log in to Zardus' account (recall the su
command from the Untangling Users module), and get that flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Even without making mistakes, users might inadvertently leave themselves at risk.
For example, many files in a typical user's home directory are world-readable by default, despite frequently being used to store sensitive information.
Believe it or not, your .bashrc
is world-readable unless you explicitly change it!
hacker@dojo:~$ ls -l ~/.bashrc
-rw-r--r-- 1 hacker hacker 148 Jun 7 05:56 /home/hacker/.bashrc
hacker@dojo:~$
You might think, "Hey, at least it's not world-writable by default"!
But even world-readable, it can do damage.
Since .bashrc
is processed by the shell at startup, that is where people typically put initializations for any environment variables they want to customize.
Most of the time, this is innocuous things like PATH
, but sometimes people store API keys there for easy access.
For example, in this challenge:
zardus@dojo:~$ echo "FLAG_GETTER_API_KEY=sk-XXXYYYZZZ" > ~/.bashrc
Afterwards, Zardus can easily refer to the API key.
In this level, users can use a valid API key to get the flag:
zardus@dojo:~$ flag_getter --key $FLAG_GETTER_API_KEY
Correct API key! Do you want me to print the key (y/n)? y
pwn.college{HACKED}
zardus@dojo:~$
Naturally, Zardus stores his key in .bashrc
.
Can you steal the key and get the flag?
NOTE:
When you get the API key, just execute flag_getter
as the hacker
user.
This challenge's /challenge/victim
is just for theming: you don't need to use it.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Daring Destruction
With great power comes great responsibility.
Over the course of the Luminarium, you have learned how to navigate, manipulate, and control a Linux machine.
Before we send you off into the wild it, is only fair that we end with some words of caution—and a little mayhem.
Below is a non-exhaustive collection of seemingly innocent actions that, when executed on a real system, can lead to catastrophic data-loss, denial of service, or even unrecoverable system corruption.
All are recoverable on pwn.college (by restarting your container), but they are very real dangers on an unsuspecting computer.
Practice them, marvel at them, do not run them on anything that matters.
As you learned in the Processes and Jobs module, whenever you start a program the Linux operating system creates a new process.
If you create processes faster than the kernel can handle, the process table fills up and everything grinds to a halt.
This new process (e.g., of an ls
invocation) is ``forked'' off of a parent process (e.g., a shell instance).
Thus, the induced explosion of processes is called a "Fork Bomb".
You have the tools to do this:
Each copy will launch two more, and each of those will launch two more, and you will flood the system with so many processes that new ones will not be able to start!
This challenge contains a /challenge/check
that'll try to determine if your fork bomb is working (e.g., if it can't launch new processes) and give you the flag if so.
Make sure to launch it (in a different terminal) before launching your attack; otherwise you won't be able to launch it!
NOTE:
Needless to say, this will render your environment unusable.
Just restart the challenge (or start a different one) to get things back to a usable state!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
The available space in /home/hacker
in this container is a measly 1 gigabyte.
In this level you will clog up /home/hacker
with so much junk that even a tiny 1 megabyte file can't be created.
When this happens, your workspace becomes unusable.
We'll practice inducing this in this challenge, and then expand on it a bit later.
How to fill the disk?
There are so many ways.
Here, we'll teach you the yes
command!
hacker@dojo:~$ yes | head
y
y
y
y
y
y
y
y
y
y
hacker@dojo:~$
The yes
outputs y
over and over forever.
The typical usage is to automate confirmation prompts ("Are you sure you want to delete this file?") using piping, but we'll use it here to make a massive file full of "y" lines.
Just redirect yes
to a file in your home directory, and you'll fill your disk in a minute or two!
This challenge forces you to fill the disk and then clean up.
The process:
- Fill your disk.
- Run
/challenge/check
. It will attempt to create a 1 megabyte temporary file. If that fails, you pass the first stage and the checker will ask you to free the space.
- Delete the file you made (with
rm
) to clear up the space.
- Run
/challenge/check
a second time. If it can now create the temporary file (i.e., you successfully cleaned up your home directory), you’ll receive the flag.
Why two stages?
Your home directory persists across challenge instances.
If we let you keep it full, your pwn.college will stop working.
This is by far the most common cause of weird issues on pwn.college!
HELP IT BROKE!
If you fill the disk and don't clean it up afterwards, you'll need to ssh
in to fix things (by removing that file).
This is a bit tricky, but we describe how to do it under "Connecting over SSH" in the Getting Started module.
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Want to wipe the slate clean and start over?
You can!
hacker@dojo:~$ ls /
bin etc blah blah blah
hacker@dojo:~$ rm -rf /
hacker@dojo:~$ ls /
bash: ls: command not found
hacker@dojo:~$
What happened here?
As you recall, rm
removes files.
The -r
(recursive) flag removes directories and all files containing them.
The -f
(force) flag ignores any errors the rm
command runs into or compulsions that it may have.
Combined and aimed at /
, the results are catastrophic: a full wipe of your system.
On a modern system, things aren't that simple, but you'll figure that out when you see it.
In this challenge, you will do something that you might never do again: wipe the whole system.
We've actually modified things a bit to keep your home directory safe (normally, it would get wiped as well!), but otherwise, all that stands before you and the flag is your willingness to wipe the drive.
But before you wipe it all, make sure to start /challenge/check
so that it can watch the fireworks (and give you the flag)!
NOTE:
The rm
will take a while to run.
There's a lot to delete!
NOTE:
There are various technical reasons why you're unlikely to be able to delete everything, including the technique we use to protect your home directory in this level.
Don't worry, you'll be doing enough damage!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
Let's dig into the effects of blowing away your whole filesystem.
You're now an experienced rm
er, but previously, /challenge/check
printed the flag out for you when you cleared away the clutter of the filesystem.
What if it hadn't?
Without cat
, how would you read that /flag
?
Recall, from the Digesting Documentation module, that some shell commands are builtins.
While ls
, cat
, and such aren't, read
(which, if you recall from the Shell Variables module, can read files!) is.
That means that, even if you blow away your whole filesystem, as long as you have an already-running instance of bash, you can read files!
This challenge will force you to try it.
It's almost the same as the previous one, but you must read the flag yourself after you destroy the system.
After you rm
everything, your previously-launched /challenge/check
will restore the /flag
file and make it readable.
Then you can read
it!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
So you can live without cat
!
How about without ls
?
This time, /challenge/check
will restore the flag to a randomly-named file.
You'll need to find it without reaching for your ls
command.
There are a lot of ways to solve this challenge.
echo
is a builtin, and you can File Glob an argument to it to expand to all files!
For example, echo *
will print out the names of all of the files in the current directory.
Similarly, you can use tab-completion (hit tab a few times) of an argument to have the shell list possible files for you.
Whatever route you use, find the randomly-named file that /challenge/check
makes in /
after you rm
, read it, and get the flag!
Connect with SSH
Link your
SSH key, then connect with:
ssh hacker@pwn.college
This scoreboard reflects solves for challenges in this module after the module launched in this dojo.