2
* 2004/09/23 - Jeremy Miller <jmtgzd@gmail.com>
4
* This utility compares the output from the ps command and tries to find
5
* a matching entry bound to the same tty in the utmp login records. The
6
* idea is to display users that may have wiped themselves from the utmp
7
* log. When analyzing a compromised box, it is assumed you have the
8
* path to a known good 'ps' binary in your PATH.
10
* LICENSE: This program is free software; you can redistribute it and/or
11
* modify it under the terms of the GNU General Public License as
12
* published by the Free Software Foundation; either version 2 of the
13
* License, or (at your option) any later version.
15
* This program is distributed in the hope that it will be useful, but
16
* WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
* General Public License for more details.
20
* You should have received a copy of the GNU General Public License along
21
* with this program; if not, write to the Free Software Foundation, Inc.,
22
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
* Ighighi X - Improved speed via break command - 2005/03/27
26
* Some overflow fixes by Michael Schwendt - 2009/07/21
30
#if !defined(__sun) && !defined(__linux__)
31
int main () { return 0; }
51
#define UTMP "/var/log/utmpx"
52
#define UT_LINESIZE 12
57
#define UTMP "/var/run/utmp"
61
char ps_tty[UT_LINESIZE+2];
62
char ps_user[UT_NAMESIZE+2];
63
char ps_args[MAXLENGTH+2];
67
char ut_tty[UT_LINESIZE];
71
static char *cmd[] = {
72
"ps -ef -o \"tty,pid,ruser,args\"", /* solaris */
73
"ps axk \"tty,ruser,args\" -o \"tty,pid,ruser,args\"" /* linux */
75
int fetchps(struct ps_line *);
76
int fetchutmp(struct utmp_line *);
78
int fetchps(struct ps_line *psl_p)
81
char line[MAXREAD + 1], pid[UT_PIDSIZE];
83
struct ps_line *curp = &psl_p[0];
84
struct ps_line *endp = &psl_p[MAXBUF-1];
88
if ((ps_fp = (popen(cmd[PS_CMD], "r"))) != NULL) {
89
fgets(line, MAXREAD, ps_fp); /* skip header */
90
while (fgets(line, MAXREAD, ps_fp)) {
92
if (*s != '\?' && curp <= endp) { /* only interested in lines that
95
for (x = 0; (!isspace(*s)) && (*d++ = *s++) && x <= UT_LINESIZE; x++) /* grab tty */
98
while (isspace(*s)) /* skip spaces */
101
for (x = 0; (!isspace(*s)) && (*d++ = *s++) && x <= UT_LINESIZE; x++) /* grab pid */
104
curp->ps_pid = atoi(pid);
105
while (isspace(*s)) /* skip spaces */
108
for (x = 0; (!isspace(*s)) && (*d++ = *s++) && x <= UT_NAMESIZE; x++) /* grab user */
112
while (isspace(*s)) /* skip spaces */
114
for (x = 0; (*d++ = *s++) && x <= MAXLENGTH; x++) /* cmd + args */
124
fprintf(stderr, "\nfailed running 'ps' !\n");
130
int fetchutmp(struct utmp_line *utl_p)
137
struct utmp_line *curp = &utl_p[0];
138
struct utmp_line *endp = &utl_p[MAXBUF-1];
139
int i, f, del_cnt, sz_ut;
142
if ((f = open(UTMP, O_RDONLY)) > 0) {
144
sz_ut = sizeof(struct utmpx);
146
sz_ut = sizeof(struct utmp);
149
while (read(f, &ut, sz_ut) > 0 && curp <= endp) {
152
del_cnt++; /* ut_time shouldn't be zero */
154
if (strlen(ut.ut_user) > 0) {
155
strncpy(curp->ut_tty, ut.ut_line, UT_LINESIZE);
156
curp->ut_pid = ut.ut_pid;
157
curp->ut_type = ut.ut_type;
164
printf("=> possibly %d deletion(s) detected in %s !\n",
167
fprintf(stderr, "\nfailed opening utmp !\n");
173
int main(int argc, char *argv[])
175
struct ps_line ps_l[MAXBUF]; /* array of data from 'ps' */
176
struct utmp_line ut_l[MAXBUF]; /* array of data from utmp log */
177
int h, i, y, z, mtch_fnd, hdr_prntd;
182
for (h = 0; h < y; h++) { /* loop through 'ps' data */
184
for (i = 0; i < z; i++) { /* try and match the tty from 'ps' to one in utmp */
185
if (ut_l[i].ut_type == LOGIN_PROCESS /* ignore getty processes with matching pid from 'ps' */
186
&& ut_l[i].ut_pid == ps_l[h].ps_pid)
191
else if (strncmp(ps_l[h].ps_tty, ut_l[i].ut_tty, /* compare the tty's */
192
strlen(ps_l[h].ps_tty)) == 0)
201
(" The tty of the following user process(es) were not found\n");
202
printf(" in %s !\n", UTMP);
203
printf("! %-9s %7s %-6s %s\n", "RUID", "PID", "TTY",
207
printf("! %-9s %7d %-6s %s\n", ps_l[h].ps_user,
208
ps_l[h].ps_pid, ps_l[h].ps_tty, ps_l[h].ps_args);