Finding SGID files

How to find SGID files.

There are 2 ways to find SGID files:

  • You can directly search for them using the find command
  • You can take a complete listing of the file system, and searching through that listing afterwards

The advantage of using the find command is that you directly have the information you need. However, most of the time you will be looking for more than only SGID files (e.g. SUID, world-writable, unowned). Running a find command for each of these can be resource intensive. Therefore, if resources could be an issue, take a complete listing of the file system and afterwards you can search manually through that listing of all sorts of files you want.

Below you will find the description of how to search for SGID files using both these methods.

Finding SGID files using find

The find command is really simple. Just run the following command (with root privileges) on the UNIX system:
find / -type f -perm -2000 -ls > find_sgid.txt 2>> error_find_sgid.txt
All SGID files will be listed in the file find_sgid.txt and errors encountered during the process will be listed in error_find_sgid.txt

Finding SGID files in a filesystem listing

First of all you need to take a full listing of the complete filesystem. You can do this using the ls command:
ls -laR / > /tmp/full_fs_list.txt 2>> error_full_fs_list.txt

You can see a clear pattern in this listing. First you see the name of the folder and then follows the listing of the files in that folder. For example:

/usr:
total 152
drwxr-xr-x  11 root root   4096 2007-10-07 18:06 .
drwxr-xr-x  22 root root   4096 2008-05-18 15:55 ..
drwxr-xr-x   2 root root  36864 2008-05-18 10:26 bin
drwxr-xr-x   2 root root   4096 2007-10-07 17:01 games
drwxr-xr-x   6 root root   4096 2007-10-07 16:50 include
drwxrwsr-x   2 root src    4096 2006-10-28 16:06 src
drwxr-xr-x   3 root root   4096 2007-10-07 18:06 X11R6

/usr/bin:
total 55424
drwxr-xr-x  2 root   root      36864 2008-05-18 10:26 .
drwxr-xr-x 11 root   root       4096 2007-10-07 18:06 ..
-rwxr-xr-x  1 root   root       3840 2008-04-25 22:44 cpan
lrwxrwxrwx  1 root   root          7 2007-10-07 18:06 cpp -> cpp-4.1
-rwxr-xr-x  1 root   root     183444 2006-12-10 15:45 cpp-4.1
-rwxr-xr-x  1 root   root       3899 2008-05-08 02:39 c_rehash
-rwxr-sr-x  1 root   crontab   26380 2006-12-20 01:02 crontab
-rwxr-xr-x  1 root   root      86140 2007-01-30 19:51 csplit

Our goal is to filter out the folder name containing SGID files and the details of the SGID file itself. I always filter such filesystem listings in 2 phases:

  • First I filter out all directory names and all SGID files
  • Then I filter out all directory names that don't contain SGID files

Phase 1: filtering all directory names and all SGID files
If you just want to know about all SGID files on your system, filter the listing using this command:
sed -n -r -e "/^-[rwxstS-]{5}s/p" -e "/^\//p" ls_usr.txt
This code will print out all lines that have the SGID bit set and will print out all lines starting with a slash (the directory names).

If you want to know only about all SGID files owned by the root group filter the listing using this command:
sed -n -r -e "/^-[rwxstS-]{5}s[-rwxstS]{3}[[:space:]]{1,}[[:digit:]]{1,}[[:space:]]{1,}[[:alnum:]]{1,}[[:space:]]{1,}root/p" -e "/^\//p" ls_usr.txt

If we run the first commands against the small listing from above, we will get the following result:

/usr:
/usr/bin:
-rwxr-sr-x  1 root   crontab   26380 2006-12-20 01:02 crontab

You can imagine that on a complete filesystem, there will be a lot of directories not having SGID files, so you will have many instances similar to the /usr: in the above listing. Therefore, we will filter these out in the following phase.

Phase 2: Filtering out empty directory names
The important thing to see, is that empty directories have a certain pattern. You will see that the first character of the next line will be a slash again. This will be how we will filter out empty directories.

I once quickly wrote this bash script to do this task:

read line1
while read line2
do
  if [[ "/" == "${line1:0:1}" ]]
  then
    if [[ "/" != "${line2:0:1}" ]]
    then
      echo "$line1"
      echo "$line2"
    fi
  else
      echo "$line1"
  fi
  line1=$line2
done | uniq

If you save this script to a file called filter.sh, then you can combine the two phases into 1 command line to get what you wanted to see:
lode@LNX-DEBIANWS:~$ sed -n -r -e "/^-[rwxstS-]{5}s/p" -e "/^\//p" ls_usr.txt | sh filter.sh
/usr/bin:
-rwxr-sr-x 1 root crontab 26380 2006-12-20 01:02 crontab
lode@LNX-DEBIANWS:~$

On a full directory listing of the /usr folder on my system, the script gives you the following result

lode@LNX-DEBIANWS:~$ ls -laR /usr > ls_usr.txt
lode@LNX-DEBIANWS:~$ sed -n -r -e "/^-[rwxstS-]{5}s[-rwxstS]{3}[[:space:]]{1,}[[:digit:]]{1,}[[:space:]]{1,}[[:alnum:]]{1,}[[:space:]]{1,}root/p" -e "/^\//p" ls_usr.txt | sh filter.sh
/usr/bin:
-rwsr-sr-x  1 root   root       7672 2007-04-08 20:26 X
lode@LNX-DEBIANWS:~$

Tags: 

You might also be interested in...