When auditing Unix-based systems, particularly some Linux flavors, some requirements arise regarding the authentication files.
These systems have two main files: `/etc/passwd` contains user information like username, main group, home directory and shell being used; and `/etc/shadow`, which contains the user’s hashed password, settings and related data.
We will be using these files from the box containing the OWASP Broken Web Applications Project.
Analyzing /etc/passwd file
This file contains 7 distinct fields:
- User ID: it is used when the user logs in, and it is compared to the `/etc/shadow` file. Its maximum length is 32 characters.
- Password: it indicates with an “x” that the real password is stored in another file; `/etc/shadow` in this case.
- UID: it is the unique identifier assigned to a user. 0 is used for root, and every other predefined account uses the range 1-99. For system accounts, the commonly used range is 100-999.
- GID: it is the primary user group. More details can be found in the `/etc/group` file.
- User Info: it is usually used to save the user’s full name and other relevant data.
- Home Dir: it is the absolute path of the user’s home directory.
- Shell: it is the absolute path of the user’s default shell.
This is the content we are going to analyze:
We are interested in extracting group and shell information from this file. If you need additional information about user groups please use the groups <username> command or, for a group perspective, you can look in the `/etc/group` file. Let’s start working on it.
First, we will be importing some python libraries we need and define the base structure:
The following function will iterate the content of our `/etc/passwd` file and return the information to be analyzed. We will be counting the number of users with a particular group membership and the shells they are using. We will also be ignoring those lines that are commented.
Assuming we saved this information in a data/passwd.txt file, we may want to capture the file content in the following way:
And to complement this, let’s draw some graphics. For that, we will be using the following function:
So, our main function will now be this:
And this is the resulting picture:
With a few small changes to our main function, we can draw the shells being used as well:
Analyzing /etc/shadow file
These are the fields of the `/etc/shadow` file:
- User ID: it is the same identifier used in the `/etc/passwd` file.
- Encrypted Password: it is the encrypted password and its format is usually `$id$salt$hashed`.
- Last Chg Days: this is an integer value indicating the number of days since Jan 1, 1970, when the password was last changed.
- Min Days: this is the minimum number of days after which a user is authorized to change the password.
- Max Days: this is the maximum number of days in which a password is valid. Exceeded this period, the user will be forced to change the password.
- Warn Days: this number indicates a notification of the number of days before the user password expires.
- Inactive Days: this is the number of days after the password expiration date, in which the account will be disabled.
- Disabled Days: it is an integer value that indicates the number of days since Jan 1, 1970, when the account will no longer be used.
- Not Used: this field is not currently being used.
And this is how the content looks:
We will add another dictionary to save our data:
And we will be using a similar function to complete this information:
Finally, we will be adding this function to our main function using a `data/shadow.txt` file and, with minimal changes, we should be able to see when users changed their password.
With this, you may be able to answer questions like:
- Do accounts that don’t need interactive logon have a false shell in place?
- Are the users assigned to the correct group considering the least privilege principle? You may need to perform additional work to have a complete answer to this question, as previously mentioned
- Have the users recently changed their password?
- Are the expiration settings properly configured?
- Is the user being asked to change his password with proper anticipation?
Thanks for reading!
You can see a full version of the code here.