Python 实现端口扫描
一、常见端口扫描的原理
0、秘密扫描
秘密扫描是一种不被审计工具所检测的扫描技术。
它通常用于在通过普通的防火墙或路由器的筛选(filtering)时隐藏自己。
秘密扫描能躲避IDS、防火墙、包过滤器和日志审计,从而获取目标端口的开放或关闭的信息。由于没有包含TCP 3次握手协议的任何部分,所以无法被记录下来,比半连接扫描更为隐蔽。
但是这种扫描的缺点是扫描结果的不可靠性会增加,而且扫描主机也需要自己构造IP包。现有的秘密扫描有TCP FIN扫描、TCP ACK扫描、NULL扫描、XMAS扫描和SYN/ACK扫描等。
1、Connect()扫描
此扫描试图与每一个TCP端口进行“三次握手”通信。如果能够成功建立接连,则证明端口开发,否则为关闭。准确度很高,但是最容易被防火墙和IDS检测到,并且在目标主机的日志中会记录大量的连接请求以及错误信息。
TCP connect端口扫描服务端与客户端建立连接成功(目标端口开放)的过程:
① Client端发送SYN;
② Server端返回SYN/ACK,表明端口开放;
③ Client端返回ACK,表明连接已建立;
④ Client端主动断开连接。
建立连接成功(目标端口开放)
TCP connect端口扫描服务端与客户端未建立连接成功(目标端口关闭)过程:
① Client端发送SYN;
② Server端返回RST/ACK,表明端口未开放。
优点:实现简单,对操作者的权限没有严格要求(有些类型的端口扫描需要操作者具有root权限),系统中的任何用户都有权力使用这个调用,而且如果想要得到从目标端口返回banners信息,也只能采用这一方法。
另一优点是扫描速度快。如果对每个目标端口以线性的方式,使用单独的connect()调用,可以通过同时打开多个套接字,从而加速扫描。
缺点:是会在目标主机的日志记录中留下痕迹,易被发现,并且数据包会被过滤掉。目标主机的logs文件会显示一连串的连接和连接出错的服务信息,并且能很快地使它关闭。
2、SYN扫描
扫描器向目标主机的一个端口发送请求连接的SYN包,扫描器在收到SYN/ACK后,不是发送的ACK应答而是发送RST包请求断开连接。这样,三次握手就没有完成,无法建立正常的TCP连接,因此,这次扫描就不会被记录到系统日志中。这种扫描技术一般不会在目标主机上留下扫描痕迹。但是,这种扫描需要有root权限。
·端口开放:(1)Client发送SYN;(2)Server端发送SYN/ACK;(3)Client发送RST断开(只需要前两步就可以判断端口开放)
·端口关闭:(1)Client发送SYN;(2)Server端回复RST(表示端口关闭)
优点:SYN扫描要比TCP Connect()扫描隐蔽一些,SYN仅仅需要发送初始的SYN数据包给目标主机,如果端口开放,则相应SYN-ACK数据包;如果关闭,则响应RST数据包;
3、NULL扫描
反向扫描—-原理是将一个没有设置任何标志位的数据包发送给TCP端口,在正常的通信中至少要设置一个标志位,根据FRC 793的要求,在端口关闭的情况下,若收到一个没有设置标志位的数据字段,那么主机应该舍弃这个分段,并发送一个RST数据包,否则不会响应发起扫描的客户端计算机。也就是说,如果TCP端口处于关闭则响应一个RST数据包,若处于开放则无相应。但是应该知道理由NULL扫描要求所有的主机都符合RFC 793规定,但是windows系统主机不遵从RFC 793标准,且只要收到没有设置任何标志位的数据包时,不管端口是处于开放还是关闭都响应一个RST数据包。但是基于Unix(*nix,如Linux)遵从RFC 793标准,所以可以用NULL扫描。 经过上面的分析,我们知道NULL可以辨别某台主机运行的操作系统是什么操作系统。
端口开放:Client发送Null,server没有响应
端口关闭:(1)Client发送NUll;(2)Server回复RST
说明:Null扫描和前面的TCP Connect()和SYN的判断条件正好相反。在前两种扫描中,有响应数据包的表示端口开放,但在NUll扫描中,收到响应数据包表示端口关闭。反向扫描比前两种隐蔽性高些,当精确度也相对低一些。
用途:判断是否为Windows系统还是Linux。
4、FIN扫描
与NULL有点类似,只是FIN为指示TCP会话结束,在FIN扫描中一个设置了FIN位的数据包被发送后,若响应RST数据包,则表示端口关闭,没有响应则表示开放。此类扫描同样不能准确判断windows系统上端口开发情况。
·端口开放:发送FIN,没有响应
·端口关闭:(1)发送FIN;(2)回复RST
5、ACK扫描
扫描主机向目标主机发送ACK数据包。根据返回的RST数据包有两种方法可以得到端口的信息。方法一是: 若返回的RST数据包的TTL值小于或等于64,则端口开放,反之端口关闭。
6、Xmas-Tree扫描
通过发送带有下列标志位的tcp数据包。
·URG:指示数据时紧急数据,应立即处理。
·PSH:强制将数据压入缓冲区。
·FIN:在结束TCP会话时使用。
正常情况下,三个标志位不能被同时设置,但在此种扫描中可以用来判断哪些端口关闭还是开放,与上面的反向扫描情况相同,依然不能判断windows平台上的端口。
·端口开放:发送URG/PSH/FIN,没有响应
·端口关闭:(1)发送URG/PSH/FIN,没有响应;(2)响应RST
XMAS扫描原理和NULL扫描的类似,将TCP数据包中的ACK、FIN、RST、SYN、URG、PSH标志位置1后发送给目标主机。在目标端口开放的情况下,目标主机将不返回任何信息。
7、Dump扫描
也被称为Idle扫描或反向扫描,在扫描主机时应用了第三方僵尸计算机扫描。由僵尸主机向目标主机发送SYN包。目标主机端口开发时回应SYN|ACK,关闭时返回RST,僵尸主机对SYN|ACK回应RST,对RST不做回应。从僵尸主机上进行扫描时,进行的是一个从本地计算机到僵尸主机的、连续的ping操作。查看僵尸主机返回的Echo响应的ID字段,能确定目标主机上哪些端口是开放的还是关闭的。
二、Python 代码实现
1、利用Python的Socket包中的connect方法,直接对目标IP和端口进行连接并且尝试返回结果,而无需自己构建SYN包。
2、对IP端口进行多线程扫描,注意的是不同的电脑不同的CPU每次最多创建的线程是不一样的,如果创建过多可能会报错,需要根据自己电脑情况修改每次扫描的个数或者将seelp的时间加长都可以。
看完了吗?感觉动手操作一下把!
python学习网,免费的在线学习python平台,欢迎关注!
本文转自:
Asynchronous socket error 10061
服务器错误,
端口扫描的问题
在写端口扫描时 ,如果与某主机特定端口无法通信 ,
就此主机而言 ,我想应该有以下两种情况 :
1 。此地址上无任何主机存在
2 。有主机但被扫描的特定端口不存在 ( 也可能是被 firewall 过滤了 )
如何得知某端口一打开
给你来个简单的吧!
procedure TForm1.Timer1Timer(Sender: TObject);
var
I : integer;
begin
Memo1.Clear;
for I := 0 to 1000 do begin
ServerSocket1.Close;
ServerSocket1.Port := I;
try
ServerSocket1.Open;
except
Memo1.Lines.Add(IntToStr(I) + ' 端口被打开 !');
end;
end;
end;
对不起 ,我指的是别人机器上的 PORT
你是说 PORT 只能被一个程序打开么 ?
可是 ,我用 OICQ 时在打开 4000 没问题呀
我把上面的程序改了一下 ,也可以用的。你就去试图连接对方 ,如果通了 ,说明此端口被打
开。
procedure TForm1.ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
begin
Memo1.Lines.Add(' 端口 '+IntToStr(Socket.RemotePort)+' 被打开! ');
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
ClientSocket1.Close;
ClientSocket1.Port := PortID;
try
ClientSocket1.Open;
except
end;
Inc(PortID);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
PortID := 1;
end;
procedure TForm1.ClientSocket1Error(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
try
ClientSocket1.Close;
except
end;
Memo2.Lines.add(IntToStr(Socket.remotePort));
end;
吕雪松你的方法我试过了可是抱错 :asynchronous socket error 10061
--------------------------------------------------------------------------------
来自 :xueminliu 时间 :01-3-3 17:26:47 ID:464312
要区分 tcp 和 udp
oicq 用 udp 协议 ,connect 没有用 ,但是 tcp 可以这样
另外 ,如果你写扫描程序可千万不要这样 ,应该使用别的链接方法 ,否则你的踪迹会被别人
发现 .例如使用 sys 扫描或者 fin 扫描 :
我给你异步 socket 的 api 代码 :
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls,WInSock, ExtCtrls;
const WM_SOCKET=WM_USER+1; //socket 消息
type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
Panel1: TPanel;
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
Sockhd : integer; //socket 句柄
Serv_Addr : Tsockaddr;// 目标地址
procedure SockEvent(var msg: Tmessage);message WM_SOCKET; // 处理 cocket 消息
procedure DspMsg(msg : string); // 显示信息
{ Private declarations }
public
{ Public declarations }
end;
Form1: TForm1;
implementation
{$R *.DFM}
function lookup_hostname(const hostname:string):longint; // 把域名转化成 IP 地址
var
RemoteHost : PHostEnt; (* no, don't free it! *)
ip_address: longint;
begin
ip_address:=-1;
try
if hostname='' then
begin (* no host given! *)
lookup_hostname:=ip_address;
EXIT;
end
else
begin
ip_address:=Winsock.Inet_Addr(PChar(hostname)); (* try a xxx.xxx.xxx.xx first *)
if ip_address=SOCKET_ERROR then begin
RemoteHost:=Winsock.GetHostByName(PChar(hostname));
if (RemoteHost=NIL) or (RemoteHost^.h_length=0) then
begin
lookup_hostname:=ip_address;
EXIT; (* host not found *)
end
else
ip_address:=longint(pointer(RemoteHost^.h_addr_list^)^);
end;
end;
except
ip_address:=-1;
end;
lookup_hostname:=ip_address;
end;
procedure TFOrm1.DspMsg(msg: string);
begin
memo1.Lines.Add(msg+'...');
if Memo1.Lines.Count200 then Memo1.Lines.Delete(0);
end;
procedure TForm1.SockEvent(var msg : tmessage); // 处理 socket 消息
begin
case msg.LParam of
FD_READ: begin // 标识可以读数据 ,当然肯定已经链接上了
dspmsg(' 可以读取数据 ');
//do what you want do
end;
FD_WRITE: begin
dspmsg(' 可以发送数据 ');
//do what you want do
end;
FD_ERROR: begin
dspmsg(' 发生错误 ');
// 如果你是客户端 ,则应该是连接不上 ,即端口没有开
end;
FD_CLOSE: Begin
dspmsg(' 服务器断开连接 ');
// 对方关闭连接
end;
FD_CONNECT: begin
dspmsg(' 连结上服务器 ');
// 表示对方端口开放
end;
FD_ACCEPT: begin
dspmsg(' 接收一个请求 ');
// 这个消息只有服务端可能出现
end;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var wsaData:TwsaData;
begin // 启动 winsock 动态链接库
if WSAStartup (makeword(2,2), wsaData)0 then begin
messagebox(application.handle,' 无法启动 winsock 动态连接库 !',' 警告 ',MB_OK or MB_APPLMODAL or MB_ICONWARNING);
Application.Terminate;
end;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin // 关闭 dll
WSACleanup;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Sockhd := socket(AF_INET,SOCK_STREAM,0); // 创建 socket 句柄
if Sockhd0 then begin
messagebox(application.handle,' 无法创建句柄 !',' 警告 ',MB_OK or MB_APPLMODAL or MB_ICONWARNING);
exit;
end;
Serv_addr.sin_addr.s_addr:= lookup_hostname(edit1.Text); // 主机名
Serv_addr.sin_family := PF_INET;
Serv_addr.sin_port := htons(23); //any port you want to connect
if WSAAsyncSelect(Sockhd,Form1.handle,WM_SOCKET,FD_ACCEPT or FD_CONNECT or FD_CLOSE or FD_READ or FD_WRITE)=SOCKET_ERROR
then begin
messagebox(application.handle,' 无法创建句柄 !',' 警告 ',MB_OK or MB_APPLMODAL or MB_ICONWARNING);
exit;
end; // 异步 socket
connect(sockhd,serv_addr,sizeof(serv_addr)); // 连接 ,结果会在前面的处理函数处理
end;
end.
相信应该可以满足你的要求
请问如何编程区分这两种情况
最好详细一点喔 ( 我很笨的 )
如果在此地址上无主机存在 ,则发出的数据包得不到回应 ,应用程序会等待超时才
认为连接失败 ( 被 firewall 过滤时情况一样 ),若有主机但被扫描的特定端口不存在时 ,
该主机会发出目的端口不存在的应答
至于如何编程实现 ,应该可以由错误码来判断 ,在 OnError 事情中判定 ErrorCode 是多
小 ,再分别处理 ,ErrorCode 的详情参见 Help
这么高深的问题才 50 分 ,少了
端口扫描不是这么简单 ,否则大家都做
首先你扫描人家的端口会留下自己的痕迹 ,系统有日志可以察看
因此我们做端口扫描的的时候绝对不会直接连接别人 ,而是通过地层的接口编程
例如在 TCP 三次握手的第三次放弃 ,对方就不会有日志 ,这称为 sys 扫描
给对方端口发断开连接的请求称为 fin 扫描 .
通过这两种扫描方式都可以得知对方的端口是否开 ,而且不会留下痕迹 .
总之端口扫描里面有很多学问 ,不是这里可以说清除的
怎么做呀 ,如你所说的话好象要直接调用 socket api?
我现在首先关心的是我提出的问题 ,如何编程区分这两种情况 :
1 。此地址上无任何主机存在
2 。有主机但被扫描的特定端口不存在 ( 也可能是被 firewall 过滤了 )
还有 ,为什么我把 clientsocket 的 onread 里的 errorcode 设为 0 了 ,
还是常常会出现 delphi 自己的错误消息提示 ,象 10061,10057 什么的 ,
这好象是另外一种 error code,如能把它屏蔽我想就不会出现提示了 .
是吗?如果是 ,该怎么做呢。
最后 : 如果能给我一个多线程的端口扫描源码 ,我再给 100 分 ( 真的很穷啊 )
我找到了 help 里的有关说明 ( 是在索引中 Error TCP Event 里找到的 )
WinSock Error Codes
The following error codes apply to the WinSock ActiveX Controls.
Error Code Error Message
10004 The operation is canceled.
10013 The requested address is a broadcast address, but flag is not set.
10014 Invalid argument.
10022 Socket not bound, invalid address or listen is not invoked prior to accept.
10024 No more file descriptors are available, accept queue is empty.
10035 Socket is non-blocking and the specified operation will block.
10036 A blocking Winsock operation is in progress.
10037 The operation is completed. No blocking operation is in progress.
10038 The descriptor is not a socket.
10039 Destination address is required.
10040 The datagram is too large to fit into the buffer and is truncated.
10041 The specified port is the wrong type for this socket.
10042 Option unknown, or unsupported.
10043 The specified port is not supported.
10044 Socket type not supported in this address family.
10045 Socket is not a type that supports connection oriented service.
10047 Address Family is not supported.
10048 Address in use.
10049 Address is not available from the local machine.
10050 Network subsystem failed.
10051 The network cannot be reached from this host at this time.
10052 Connection has timed out when SO_KEEPALIVE is set.
10053 Connection is aborted due to timeout or other failure.
10054 The connection is reset by remote side.
10055 No buffer space is available.
10056 Socket is already connected.
10057 Socket is not connected.
10058 Socket has been shut down.
10060 The attempt to connect timed out.
10061 Connection is forcefully rejected.
10201 Socket already created for this object.
10202 Socket has not been created for this object.
11001 Authoritative answer: Host not found.
11002 Non-Authoritative answer: Host not found.
11003 Non-recoverable errors.
11004 Valid name, no data record of requested type.
我想只要对它进行有关操作就能完全屏蔽 winsocket 错误消息 ( 至少
能屏蔽很多 onerror 里的 errorcode 参数无法屏蔽的消息 )
我终于找到原因所在了
在打开 Socket 时也要捕获异常
try
ClientSocket.Open;
except
MessageBox(MainForm.Handle,'Error connecting to this address','Connect',MB_ICONEXCLAMATION);
end;
在 OnError 中最后要将 ErrorCode 置为 0
if ErrorEvent=eeConnect then
begin
Socket.Close;
MessageBox(MainForm.Handle,'Error connecting to this address','Connect',MB_ICONEXCLAMATION);
end
else if ErrorEvent=eeSend then
Socket.Close;
ErrorCode:=0;
你可能无做第一步
而这样也可以区分你所说的两种情况
1 。第二步 OnError 就是此地址上无任何主机存在 ,到超时就触发 OnError 事件
2 。第一步捕捉到异常就是有主机但被扫描的特定端口不存在
如何用Scapy写一个端口扫描器
常见的端口扫描类型有:
1. TCP 连接扫描
2. TCP SYN 扫描(也称为半开放扫描或stealth扫描)
3. TCP 圣诞树(Xmas Tree)扫描
4. TCP FIN 扫描
5. TCP 空扫描(Null)
6. TCP ACK 扫描
7. TCP 窗口扫描
8. UDP 扫描
下面先讲解每种扫描的原理,随后提供具体实现代码。
TCP 连接扫描
客户端与服务器建立 TCP 连接要进行一次三次握手,如果进行了一次成功的三次握手,则说明端口开放。
客户端想要连接服务器80端口时,会先发送一个带有 SYN 标识和端口号的 TCP 数据包给服务器(本例中为80端口)。如果端口是开放的,则服务器会接受这个连接并返回一个带有 SYN 和 ACK 标识的数据包给客户端。随后客户端会返回带有 ACK 和 RST 标识的数据包,此时客户端与服务器建立了连接。如果完成一次三次握手,那么服务器上对应的端口肯定就是开放的。
当客户端发送一个带有 SYN 标识和端口号的 TCP 数据包给服务器后,如果服务器端返回一个带 RST 标识的数据包,则说明端口处于关闭状态。
代码:
#! /usr/bin/python
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
dst_ip = "10.0.0.1"
src_port = RandShort()
dst_port=80
tcp_connect_scan_resp = sr1(IP(dst=dst_ip)/TCP(sport=src_port,dport=dst_port,flags="S"),timeout=10)
if(str(type(tcp_connect_scan_resp))=="type 'NoneType'"):
print "Closed"
elif(tcp_connect_scan_resp.haslayer(TCP)):
if(tcp_connect_scan_resp.getlayer(TCP).flags == 0x12):
send_rst = sr(IP(dst=dst_ip)/TCP(sport=src_port,dport=dst_port,flags="AR"),timeout=10)
print "Open"
elif (tcp_connect_scan_resp.getlayer(TCP).flags == 0x14):
print "Closed"
TCP SYN 扫描
这个技术同 TCP 连接扫描非常相似。同样是客户端向服务器发送一个带有 SYN 标识和端口号的数据包,如果目标端口开发,则会返回带有 SYN 和 ACK 标识的 TCP 数据包。但是,这时客户端不会返回 RST+ACK 而是返回一个只带有 RST 标识的数据包。这种技术主要用于躲避防火墙的检测。
如果目标端口处于关闭状态,那么同之前一样,服务器会返回一个 RST 数据包。
代码:
#! /usr/bin/python
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
dst_ip = "10.0.0.1"
src_port = RandShort()
dst_port=80
stealth_scan_resp = sr1(IP(dst=dst_ip)/TCP(sport=src_port,dport=dst_port,flags="S"),timeout=10)
if(str(type(stealth_scan_resp))=="type 'NoneType'"):
print "Filtered"
elif(stealth_scan_resp.haslayer(TCP)):
if(stealth_scan_resp.getlayer(TCP).flags == 0x12):
send_rst = sr(IP(dst=dst_ip)/TCP(sport=src_port,dport=dst_port,flags="R"),timeout=10)
print "Open"
elif (stealth_scan_resp.getlayer(TCP).flags == 0x14):
print "Closed"
elif(stealth_scan_resp.haslayer(ICMP)):
if(int(stealth_scan_resp.getlayer(ICMP).type)==3 and int(stealth_scan_resp.getlayer(ICMP).code) in [1,2,3,9,10,13]):
print "Filtered"
TCP 圣诞树(Xmas Tree)扫描
在圣诞树扫描中,客户端会向服务器发送带有 PSH,FIN,URG 标识和端口号的数据包给服务器。如果目标端口是开放的,那么不会有任何来自服务器的回应。
如果服务器返回了一个带有 RST 标识的 TCP 数据包,那么说明端口处于关闭状态。
但如果服务器返回了一个 ICMP 数据包,其中包含 ICMP 目标不可达错误类型3以及 ICMP 状态码为1,2,3,9,10或13,则说明目标端口被过滤了无法确定是否处于开放状态。
代码:
#! /usr/bin/python
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
dst_ip = "10.0.0.1"
src_port = RandShort()
dst_port=80
xmas_scan_resp = sr1(IP(dst=dst_ip)/TCP(dport=dst_port,flags="FPU"),timeout=10)
if (str(type(xmas_scan_resp))=="type 'NoneType'"):
print "Open|Filtered"
elif(xmas_scan_resp.haslayer(TCP)):
if(xmas_scan_resp.getlayer(TCP).flags == 0x14):
print "Closed"
elif(xmas_scan_resp.haslayer(ICMP)):
if(int(xmas_scan_resp.getlayer(ICMP).type)==3 and int(xmas_scan_resp.getlayer(ICMP).code) in [1,2,3,9,10,13]):
print "Filtered"
TCP FIN扫描
FIN 扫描会向服务器发送带有 FIN 标识和端口号的 TCP 数据包。如果没有服务器端回应则说明端口开放。
如果服务器返回一个 RST 数据包,则说明目标端口是关闭的。
如果服务器返回了一个 ICMP 数据包,其中包含 ICMP 目标不可达错误类型3以及 ICMP 代码为1,2,3,9,10或13,则说明目标端口被过滤了无法确定端口状态。
代码:
#! /usr/bin/python
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
dst_ip = "10.0.0.1"
src_port = RandShort()
dst_port=80
fin_scan_resp = sr1(IP(dst=dst_ip)/TCP(dport=dst_port,flags="F"),timeout=10)
if (str(type(fin_scan_resp))=="type 'NoneType'"):
print "Open|Filtered"
elif(fin_scan_resp.haslayer(TCP)):
if(fin_scan_resp.getlayer(TCP).flags == 0x14):
print "Closed"
elif(fin_scan_resp.haslayer(ICMP)):
if(int(fin_scan_resp.getlayer(ICMP).type)==3 and int(fin_scan_resp.getlayer(ICMP).code) in [1,2,3,9,10,13]):
print "Filtered"
TCP 空扫描(Null)
在空扫描中,客户端发出的 TCP 数据包仅仅只会包含端口号而不会有其他任何的标识信息。如果目标端口是开放的则不会回复任何信息。
如果服务器返回了一个 RST 数据包,则说明目标端口是关闭的。
如果返回 ICMP 错误类型3且代码为1,2,3,9,10或13的数据包,则说明端口被服务器过滤了。
代码:
#! /usr/bin/python
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
dst_ip = "10.0.0.1"
src_port = RandShort()
dst_port=80
null_scan_resp = sr1(IP(dst=dst_ip)/TCP(dport=dst_port,flags=""),timeout=10)
if (str(type(null_scan_resp))=="type 'NoneType'"):
print "Open|Filtered"
elif(null_scan_resp.haslayer(TCP)):
if(null_scan_resp.getlayer(TCP).flags == 0x14):
print "Closed"
elif(null_scan_resp.haslayer(ICMP)):
if(int(null_scan_resp.getlayer(ICMP).type)==3 and int(null_scan_resp.getlayer(ICMP).code) in [1,2,3,9,10,13]):
print "Filtered"
TCP ACK扫描
ACK 扫描不是用于发现端口开启或关闭状态的,而是用于发现服务器上是否存在有状态防火墙的。它的结果只能说明端口是否被过滤。再次强调,ACK 扫描不能发现端口是否处于开启或关闭状态。
客户端会发送一个带有 ACK 标识和端口号的数据包给服务器。如果服务器返回一个带有 RST 标识的 TCP 数据包,则说明端口没有被过滤,不存在状态防火墙。
如果目标服务器没有任何回应或者返回ICMP 错误类型3且代码为1,2,3,9,10或13的数据包,则说明端口被过滤且存在状态防火墙。
#! /usr/bin/python
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
dst_ip = "10.0.0.1"
src_port = RandShort()
dst_port=80
ack_flag_scan_resp = sr1(IP(dst=dst_ip)/TCP(dport=dst_port,flags="A"),timeout=10)
if (str(type(ack_flag_scan_resp))=="type 'NoneType'"):
print "Stateful firewall presentn(Filtered)"
elif(ack_flag_scan_resp.haslayer(TCP)):
if(ack_flag_scan_resp.getlayer(TCP).flags == 0x4):
print "No firewalln(Unfiltered)"
elif(ack_flag_scan_resp.haslayer(ICMP)):
if(int(ack_flag_scan_resp.getlayer(ICMP).type)==3 and int(ack_flag_scan_resp.getlayer(ICMP).code) in [1,2,3,9,10,13]):
print "Stateful firewall presentn(Filtered)"
TCP窗口扫描
TCP 窗口扫描的流程同 ACK 扫描类似,同样是客户端向服务器发送一个带有 ACK 标识和端口号的 TCP 数据包,但是这种扫描能够用于发现目标服务器端口的状态。在 ACK 扫描中返回 RST 表明没有被过滤,但在窗口扫描中,当收到返回的 RST 数据包后,它会检查窗口大小的值。如果窗口大小的值是个非零值,则说明目标端口是开放的。
如果返回的 RST 数据包中的窗口大小为0,则说明目标端口是关闭的。
代码:
#! /usr/bin/python
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
dst_ip = "10.0.0.1"
src_port = RandShort()
dst_port=80
window_scan_resp = sr1(IP(dst=dst_ip)/TCP(dport=dst_port,flags="A"),timeout=10)
if (str(type(window_scan_resp))=="type 'NoneType'"):
print "No response"
elif(window_scan_resp.haslayer(TCP)):
if(window_scan_resp.getlayer(TCP).window == 0):
print "Closed"
elif(window_scan_resp.getlayer(TCP).window 0):
print "Open"
UDP扫描
TCP 是面向连接的协议,而UDP则是无连接的协议。
面向连接的协议会先在客户端和服务器之间建立通信信道,然后才会开始传输数据。如果客户端和服务器之间没有建立通信信道,则不会有任何产生任何通信数据。
无连接的协议则不会事先建立客户端和服务器之间的通信信道,只要客户端到服务器存在可用信道,就会假设目标是可达的然后向对方发送数据。
客户端会向服务器发送一个带有端口号的 UDP 数据包。如果服务器回复了 UDP 数据包,则目标端口是开放的。
如果服务器返回了一个 ICMP 目标不可达的错误和代码3,则意味着目标端口处于关闭状态。
如果服务器返回一个 ICMP 错误类型3且代码为1,2,3,9,10或13的数据包,则说明目标端口被服务器过滤了。
但如果服务器没有任何相应客户端的 UDP 请求,则可以断定目标端口可能是开放或被过滤的,无法判断端口的最终状态。
代码:
#! /usr/bin/python
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
dst_ip = "10.0.0.1"
src_port = RandShort()
dst_port=53
dst_timeout=10
def udp_scan(dst_ip,dst_port,dst_timeout):
udp_scan_resp = sr1(IP(dst=dst_ip)/UDP(dport=dst_port),timeout=dst_timeout)
if (str(type(udp_scan_resp))=="type 'NoneType'"):
retrans = []
for count in range(0,3):
retrans.append(sr1(IP(dst=dst_ip)/UDP(dport=dst_port),timeout=dst_timeout))
for item in retrans:
if (str(type(item))!="type 'NoneType'"):
udp_scan(dst_ip,dst_port,dst_timeout)
return "Open|Filtered"
elif (udp_scan_resp.haslayer(UDP)):
return "Open"
elif(udp_scan_resp.haslayer(ICMP)):
if(int(udp_scan_resp.getlayer(ICMP).type)==3 and int(udp_scan_resp.getlayer(ICMP).code)==3):
return "Closed"
elif(int(udp_scan_resp.getlayer(ICMP).type)==3 and int(udp_scan_resp.getlayer(ICMP).code) in [1,2,9,10,13]):
return "Filtered"
print udp_scan(dst_ip,dst_port,dst_timeout)
下面解释下上述代码中的一些函数和变量:
RandShort():产生随机数
type():获取数据类型
sport:源端口号
dport:目标端口号
timeout:等待相应的时间
haslayer():查找指定层:TCP或UDP或ICMP
getlayer():获取指定层:TCP或UDP或ICMP
以上扫描的概念可以被用于“多端口扫描”,源码可以参考这里:
Scapy 是一个非常好用的工具,使用它可以非常简单的构建自己的数据包,还可以很轻易的处理数据包的发送和相应。
(译者注:上述所有代码均在Kali 2.0下测试通过,建议读者在Linux环境下测试代码,如想在Windows上测试,请参见 Scapy官方文档 配置好scapy环境)
如何用java实现tcp connect,tcp syn端口扫描
connect比较简单,就是用Socket+多线程,每个端口创建一次连接,没连上是不会往下执行的,会抛出异常,网上有源码,都是这个方法。
syn和FIN还不知道咋实现,可以考虑用本地方法。
多线程(端口扫描器)是如何提高程序的执行效率的?
你认为多线程CPU时间片不断切换是影响多线程执行的原因,对吧。
但是呢,要知道现在CPU主频都是很快的(微秒级甚至纳秒级),所以有一些操作CPU只需要很少时间就可以完成了,其它的时间,如果没有主动调度它,CPU都处于空闲状态。比方说,TCP/UDP连接时,一方发出数据包,在等待另一方返回数据包的过程中(毫秒级)(最简单的,可以参考TCP三次握手的过程),这段时间就处于空闲状态。
这就是多线程为什么高效率的原因了,操作系统可以充分把这毫秒级的时间利用起来,发起另一个TCP连接,然后再在这个连接的网络延迟时间内,继续新的连接扫描……
这就是多线程的优势了,楼主忽略了多线程可以利用CPU空余时间这个关键问题,哪怕多线程之间的时间片会额外花费更多的CPU时间,但是空余时间的利用完全可以弥补这相当小的开销。
求:网络端口扫描器的算法
闪电1.0 是一个多线程的端口扫描工具,用于进行狂速端口扫描。它具有极快的速度 和方便友好的操作界面,能快速地对大网段范围进行 Connect方式端口扫描。同时具有获取端口标识的功能,可以用来快速地获取端口标识(Banner),能对80端口标识进行特别处理,能方便地获取Web Server类型。当扫描到木马程序端口时,可以提示常见木马。 主要功能如下 ( 1) 发现因特网上的一个网络或者一台主机。 (2) 一旦发现一台主机,就能扫描到开放端口号和提供的服务, 能对常见木马端口返回标识。 (3)可以进行域名正向解析和反向解析。 (4)可以获取局域网在线主机的MAC地址和主机名。 (5)提供了基于窗口Ping功能和局域网信使服务。 (6)可以获取本机网络配制相关信息,如本机IP, 子网掩码,MAC地址,网卡类型和网关IP和DNS的IP。
你可以到 去下载
0条大神的评论