Holistic Engineering

A random assortment of shit with sprinkles.

Login Accounting Explained

| Comments

I put a call out for blog ideas: Devin Austin came up with “Login Accounting”. So let’s talk about that for a bit.

First off, a little disclaimer

This is not security advice, I am not a security expert, or an expert at pretty much anything. Use your head, silly.

Let’s also be clear about something

Login Accounting is pretty much a mess on unix. Programs that manage logins can “opt-in” to login accounting; the system does not inherently do this for you, largely by side effect of why it works at all. Most tools can even be configured to write to the basic accounting systems or not, or provide the option as a runtime argument. This means that your login accounting system can lie. Additionally, the systems we’re going to look at are the first thing an intruder will mess with. We’ll look at a few techniques to mitigate the lack of information later, but rest assured there’s not much you can do to make this bulletproof.

All code examples in this article expect Ubuntu 11.10 to be the platform. You will see deviation between systems so be certain you’ve absorbed this article before trying anywhere else.

utmp, wtmp, lastlog

These are the core systems in unix login accounting; they are append-only databases, more or less, with a system-dependent structure. You can usually read about the structure by typing man utmp or reading the /usr/include/utmp.h file. Note this will be dramatically different between Linux, FreeBSD, Mac OS X, etc.

One can navigate the utmp structure pretty simply, or use the w, who and last commands to navigate them. They exist as three files:

  • /var/run/utmp is what’s currently going on.
  • /var/log/wtmp is what’s happened in the past.
  • /var/log/lastlog is the last account for each event (e.g., a specific user logging in)

Anyhow, let’s have some fun. As for navigating the structure, while system-dependent that’s really easy. Here’s a small program that navigates utmp and sends the pty and username to figlet for output for all user-related information. apt-get install build-essential figlet and then gcc -std=c99 -o fig_utmp fig_utmp.c to use.

fig_utmp.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <utmp.h>
#include <stdio.h>

int main(int argc, char **argv)
{
  char buf[1024];
  struct utmp ut;

  int fd = open("/run/utmp", 'r');

  if (fd < 0) {
    perror("could not open file");
    exit(1);
  }

  while(read(fd, &ut, sizeof(struct utmp)) == sizeof(struct utmp)) {
    if(ut.ut_type == USER_PROCESS) {
      snprintf(buf, 1024, "figlet %s - %s", ut.ut_line, ut.ut_user);
      system(buf);
    }
  }

  close(fd);
  return(0);
}

It outputs something like this (I’m holding two logins to the box):

       _          ___                     _ _    _     
 _ __ | |_ ___   / / |           ___ _ __(_) | _| |__  
| '_ \| __/ __| / /| |  _____   / _ \ '__| | |/ / '_ \ 
| |_) | |_\__ \/ / | | |_____| |  __/ |  | |   <| | | |
| .__/ \__|___/_/  |_|          \___|_|  |_|_|\_\_| |_|
|_|                                                    
       _          _____                      _ _    _     
 _ __ | |_ ___   / / _ \            ___ _ __(_) | _| |__  
| '_ \| __/ __| / / | | |  _____   / _ \ '__| | |/ / '_ \ 
| |_) | |_\__ \/ /| |_| | |_____| |  __/ |  | |   <| | | |
| .__/ \__|___/_/  \___/           \___|_|  |_|_|\_\_| |_|
|_|                

Try modifying it to output the hostname as well! (Hint: the struct member is called ut_host)

utmp carries a lot more than just user logins though, it’s responsible for recording most of the events that happen at a system level. For example, here’s some last output:

erikh@utmptest:~$ last
erikh    pts/0        speyside.local   Sun Mar 25 10:18 - 10:18  (00:00)    
erikh    pts/0        speyside.local   Sun Mar 25 09:17 - 10:06  (00:48)    
reboot   system boot  3.0.0-16-server  Sun Mar 25 09:13 - 10:22  (01:08)    
erikh    pts/1        speyside.local   Sun Mar 25 09:13 - crash  (00:00)    
erikh    pts/0        speyside.local   Sun Mar 25 09:12 - down   (00:00)    
reboot   system boot  3.0.0-16-server  Sun Mar 25 09:11 - 09:13  (00:01)    
reboot   system boot  3.0.0-16-server  Thu Mar 22 00:35 - 00:53  (00:18)    
reboot   system boot  3.0.0-16-server  Thu Mar 22 00:32 - 00:33  (00:01)    
erikh    pts/0        speyside.local   Thu Mar 22 00:31 - down   (00:00)    
erikh    tty1                          Thu Mar 22 00:27 - down   (00:04)    
erikh    tty1                          Thu Mar 22 00:27 - 00:27  (00:00)    
reboot   system boot  3.0.0-16-server  Thu Mar 22 00:20 - 00:31  (00:11)    
erikh    tty1                          Thu Mar 22 00:16 - down   (00:03)    
erikh    tty1                          Thu Mar 22 00:16 - 00:16  (00:00)    
reboot   system boot  3.0.0-12-server  Thu Mar 22 00:16 - 00:20  (00:03)    

Notice all the reboots in there? This is why we filter on USER_PROCESS above. The ut_type contains a lot more information than what we care about. Anyhow, this is explained better in man utmp, so go read that. There is also the POSIX utmpx which isn’t really any more consistent than utmp is across different unices.

So, about this lossy login accounting issue…

What to do about it? There are really two options:

  • Make sure your things are logging utmp entries.
  • Use something else, like log scanning.

In reality only one of these is the serious choice — there are other things like auditd and PAM controls that can assist here, but not much really. Log scanning and having tight control over how users get into your systems is the way to go. Since log scanning is such a deep article, we’ll cover it in a separate one. Stay Tuned.

Conclusion

The utmp system is typically relied on for a lot more than it should be; it’s inconclusive and generally flawed especially for non-interactive … interaction.

Comments