?? port_scan.txt
字號:
有的時候有可能SYN掃描都不夠秘密。一些防火墻和包過濾器會對一些指定的端口進行監視,有的程序能檢測到這些掃描。相反,FIN數據包可能會沒有任何麻煩的通過。這種掃描方法的思想是關閉的端口會用適當的RST來回復FIN數據包。另一方面,打開的端口會忽略對FIN數據包的回復。這種方法和系統的實現有一定的關系。有的系統不管端口是否打開,都回復RST,這樣,這種掃描方法就不適用了。并且這種方法在區分Unix和NT時,是十分有用的。
IP段掃描
這種不能算是新方法,只是其它技術的變化。它并不是直接發送TCP探測數據包,是將數據包分成兩個較小的IP段。這樣就將一個TCP頭分成好幾個數據包,從而過濾器就很難探測到。但必須小心。一些程序在處理這些小數據包時會有些麻煩。
TCP 反向 ident掃描
ident 協議允許(rfc1413)看到通過TCP連接的任何進程的擁有者的用戶名,即使這個連接不是由這個進程開始的。因此你能,舉個例子,連接到http端口,然后用identd來發現服務器是否正在以root權限運行。這種方法只能在和目標端口建立了一個完整的TCP連接后才能看到。
FTP 返回攻擊
FTP協議的一個有趣的特點是它支持代理(proxy)FTP連接。即入侵者可以從自己的計算機a.com和目標主機target.com的FTP server-PI(協議解釋器)連接,建立一個控制通信連接。然后,請求這個server-PI激活一個有效的server-DTP(數據傳輸進程)來給Internet上任何地方發送文件。對于一個User-DTP,這是個推測,盡管RFC明確地定義請求一個服務器發送文件到另一個服務器是可以的。但現在這個方法好象不行了。這個協議的缺點是“能用來發送不能跟蹤的郵件和新聞,給許多服務器造成打擊,用盡磁盤,企圖越過防火墻”。
我們利用這個的目的是從一個代理的FTP服務器來掃描TCP端口。這樣,你能在一個防火墻后面連接到一個FTP服務器,然后掃描端口(這些原來有可能被阻塞)。如果FTP服務器允許從一個目錄讀寫數據,你就能發送任意的數據到發現的打開的端口。
對于端口掃描,這個技術是使用PORT命令來表示被動的User DTP正在目標計算機上的某個端口偵聽。然后入侵者試圖用LIST命令列出當前目錄,結果通過Server-DTP發送出去。如果目標主機正在某個端口偵聽,傳輸就會成功(產生一個150或226的回應)。否則,會出現"425 Can't build data connection: Connection refused."。然后,使用另一個PORT命令,嘗試目標計算機上的下一個端口。這種方法的優點很明顯,難以跟蹤,能穿過防火墻。主要缺點是速度很慢,有的FTP服務器最終能得到一些線索,關閉代理功能。
這種方法能成功的情景:
220 xxxxxxx.com FTP server (Version wu-2.4(3) Wed Dec 14 ...) ready.
220 xxx.xxx.xxx.edu FTP server ready.
220 xx.Telcom.xxxx.EDU FTP server (Version wu-2.4(3) Tue Jun 11 ...) ready.
220 lem FTP server (SunOS 4.1) ready.
220 xxx.xxx.es FTP server (Version wu-2.4(11) Sat Apr 27 ...) ready.
220 elios FTP server (SunOS 4.1) ready
這種方法不能成功的情景:
220 wcarchive.cdrom.com FTP server (Version DG-2.0.39 Sun May 4 ...) ready.
220 xxx.xx.xxxxx.EDU Version wu-2.4.2-academ[BETA-12](1) Fri Feb 7
220 ftp Microsoft FTP Service (Version 3.0).
220 xxx FTP server (Version wu-2.4.2-academ[BETA-11](1) Tue Sep 3 ...) ready.
220 xxx.unc.edu FTP server (Version wu-2.4.2-academ[BETA-13](6) ...) ready.
UDP ICMP端口不能到達掃描
這種方法與上面幾種方法的不同之處在于使用的是UDP協議。由于這個協議很簡單,所以掃描變得相對比較困難。這是由于打開的端口對掃描探測并不發送一個確認,關閉的端口也并不需要發送一個錯誤數據包。幸運的是,許多主機在你向一個未打開的UDP端口發送一個數據包時,會返回一個ICMP_PORT_UNREACH錯誤。這樣你就能發現哪個端口是關閉的。UDP和ICMP錯誤都不保證能到達,因此這種掃描器必須還實現在一個包看上去是丟失的時候能重新傳輸。這種掃描方法是很慢的,因為RFC對ICMP錯誤消息的產生速率做了規定。同樣,這種掃描方法需要具有root權限。
UDP recvfrom()和write() 掃描
當非root用戶不能直接讀到端口不能到達錯誤時,Linux能間接地在它們到達時通知用戶。比如,對一個關閉的端口的第二個write()調用將失敗。在非阻塞的UDP套接字上調用recvfrom()時,如果ICMP出錯還沒有到達時回返回EAGAIN-重試。如果ICMP到達時,返回ECONNREFUSED-連接被拒絕。這就是用來查看端口是否打開的技術。
ICMP echo掃描
這并不是真正意義上的掃描。但有時通過ping,在判斷在一個網絡上主機是否開機時非常有用。
前面幾章基礎知識介紹已經為這里的編程作了準備了。
下面是一個端口掃描器的源程序,功能相當的簡單,一個典型的TCP connect()掃描。沒有對返回的數據進行分析。
#include < stdio.h>
#include < sys/socket.h>
#include < netinet/in.h>
#include < errno.h>
#include < netdb.h>
#include < signal.h>
int main(int argc, char **argv)
{
int probeport = 0;
struct hostent *host;
int err, i, net;
struct sockaddr_in sa;
if (argc != 2) {
printf("用法: %s hostname\n", argv[0]);
exit(1);
}
for (i = 1; i < 1024; i++) { //這里有點不是很好,可以將主機地址放在循環外
strncpy((char *)&sa, "", sizeof sa);
sa.sin_family = AF_INET;
if (isdigit(*argv[1]))
sa.sin_addr.s_addr = inet_addr(argv[1]);
else if ((host = gethostbyname(argv[1])) != 0)
strncpy((char *)&sa.sin_addr, (char *)host->h_addr, sizeof sa.sin_addr);
else {
herror(argv[1]);
exit(2);
}
sa.sin_port = htons(i);
net = socket(AF_INET, SOCK_STREAM, 0);
if (net < 0) {
perror("\nsocket");
exit(2);
}
err = connect(net, (struct sockaddr *) &sa, sizeof sa);
if (err < 0) {
printf("%s %-5d %s\r", argv[1], i, strerror(errno));
fflush(stdout);
} else {
printf("%s %-5d accepted. \n", argv[1], i);
if (shutdown(net, 2) < 0) {
perror("\nshutdown");
exit(2);
}
}
close(net);
}
printf(" \r");
fflush(stdout);
return (0);
}
下面這個又是一個端口器:
#include < stdio.h>
#include < sys/types.h>
#include < sys/socket.h>
#include "netdb.h"
struct hostent *gethostbyaddr();
void bad_addr();
main(argc, argv)
int argc;
char *argv[];
{
char addr[4];
int i, j,
a0, a1, a2, a3,
c,
classB, classC, single, hex;
char *fmt = "%d.%d.%d";
char **ptr;
struct hostent *host;
extern char *optarg;
classB = classC = single = hex = 0;
while((c = getopt(argc,argv,"bcsx")) != EOF) {
switch(c) {
case 'b':
classB++;
break;
case 'c':
classC++;
break;
case 's':
single++;
break;
case 'x':
hex++;
break;
}
}
if(classB == 0 && classC == 0 && single == 0) {
fprintf(stderr, "usage: %s [-b||-c||-s] [-x] xxx.xxx[.xxx[.xxx]]\n", argv[0]);
exit(1);
}
if(classB)
if(hex) {
fmt = "%x.%x";
sscanf(argv[3], fmt, &a0, &a1);
} else {
fmt = "%d.%d";
sscanf(argv[2], fmt, &a0, &a1);
}
else if(classC)
if(hex) {
fmt = "%x.%x.%x";
sscanf(argv[3], fmt, &a0, &a1, &a2);
} else {
fmt = "%d.%d.%d";
sscanf(argv[2], fmt, &a0, &a1, &a2);
}
else if(single)
if(hex) {
fmt = "%x.%x.%x.%x";
sscanf(argv[3], fmt, &a0, &a1, &a2, &a3);
} else {
fmt = "%d.%d.%d.%d";
sscanf(argv[2], fmt, &a0, &a1, &a2, &a3);
}
sscanf(argv[1], fmt, &a0, &a1, &a2);
addr[0] = (unsigned char)a0;
addr[1] = (unsigned char)a1;
if(a0>255||a0< 0)
bad_addr(a0);
if(a1>255||a1< 0)
bad_addr(a1);
if(classB) {
if(hex)
printf("Converting address from hex. (%x.%x)\n", a0, a1);
printf("Scanning Class B network %d.%d...\n", a0, a1);
while(j!=256) {
a2=j;
addr[2] = (unsigned char)a2;
jmpC:
if(classC)
if(hex)
printf("Converting address from hex. (%x.%x.%x)\n", a0, a1, a2);
printf("Scanning Class C network %d.%d.%d...\n", a0, a1, a2);
while(i!=256) {
a3=i;
addr[3] = (unsigned char)a3;
jmpS:
if ((host = gethostbyaddr(addr, 4, AF_INET)) != NULL) {
printf("%d.%d.%d.%d => %s\n", a0, a1, a2, a3, host->h_name);
ptr = host->h_aliases;
while (*ptr != NULL) {
printf("%d.%d.%d.%d => %s (alias)\n", a0, a1, a2, a3, *ptr);
ptr++;
}
}
if(single)
exit(0);
i++;
}
if(classC)
exit(0);
j++;
}
} else if(classC) {
addr[2] = (unsigned char)a2;
if(a2>255||a2< 0)
bad_addr(a2);
goto jmpC;
} else if(single) {
addr[2] = (unsigned char)a2;
addr[3] = (unsigned char)a3;
if(a2>255||a2< 0)
bad_addr(a2);
if(a3>255||a3< 0)
bad_addr(a3);
goto jmpS;
}
exit(0);
}
void
bad_addr(addr)
int *addr;
{
printf("Value %d is not valid.\n", addr);
exit(0);
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -