Book Image

Penetration Testing with the Bash shell

By : Keith Harald Esrick Makan
Book Image

Penetration Testing with the Bash shell

By: Keith Harald Esrick Makan

Overview of this book

Table of Contents (13 chapters)

Using I/O redirection


I/O redirection is one of the easiest things to master when it comes to the bash scripting. It's as simple as knowing where you want your input to go and where it's coming from. It may seem like this is a very interesting topic and you might not see why you need to know this, but redirecting output—if you truly get to understand what it's all about—will be what you're doing on your command line almost 80 percent of the time! It's essentially the one thing that allows you to combine different utilities and have them work together quite effectively on the command line in a compact and simple way. For instance, you may want to search through the output from nmap or tcpdump or a key-logger by feeding its output to another file or program to analyze.

Redirecting output

To redirect the output of one program that is invoked from the command line into a file, all you need to do is add a > symbol at the end of the command line for the said program and proceed this with a filename.

For instance, using the most recent example, if you want to redirect the output of the find command to a file named something like writeable-files.txt, this is how it would be done:

find / -writeable > writeable-files.txt 

There is one small detail about this kind of I/O redirection though, as with many of the common bash shorthands: there's usually quite a bit going on under the hood. If used as demonstrated previously, the only output that will actually appear in the chosen file (for the previous example it is writeable-files.txt) would be the output actually printed to the standard output file that is commonly referred to as file descriptor 0, which is the default destination for normal output.

Note

File descriptors are constructs in operating systems that represent access to an actual section of the physical storage mechanism or a file. File descriptors are nothing more than numbers that are associated to other data structures managed by the kernel that represent open files. Each process has its own "private" set of file descriptors.

Whenever you open a file using a text editor or generally perform any editing of a resource stored on a physical medium, a file descriptor representing the involved file is passed to the kernel through a system call. The kernel then uses this number to look up other details about the file in a data structure only the kernel should have access to.

The file descriptor's primary purpose is to help abstract and logically isolate details about the actual process involved with accessing the storage mechanism. After all, reading and writing to files is quite an essential operation to computer systems and it would be quite tedious—and error-prone—to do many things if writing to a file meant accommodating actions such as spinning/stopping the hard drive disk, interpreting different filesystems' organization, and handling read/write errors!

Output destined for or coming from any file descriptor can be redirected, provided that you have the correct access rights from your bash shell! Here's the code to do that:

[command line] a>&b > [output file]

In the previous command, a and b are both file descriptors. If a or b are not explicitly set, then they default to 1, which is standard output.

What about output destined for the standard error file? How do you redirect that? Well as it turns out this is pretty easy too, and here's the code to do it:

[command] 2> [output file]

As you can see in the previous example, we specified the redirection symbol as 2>, which simply means the following:

Redirect everything from file descriptor 1 to the file called writeable-files.txt.

You can also combine or bond the two standard output files, namely send the output of both input and output to a single file if there is anything interesting being printed to the standard error output. It is done using the following command:

[command line] 2>&1 > [output file]

There's also a simpler abbreviation for this and here's what it looks like:

[command line] &> [output file]

This means the following:

Redirect everything from file descriptor 1 to file descriptor 0 and then redirect everything from file descriptor 0 to [output file].

The previous redirection commands will all assume that the specified file does not exist; if it does, the output being directed will overwrite whatever is currently in the file. What will you do if you'd like to append text to a file? Well, the following command shows how that works:

[command line] [&][n] >> [&][m] [filename.txt]

As before, the &, n, and m notations are all optional parameters and work exactly the same as they did in previous examples.

Redirecting input

If you can redirect output, you should also be able to redirect input using the following command:

[command line] < [input file | command line]

Its pretty straightforward really: if > means redirect output, then < means redirect the 'output' of the right operand, which from the perspective of the left operand is input.

As with output redirection, you can also control which file descriptors you'd like to include in the redirection using the following command:

[command line] <[n] [input file | command line]

In the previous command, [n] is the file descriptor number, as with output redirection. The following are a few examples you can test out on your terminal console:

  • keylogs.txt < /dev/`tty`

    The preceding command redirects all the input written to the terminal into the file called keylogs.txt. It achieves this by getting the current tty device associated to the terminal console using the tty command.

  • wc –l < /etc/passwd

    The preceding command redirects input from the /etc/passwd file that contains all the usernames and other user account-orientated details to the wc command, which is used to count lines, file sizes, and other file attributes. Using the –l switch causes the wc command to count all the lines, or more specifically all the new line characters it encounters, until an end of file (EOF) sentinel is reached.