Dump process i/o

Spawn and trace a process using the ptrace system call. By interpreting i/o operations, all user interaction and communication can be dumped to disk.

fdtrace will spawn an external binary, attach to it using the ptrace system call, listen for i/o calls, and dump all read or written data to a file. By observing p?(read|write)v? invocations, all ordinary file operations, user interaction, and network communication can be intercepted (bypassing possibilities exist, though). Currently supported architectures are x86_64 and ARM_EABI.

One could argue that this tool might be (ab-)used to replace sensitive binaries such as ssh in order to covertly dump passwords and private keys. However, the same could be achieved by using a patched or custom binary or by e.g. an strace wrapper for:

$ strace -o dump -e trace=file,read,write -e read=all -e write=all

So you should consider fdtrace as an redundant tool for already existing and widely available functionality. Its main purpose is thus the illustration of ptrace() usage with inspecting the tracee’s registers and memory.

I/O tracing usage example: SSH

In case you want to call and trace e.g. /usr/bin/ssh (absolute path), build the corresponding tracer with:

$ make TARGET=/usr/bin/ssh #CFLAGS=-DNDEBUG
$ sudo chown root:root fdtrace-ssh
$ sudo chmod 04755 fdtrace-ssh

Note that the binary to call has to be defined in advance (one could try to find it according to argv[0], though). In order to ensure superuser (i.e. tracing) permissions, a root setuid bit can be used (as above) or the command itself could be started using sudo in the next step.

Given runtime arguments will be then passed along to the chosen child process:

$ ./fdtrace-ssh foouser@192.168.1.2
foouser@192.168.1.2's password:
$ logout
Connection to 192.168.1.2 closed.

The input and output of each filedescriptor will be written to /tmp/.pid.fd:

$ cat /tmp/.3422.2 | head -n 1
<Connection to 192.168.1.2 closed.
$ hexdump -C /tmp/.3422.3 | head -n 1
00000000  3e 7f 45 4c 46 02 01 01  00 00 00 00 00 00 00 00  |>.ELF...........|
$ cat /tmp/.3422.4 | head -n 1
>|1|guO7PbLLb5FWIpxNZHF03ESTTKg=|r002DA8L2JUYRVykUh7jcVUHeYE= ssh-rsa AAAAB3Nz[...]
$ cat ~/.ssh/known_hosts | head -n 1
|1|guO7PbLLb5FWIpxNZHF03ESTTKg=|r002DA8L2JUYRVykUh7jcVUHeYE= ssh-rsa AAAAB3Nz[...]
$ cat /tmp/.3422.5 | head -n 1
<foouser@192.168.1.2's password: >p>4>s>s>w>0>r>d>

The SSH password can be seen in plaintext as individual chars written to the terminal i/o file descriptor. Over the network, this is of course encrypted – length and timing attacks on SSH exist, though.

Code & Download