Tips for the CTF

The aim of this page, which may be updated during the semester, is to give you some hints for the CTF. Remember that each team has to manage its own virtual machine, running some vulnerable services on a Gentoo Linux operating system, hence you may need to know some useful commands to list or kill processes currently in execution, find out active connections on your machine, connect to a MySQL database via command line and so on.

Furthermore, during the CTF you should develop some scripts to avoid to perform manually the attacks and the submission of the flags during each round, so we will show you how to perform easily HTTP requests using Python.

Clearly this cannot be a comprehensive guide: if you need more information, please refer to the manual page of the related command or ask Google 😀
If you think that something really important is missing or you haven’t understood something, feel free to post a comment!

Change your password

The first thing you have to do when the competition starts is to change the root password of your virtual machine: since you will connect directly as root with ssh, it is enough to use the command passwd.

Switch user

In your machine there will be a different user for each service: since it is a good habit to use root only when strictly necessary, you may consider the possibility of switching to the user that owns the service on which you want to work. This can be done with the command su - ; if you want to go back to the previous user, you can use the combination CTRL + D or the command exit.

The manual

If you need to know more information about a command, you must simply type man <command_name> on the command line. You can search for a word typing /<word> once the manual page is open and, if you press n, the next occurrence will be shown. You can move inside the page using arrow keys. When you have finished, type q to exit.

You can also get the documentation of many functions of the standard C library using man 3 <function_name>.

Do you want to know more about man? Read the manual of the manual :)

Files search

find is a very powerful tool for searching files inside a given path with some particular properties: for instance you can ask to list files that belong to a given user, search for files on which you have particular permissions and so on. You can also combine different properties using logical operators.

For instance, this command allows you to find regular files (not directories) owned by the specified user that are readable by everybody:

Instead, if you want to search, only in the working directory, for files whose names start with .b or with permissions exactly 755, we can use:

Refer to the manual if you want to know more about this utility.

Process management

A common way to obtain complete information about the processes currently in execution on the system consists on using ps with options aux. Here is an example of (part of) the result produced by the command:

The fields to which you may be interested are probably USER, PID and COMMAND that respectively denote, for each process, the user that has started it, its process identifier and the command given to start it.

You can kill a process using the command kill and specifying the PID: for instance, if we want to kill nano:

If you want to kill processes that are not owned by your current user, you have to switch to the one that owns the process (or to root).

You can even specify to kill processes with a (partially) given name or that belong to some specified users and so on using pkill: please refer to the manual for more information.

Network connections

Information about active network connections can be seen using netstat as follows:

Column Proto reports the transport protocol in use, Local Address and Foreign Address denote, respectively, addresses of the parts involved in the connection, State is the state of the connection (except for connectionless protocols) and PID/Program name shows the PID and the name of the program that has created the connection. The last column shows information only of processes owned by the user that gives the command: if you want to see them all, you have to run the command as root.

For instance, the first row says that there is a Python program listening on the port 8000, while the fifth says that there is a connection on the interface with IP address 192.168.69.22 on the port 22 with a machine with address 192.168.69.159 on the port 51987.

As we have seen during the course, you can quickly open a connection with an entity using nc (netcat), specifying the IP address (or the domain name) and the port. An example follows, referred to a service of the previous year:

Apart from this, you can also use nc to listen for a connection and so on: if you want to know more, check the manual.

Furthermore, you may want to see the traffic you’re receiving: in this case, use the command tcpdump seen during the course.

Init scripts

Init scripts are used to start processes at boot time (e.g. the web server nginx, SSH server and so on). Init scripts for system services are located in the /etc/init.d/ folder: if you want to start, stop or restart a service it is enough to use the command /etc/init.d/<service> <mode> where <service> is the name of the service on which you want to operate and <mode> is the operation type (e.g. start, stop or restart to perform the three operations listed above).

If you want to add or remove an init script, use the command rc-update with the add or del argument, followed by the service and the runlevel (typically default is used as runlevel). For instance:

If you want to add custom init scripts, you may add them into /etc/local.d/.

For additional information about custom init scripts, you may refer to the related Gentoo documentation page.

Remote file copy

If you want to copy some files from your virtual machine to the computer you’re using in the lab or viceversa, scp is what you need. As for the standard cp command, first you have to specify the source and then the target: to denote a remote location you have to use the syntax <user>@<IP_or_domain_name>:<path>.
For instance, if you want to copy a file to a remote machine, you can proceed as follows:

Viceversa, if you want to copy a remote file in your working directory:

scp allows also to copy recursively entire directory trees (using the option -r) and so on: check the manual if you need more advanced options.

Command Line Editors

Copying a file to your computer each time you have to modify it and then moving it back to the virtual machine is not only boring: you also have to pay attention that the attributes of the copied file, such as user and group owner or permissions, are the same of the previous version. Using a command line editor is not a bad idea at all: one of the simplest editors available is nano. If you want to create or open a file, simply type nano <path_to_file> on the command line, while to perform commands like saving the file, quit from the program and so on, you need to know the relative combinations of keys: this page lists the ones used to perform the most common actions.

There are also more advanced command line text editors, such as vim: you’re free to use it if you want to make lavish happy, but remember that you have only 3 months to play the CTF 😀

Tcpserver

In the CTF we use tcpserver to allow the use of C-compiled programs by remote users without having to deal manually with sockets: when a connection is received on the port associated to a certain service, tcpserver runs the program with file descriptors 0 and 1 (that denote standard input and standard output) reading from and writing to the network. Suppose you have the following program:

You can bind the service to a port on a specific address typing tcpserver <options> <ip_address> <port> <absolute_path_to_executable>. For instance:

Now you can use netcat, for example, to interact with the service:

Actually, during the CTF you shouldn’t need to run the command tcpserver by yourself (unless, for some reason, tcpserver crashes): when you fix a vulnerability in a C program, it is enough to replace the executable of the service with the new one to use it.

Interaction with MySQL via command line

During the competition you may need to interact with the MySQL DBMS installed on your virtual machine for different reasons: for instance, to find out where are located the flags of services that rely on a database for data storage, in order to plan your attack.

You can open a simple SQL shell using the command mysql -u <user> -p, where user is the name of a user registered in the DBMS: you may also specify directly the password of the user after the option -p or insert it interactively.

Here are some useful commands: to see databases available on the system, you can use show databases.

If you want to see information about tables of a certain database or columns of a particular table, you can proceed as follows.

If you want to use a particular database, so that each time you don’t have to specify the DB name before the table on which you want to operate, give the command use <database>. Of course you can also execute standard SQL queries to retrieve, insert, update or delete data.

If you need to know more about this tool, on the web you will find a lot of information :)

HTTP requests with Python

When you find a flag, you have to submit it on a login protected site to earn points and rise in ranking: doing it manually for all the flags is really annoying, since you will have to collect as much flags as you can during the different rounds in which the competition is divided.

Manual submission is ok at the beginning of the competition, but remember that you are expected to write your own scripts to perform attacks automatically at each round against all your opponents. You can easily perform HTTP requests using a Python module that is installed on your virtual machines, Requests.

Consider a website that consists of the following pages:

  • login.php: if nothing is received via POST, a form with fields username and password is shown, otherwise the script checks the correctness of authentication information. If credentials correspond to an existing user, the access to the page submit.php is granted.
  • submit.php: if nothing is received via POST, a form with fields flag and service is shown, otherwise the script performs controls on the flag and, if there are no errors, it is marked as submitted. An error message is shown if a request comes from a non authenticated user.

Here is a simple script that performs authentication and submits a flag.

First of all a Session object is created: this kind of object allows you to execute multiple requests without having to deal manually with cookies that are used for session management. Then the script executes a POST to the login page, using the parameters required for authentication, and then submits the flag related to a certain service. Notice that the parameter data (a dictionary) is indispensable when you do a POST.

When you do a request (GET or POST), the method returns an object that represents the answer. You can print the content of the response (without HTTP headers, so the HTML code of the page) as follows:

If you need more information, you can refer to the documentation on the website of the module, linked above.

Sockets with python

Communication over a network is achieved through sockets, which represent the communication endpoints used by programs to send and receive messages, similarly to file descriptors and other system resources.

We will focus on the IPv4 address family (AF_INET) and on stream sockets (SOCK_STREAM) as they are the most commonly used ones. The following example creates a stream IPv4 socket and use it to connect to www.google.com:

Bytes can be sent and received through send and recv primitive. However it is important to remember that these primitives work with the network buffer and it is not guaranteed that all the bytes are sent or received after one invocation. It is the programmer responsibility to invoke the functions many times, until all the bytes have been transmitted.

In order to experiment with sockets we run nc listening on port 10000:

Then we connect to it and we send string ‘ciao’ as follows:

Notice that send returns the number of bytes read, 4 in this case. So we know that all the bytes haves been transmitted. On the shell we see that ‘ciao’ is correctly received by nc:

Since we are not guaranteed that all bytes are sent in one send we need to iterate until the whole string has been sent, as follows:

The above function counts how many bytes have been sent so far and goes on until the whole string has been sent. Notice the use of msg[totalsent:] to send what has not yet been sent.

Similarly, when we receive a message we need to iterate until all the bytes have been received. Sometimes, instead of reaching a specific number of bytes it is useful to read until a certain string is received (for example a newline). The following function checks both length and a specific string:

For example if we invoke:

The function will loop until 100 bytes are read or a newline is found in the bytes read so far. We can experiment again with nc, writing an answer back to our program. We obtain the following:

The string ‘ciao ciao 123’ is what we have written on the terminal:

The following code implements a Python class with basic functions to quickly interact with a remote application

Simple echo server

The following example shows a simple multi-threaded echo server. In particular:

  • the primitive bind binds the server socket to a specific address;
  • the primitive listen listens for connections;
  • new connections are accepted through the primitive accept which returns a new socket for each new connection. This allows for independently dealing with multiple connections.

Notice that each connection is handled by a different thread so to allow many connections at a time.

We can run the server and connect to it using nc from multiple terminals. Everything we write will be sent back. Connections will be dealt with independently. For example:

Exercises

  1. Run the simple echo server and connect to it from multiple nc clients. Notice that this is possible because of multithreading
  2. Remove multi-threading and observe that now the server can only handle one connection at a time
  3. Write a program that connects to the echo server, sends a string and reads the answer
  4. Modify the echo server so that it changes some words before echoing them back (note that this requires to change the way the server reads which, in the example, is 1 byte at the time)

Leave a Reply

Your email address will not be published. Required fields are marked *