|
/*** *** *** author : beavis & butthead *** *** nitwit.c : checks for a vnode with major/minor similar *** to /dev/nit. i.e. reports if there is a sunsniffer. *** *** compile : cc -o nitwit nitwit.c -lkvm *** *** include : all header files about disclaimers and that kind of rubbish. *** *** "bugs" : it checks 'kmem' for such vnodes therefore there is no *** guarantee that it will cue for all sniffers. *** the intruder might have modified 'kmem' already. *** *** advntges : better than cert's 'cpm' because the sniffer can be *** reading in normal (non promiscuous) mode from /dev/nit *** and nittie.c will sense this. *** ***/ #include <stdio.h> #include <errno.h> #include <nlist.h> #include <pwd.h> #include <sys/time.h> #include <kvm.h> #define KERNEL #include <sys/file.h> #include <fcntl.h> #include <sys/proc.h> #undef KERNEL /* the following lines are stollen from <sys/vnode.h> */ enum vtype { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VBAD, VFIFO }; struct vnode { u_short v_flag; /* vnode flags (see below) */ u_short v_count; /* reference count */ u_short v_shlockc; /* count of shared locks */ u_short v_exlockc; /* count of exclusive locks */ struct vfs *v_vfsmountedhere; /* ptr to vfs mounted here */ struct vnodeops *v_op; /* vnode operations */ union { struct socket *v_Socket; /* unix ipc */ struct stdata *v_Stream; /* stream */ struct page *v_Pages; /* vnode pages list */ } v_s; struct vfs *v_vfsp; /* ptr to vfs we are in */ enum vtype v_type; /* vnode type */ dev_t v_rdev; /* device (VCHR, VBLK) */ long *v_filocks; /* File/Record locks ... */ caddr_t v_data; /* private data for fs */ }; /* down to here */ #define NIT_MAJ 0x2800 #define MAJ_MASK 0xff00 #define MIN_MASK 0x00ff #define FALSE 0 #define TRUE 1 #define k_read(x, y, l) \ if (kvm_read(kd, (unsigned long)x, (char *)y, (unsigned)l) < 0) \ { perror("kvm_read"); exit(1); } int cnt = 0; kvm_t *kd; int CheckFile(pUsrFile) struct file *pUsrFile; { struct vnode vn; if ((pUsrFile->f_count == 0) || (pUsrFile->f_data == NULL)) return FALSE; k_read(pUsrFile->f_data, &vn, sizeof(struct vnode)); if ((vn.v_type == VCHR) && ((vn.v_rdev & MAJ_MASK) == NIT_MAJ)) { printf("open NIT with major/minor: %d / %d\n", ((vn.v_rdev >> 8) & MIN_MASK), (vn.v_rdev & MIN_MASK)); printf("NIT open() flags: %s%s\n", (((pUsrFile->f_flag) & _FREAD) ? "READ " : ""), (((pUsrFile->f_flag) & _FWRITE) ? "WRITE" : "")); return TRUE; } return FALSE; } void userSearch(userProc) struct proc *userProc; { #define MAX_CWD_LEN 1024 int flg; char **usrArg; struct file **ppFile, *pCurFile, curFile; struct user *pUsrEnv; struct passwd *pUsrInfo; struct ucwd usrCurDir; char szCD[MAX_CWD_LEN]; pUsrEnv = kvm_getu(kd, userProc); ppFile = pUsrEnv->u_ofile; if (ppFile) do { k_read(ppFile++, &pCurFile, sizeof(struct file *)); if (pCurFile == NULL) continue; k_read(pCurFile, &curFile, sizeof(struct file)); if (flg = CheckFile(&curFile)) { cnt++; pUsrInfo = getpwuid(userProc->p_uid); if (pUsrInfo) printf("user: %s (%s)\n", pUsrInfo->pw_name, pUsrInfo->pw_gecos); else printf("userid: %d\n", userProc->p_uid); k_read(pUsrEnv->u_cwd, &usrCurDir, sizeof(struct ucwd)); k_read(usrCurDir.cw_dir, szCD, MAX_CWD_LEN); printf("starting dir: %s\n", (szCD[0] ? szCD: "/")); kvm_getcmd(kd, userProc, pUsrEnv, &usrArg, NULL); if (usrArg) { printf("program:"); while (*usrArg != NULL) printf(" %s", *usrArg++); puts(""); } else puts("can not find program's args"); printf("pid: %d\n", userProc->p_pid); puts("---"); } } while (pCurFile && !flg); } main(argc, argv) int argc; char **argv; { struct proc *pCurProc; if (!(kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL))) { perror("kvm_open"); exit(1); } kvm_setproc(kd); while ((pCurProc = kvm_nextproc(kd)) != NULL) userSearch(pCurProc); if (!cnt) puts("can not sense anyone reading from the NIT"); else printf("total: %d process%s using NIT\n", cnt, (cnt == 1 ? "" : "es")); kvm_close(kd); }