How to break out of restricted shells with tcpdump

During security assessments we sometimes obtain access to a restricted shell on a target system. To advance further and gain complete control of the system, the next step is usually to break out of this shell. If the restricted shell provides access to certain system binaries, these binaries can often be exploited to perform such a break out. Here we would like to show an interesting example of such a break out by using the tcpdump binary.

Imagine that from your restricted shell you cannot do anything else than calling the tcpdump binary with its usual parameters. Everything else is prevented by the shell, e.g. other binaries cannot be called, environment variables cannot be set, and break out mechanisms for commands passed to an underlying system shell are filtered. How can we then use tcpdump and especially the parameters it provides to break out of the restricted shell?

A look at the man page of tcpdump shows that the -z parameter can be used to execute a so-called postrotate-command, i.e.

-z postrotate-command
    Used in conjunction with the -C or -G options, this will make tcpdump run " postrotate-command
    file " where file is the savefile being closed after each rotation. For example, specifying -z
    gzip or -z bzip2 will compress each savefile using gzip or bzip2
    Note that tcpdump will run the command in parallel to the capture, using the  lowest  priority
    so that this doesn't disturb the capture process.

    And  in  case  you would like to use a command that itself takes flags or different arguments,
    you can always write a shell script that will take the savefile name  as  the  only  argument,
    make the flags & arguments arrangements and execute the command that you want.

The mentiond -G option will do the following:

-G rotate_seconds
    If specified, rotates the dump file specified with the -w option every rotate_seconds seconds.

Overall, by using the -z paramter we can execute a command of our choosing that is applied to a savefile. However, as the last paragraph states, we cannot provide arguments to this command, since we somehow would need to provide a shell script with our content (and that would be restricted by the shell).

Savefiles are specified via the -w parameter. The following can be found on the man page for this parameter:

-w file
    Write  the  raw  packets to file rather than parsing and printing them out.  They can later be
    printed with the -r option.  Standard output is used if file is ``-''.

    This output will be buffered if written to a file or pipe, so a program reading from the  file
    or  pipe may not see packets for an arbitrary amount of time after they are received.  Use the
    -U flag to cause packets to be written as soon as they are received.

The idea is now to use tcpdump to capture network traffic sent by us and containing a malicious script to be executed. With the -w parameter the malicious script is saved to a file and with the -z parameter a corresponding script interpreter is called. Note that it makes sense to additionally provide the -U flag to directly save the network packets to the capture file (as stated above).

Moreover, it makes sense to also supply the -A and -n paramter.

-A     Print each packet (minus its link level header) in ASCII.  Handy for capturing web pages.
-n     Don't convert addresses (i.e., host addresses, port numbers, etc.) to names.

Finally, it should be noted that tcpdump will (even if the -A option is used) prepend some headers to the captured network traffic. Hence, to execute some script command included in the capture file, we would need an interpreter that is liberal with regard to bad characters. One of the scripting languages that is optimal for such a case is PHP. If PHP is not installed on the system, you may use other languages, but we will stick with PHP here.

Putting everything together, our tcpdump command should look like this:

tcpdump -n -i any -G 1 -z /usr/bin/php -U -A udp port 1234

The filter ‘udp port 1234’ can be adjusted depending on the firewall rules of the system. Overall, it should only make sure that we do not capture arbitrary network traffic but only our well-crafted network packet.

Now that our tcpdump is running, we have to send the network packet with our PHP script content. This can be done in the following way:

echo "<?php system('id');?>" | nc -u  1234

Therefore, we can now execute arbitray commands on the system (in the context of the permissions provided by the tcpdump binary for the executed command) and are not restricted anymore by the initial shell. And of course, you could also execute a reverse shell that gives you complete control over the system in the context of the user under which the tcpdump binary is executed.

Finally, a great list of binaries that may be used to break out of restricted shells or environments can be found here for Linux systems and here for Windows systems.

Oliver & Birk

Edit (01.08.2019): It should be noted, though, that the tcpdump binary (usually) sets its Linux capabilities such that it does not have many permissions. Therefore, after breaking out of the restricted shell, you may have to identify additional ways to escelate your privileges further (e.g. by writing a cron job file).