There are several simple perl parsers for wtmp files, like wtmp.pl by "Brocade Blue"
http://brocadeblue.blogspot.com/2012/10/perl-script-to-parse-wtmp-logs.html
Full source of wtmp.pl with minor typos fixed:
#!/usr/bin/perl
@type = (
"Empty", "Run Lvl", "Boot", "New Time", "Old Time", "Init",
"Login", "Normal", "Term", "Account"
);
$recs = "";
while (<>) {
$recs .= $_;
}
foreach ( split( /(.{384})/s, $recs ) ) {
next if length(
type,
line, $inittab, $user, $host,
t2,
t4,
_ =~ /(.{4})(.{4})(.{32})(.{4})(.{32})(.{256})(.{4})(.{4})(.{4})(.{4})(.{4})/s;
if ( defined $line && $line =~ /\w/ ) { ##FILTER
$line =~ s/\x00+//g;
$host =~ s/\x00+//g;
$user =~ s/\x00+//g;
printf(
"%s %-8s %-12s %10s %-45s \n",
scalar( gmtime( unpack( "I4",
type[ unpack( "I4", $type ) ],
$user, $line, $host
);
}
}
printf "\n"
The script may not work on 64-bit machines. The "384" and long line with (.{4}) should be fixed for 64-bit environment.
PS: to see really all records, disable the expression in the if marked with "##FILTER".
There are several simple perl parsers for wtmp files, like wtmp.pl by "Brocade Blue"
http://brocadeblue.blogspot.com/2012/10/perl-script-to-parse-wtmp-logs.html
Full source of wtmp.pl with minor typos fixed:
#!/usr/bin/perl
@type = (
"Empty", "Run Lvl", "Boot", "New Time", "Old Time", "Init",
"Login", "Normal", "Term", "Account"
);
$recs = "";
while (<>) {
$recs .= $_;
}
foreach ( split( /(.{384})/s, $recs ) ) {
next if length(
type,
line, $inittab, $user, $host,
t2,
t4,
_ =~ /(.{4})(.{4})(.{32})(.{4})(.{32})(.{256})(.{4})(.{4})(.{4})(.{4})(.{4})/s;
if ( defined $line && $line =~ /\w/ ) { ##FILTER
$line =~ s/\x00+//g;
$host =~ s/\x00+//g;
$user =~ s/\x00+//g;
printf(
"%s %-8s %-12s %10s %-45s \n",
scalar( gmtime( unpack( "I4",
type[ unpack( "I4", $type ) ],
$user, $line, $host
);
}
}
printf "\n"
The script may not work on 64-bit machines. The "384" and long line with (.{4}) should be fixed for 64-bit environment.
PS: to see really all records, disable the expression in the if marked with "##FILTER".
You should look at the audit log instead.
Try using ausearch, it offers what utmp does and more.
All three of the files that you want to read are stored in binary format. They are not plain text files and cannot be read with a normal text editor, or by using the cat command. Doing so will result in garbled output as you have noted.
Below are the functions of each of the three files:
- The file
/var/log/btmprecords failed login attempts. - The file
/var/run/utmpallows one to discover information about who is currently using the system. This file will contain information on a user's logins: on which terminals, logouts, system events and the current status of the system, system boot time (used by uptime) etc. - The file
/var/log/wtmpprovides an historical record of utmp data.
You can use the last command to read each of the files.
For example:
sudo last /var/log/btmp` (note: this command needs to be run using sudo)
johndoe@computer:~$ last -f /var/run/utmp
johndoe tty7 Fri Jul 26 17:58 still logged in
reboot system boot 3.5.0-37-generic Fri Jul 26 17:57 - 20:10 (1+02:13)
johndoe@computer::~$ last -f /var/log/wtmp
reboot system boot 3.5.0-37-generic Fri Jul 26 17:57 - 20:16 (1+02:19)
johndoe pts/2 :0 Fri Jul 26 17:52 - 17:55 (00:03)
johndoe pts/5 :0 Fri Jul 26 12:00 - 17:55 (05:55)
johndoe pts/0 :0.0 Fri Jul 26 07:11 - 11:58 (04:46)
<snip>...
For more information see: Linux Display Date And Time Of Login and the man pages for the command "last".
Using Perl 5
#!/usr/bin/env perl
#
# ripped from https://www.hcidata.info/wtmp.htm
use warnings;
@type=("Empty","Run Lvl","Boot","New Time","Old Time","Init","Login","Normal","Term","Account");
$recs = "";
while (<>) {
$recs .= $_
};
foreach (split(/(.{384})/s, $recs)) {
next if length(
type,
line, $inittab, $user, $host,
t2,
t4,
_ =~/(.{4})(.{4})(.{32})(.{4})(.{32})(.{256})(.{4})(.{4})(.{4})(.{4})(.{4})/s;
if (defined $line && $line =~ /\w/) {
$line =~ s/\x00+//g;
$host =~ s/\x00+//g;
$user =~ s/\x00+//g;
printf("%s %-8s %-12s %10s %-45s\n",
scalar(gmtime(unpack("I4",
type[unpack("I4", $type)],
$user,
$line,
$host,
)
};
};
Output will look something like
Tue Dec 20 08:08:25 2022 Term pts/0
Mon Dec 26 02:19:58 2022 Normal root pts/0 131.191.30.152
Mon Dec 26 17:27:51 2022 Term pts/0
Mon Dec 26 18:23:54 2022 Normal root pts/0 131.191.30.152
Mon Dec 26 20:06:19 2022 Term pts/0
Wed Dec 28 07:07:29 2022 Normal root pts/0 131.191.30.152
last is the canonical way to read wtmp files. But this perl script hints at the wtmp file format.
Ripped from here.
Once i opened the file using less , i could only see binary data. Now logstash cant understand this data. A logstash file like the following should work fine -
input {
pipe {
command => "/usr/bin/last -f /var/log/wtmp"
}
}
output {
elasticsearch {
host => localhost
protocol => "http"
port => "9200"
}
}
Vineeth's answer is right but the following cleaner config works as well:
input { pipe { command => "last" } }
last /var/log/wtmp and last are exactly the same.
utmp, wtmp, btmp are Unix files that keep track of user logins and logouts. They cannot be read directly because they are not regular text files. However, there is the last command which displays the information of /var/log/wtmp in plain text.
$ last --help
Usage:
last [options] [<username>...] [<tty>...]
I can read the file when logged into the box by using last -F /var/log/wtmp
I doubt that. What the -F flag does:
-F, --fulltimes print full login and logout times and dates
So, last -F /var/log/wtmp will interpret /var/log/wtmp as a username and won't print any login information.
What the -f flag does:
-f, --file <file> use a specific file instead of /var/log/wtmp
logrotate was a good idea.
Like any regular file, wtmp could have been "sparse" (cf. lseek(2) "holes" and ls -s) which can show a extreme file size that actually occupies little disk. How did the hole get there, if it was a hole? getty(8) and friends could have had a bug. Or a system crash and fsck repair could have caused it.
If you are looking to see the raw contents of wtmp, od or hd are good for peeking at binaries and have the happy side effect of showing long runs of empty as such.
Unless it recurs, I wouldn't give it much more thought. A marginally competent intruder would do a better job than that, the contents aren't all that interesting, and little depends on them.
Just to help others which might find this useful...
Is there another program besides
lastto inspect these files?
Yes, try utmpdump.
$ utmpdump /var/log/wtmp