Going through an old hardware stash, I've noticed a harddisk that was part of a Solaris test system of mine I disassembled 10 years ago. The disk contains an interesting artifact I implemented at that time: a proof-of-concept for capturing user entered passwords with DTrace.
Proof of Concept¶
With Solaris 10 and later, the natural and very convenient tool for this job is DTrace. DTrace comes with several providers, e.g. you can install a probe for specific system calls or even specific userspace functions.
The challenge with this is that in contrast to - say - syscall
tracing, userspace tracing always has a significant overhead.
pid provider requires a concrete process
id (PID) to trace, one cannot directly trace all userspace
processes of an executable with that provider.
Fortunately, one can work around this: write two DTrace scripts.
The first installs a probe that is executed for each exec of a -
say - ssh process. In the probe's action the just started process
is stopped (to avoid a race condition) and the second DTrace
script with some pid provider userspace probes is started for
the new PID. The first action of this script is to restart the
stopped process (see also Destructive Actions, Dtrace
Manual). By default, dtrace only allows safe
actions, but it also supports enabling unsafe ones. Clearly,
running external commands from a dtrace script and recursively
dtrace isn't safe and can escalate quickly.
The remainder of the challenge is then to identify the interesting functions that are called by the SSH and rlogin daemon for obtaining the user entered password.
The wrapper script (part 1):
1 2 3 4 5 6 7 8 9 10
The actual script for ssh (part 2):
1 2 3 4 5 6 7 8 9 10 11 12 13 14
prun is a Solaris command line utility for restarting
a stopped process (think:
kill -CONT). There is also room for
improvement: we don't really need to trace this ssh process until
it exits. For our purposes, it is sufficient to trace it until -
say - it returns from
ssh_login. Thus, we can add another probe
for just that event that executes the exit-Action, such that this
dtrace process stops all tracing and exits. This doesn't
interrupts the traced process.
ssh 1234: sehrgeheimespassword ssh`read_passphrase ssh`input_userauth_info_req+0xef ssh`dispatch_run+0x49 ssh`ssh_userauth2+0x19e ssh`ssh_login+0xa6 ssh`main+0xbd2 ssh`0x80586ba
Similar script for rlogin:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
CPU ID FUNCTION:NAME 0 1 :BEGIN 0 42222 getpassphrase:return sehrgeheimespassword 0xd0ea86ec libnsl.so.1`S_tab+0x2e libnsl.so.1`S_tab+0x282 0xd0c10bd6 libnsl.so.1`_C0095A10+0xa3 libnsl.so.1`_C0095A14+0x50 bash`0x8052829 bash`0x8053b59 bash`0x8052137 bash`0x8051e3a
How to read the disk¶
The old Solaris system was built with left-over hardware that was
old even 10 years ago. That means the disk is a 80 GB
parallel-ATA one. Thus, I've used a parallel-ATA to USB adaptor
to connect the old disk to a modern Fedora 27 Linux system. A
quick inspection shows that the disk contains some BSD style
partition slices that
fdisk doesn't understand but the kernel
does such that some additional
/dev/sdXY files are created. The
kernel even correctly detects the UFS magic - but fails to mount
# mount -o noatime /dev/sdf5 /mnt/old mount: /mnt/old: unknown filesystem type 'ufs'.
This is due to the ufs kernel module missing - Fedora 27 doesn't install it, by default. Thus:
# dnf -y install kernel-modules-extra
With the ufs kernel module available the mount succeeds:
# mount -t ufs -o noatime /dev/sdf5 /mnt/old mount: /mnt/old: WARNING: device write-protected, mounted read-only.
The module also prints some warnings to the kernel log:
kernel: ufs: ufs was compiled with read-only support, can't be mounted as read-write kernel: ufs: You didn't specify the type of your ufs filesystem mount -t ufs -o ufstype=sun|sunx86|44bsd|ufs2|5xbsd|old|hp|nextstep|nextstep-cd|openstep ... >>>WARNING<<< Wrong ufstype may corrupt your filesystem, default is ufstype=old
The warning might look scary, but the filesystem is mounted read-only, thus a wrong fs-type can't really damage the filesystem. At least for OpenSolaris post 10-ish/Solaris 11 pre-release the default ufs type is good enough and all files can be accessed.