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.