Chklinkcnt is a small tool I wrote to find evidence that a kernel based rootkit tried to hide something in the local filesystem. The name is meant to be spoken "check link count". Many unix and linux rootkits allow directories to be hidden. But often the link count of the father directory is not corrected. The idea of chklinkcnt is to traverse all directories of a linux or unix filesystem and in each directory count the directory entries and compare the number with the link count of the current directory. If these don't match something might be wrong. Sounds simple? It really is!
Important: we use the assumption that the link count of a directory is the number of subdirectories plus 2 (for '.' and '..'). This is dependent on the filesystem and might not hold. It currently works for ext2/3, though. This also means that special file systems like /proc will give many false positives.
bibo:~ # chklinkcnt dir '/proc/bus' has 5 hard links but 6 dir entries! 25022 dirs checked bibo:~ #Here /proc/bus is not an ordinary directory and checking it results in a false positive.
linux:~ # chklinkcnt dir '/proc' has 48 hard links but 46 dir entries! dir '/proc/bus' has 4 hard links but 5 dir entries! dir '/proc/bus/usb' has 1 hard links but 2 dir entries! dir '/usr/share/locale/sk' has 4 hard links but 3 dir entries! 2692 dirs checked linux:~ # ls -al /usr/share/locale/sk total 3 drwxr-xr-x 4 root root 1024 Sep 2 2006 . drwxr-xr-x 42 root root 1024 Aug 31 2006 .. drwxr-xr-x 2 root root 1024 Aug 31 2006 LC_MESSAGES linux:~ #Again, the findings in /proc are better ignored. But the directory /usr/share/locale/sk should not produce a false positive. Looking closer reveals a subdirectory, a reference to the father directory and a reference to itself: a sum of 3. The link count of '.' is 4, though. There might be a problem.
linux:~ # debugfs /dev/sda1
debugfs 1.37 (21-Mar-2005)
debugfs: ls -l /usr/share/locale/sk
808001 41777 (2) 0 0 4096 2-Sep-2006 00:52 .
2 40755 (2) 0 0 4096 31-Aug-2006 02:11 ..
938006 40755 (2) 21037 27421 4096 17-Okt-2006 15:30 owned
340099 40700 (2) 0 0 4096 31-Aug-2006 15:35 LC_MESSAGES
There really was something wrong! The directory 'owned' was hidden -
probably by changing the user and group-id to some "magic" values which
are debugfs conviniently provides. You can now dump the directory with
debugfs or just try to enter it by using the full path.
gpg --verify chklinkcnt.c.sig chklinkcnt.cIf you don't know my key (0x7C06FD25) you have to import it and you might want to check if there is a path in the web of trust between your key and mine (key stats at uu.nl):
gpg --keyserver pgpkeys.pca.dfn.de --recv-key 0x7C06FD25I recommend to compile a static binary:
gcc -Wall -static chklinkcnt.c -o chklinkcnt