使用Python编写渗透测试工具——学习笔记


0x01.Socket模块

安装socket模块

pip install socketssh

重要的函数(socket.py)

import socket

# --------------------------------------------------------
# s = socket.socket()     #初始化tcp类型的socket
# print(s)
# s.bing(('127.0.0.1', 2345))     #初始化socket,bing((host,port))
# s.listen(5)     #最大连接数
# s.connect(('127.0.0.1', 2345))      #客户端连接
# s.sendall(bytes("hello,my friend?", encoding="utf-8"))      #发送字符到socket
# s.recv(1024)        #接受数据,接受的长度
# ---------------------------------------------------------

服务端的编写(server.py)

import socket

# --------------------------------------------------------
# s = socket.socket()     #初始化tcp类型的socket
# print(s)
# s.bing(('127.0.0.1', 2345))     #初始化socket,bing((host,port))
# s.listen(5)     #最大连接数
# s.connect(('127.0.0.1', 2345))      #客户端连接
# s.sendall(bytes("hello,my friend?", encoding="utf-8"))      #发送字符到socket
# s.recv(1024)        #接受数据,接受的长度
# ---------------------------------------------------------

可能会出现的问题:客户端接收不到字符。
解决办法:发送的字符使用bytes函数转换
客户端的编写(client.py)

import socket
s2 = socket.socket()
s2.connect(('127.0.0.1',1234))
data = s2.recv(1024)
s2.close()
print('received:', repr(data))

0x02.python-nmap模块

安装python-nmap模块

pip install python-nmap

编写出一个自定义输出的扫描模块(基于 nmap)

import nmap
nm = nmap.PortScanner()     #定义扫描类
ip = input('please input host_ip(eg:192.168.1.1, 192.168.1.1\\24):')
port = input('please input port(eg:80,1-1024,default:1-1024):')
if port == '':
    port = '1-1024'
arguments = input('please input arguments(eg:-sP,-PR,-sS,-sT,-O,-sV,default:-sV):')
if arguments == '':
    arguments = '-sV'
nm.scan(ip, port, arguments)        #对指定目标进行扫描
for host in nm.all_hosts():     #对扫描的主机进行遍历
    print("-"*100)
    print(nm.command_line())        #显示扫描命令行
    print('Host : %s (%s)'% (host,nm[host].hostname()))     #输出扫描主机名
    print('State : %s'% nm[host].state())       #输出主机登录状态
    for proto in nm[host].all_protocols():      #对获取到的网络协议类型进行遍历
        print("-"*100)
        print('Protocol : %s' % proto)     #输出协议类型
        lport = nm[host][proto].keys()      #获取TCP所有的端口号
        for port in lport:      #对端口号进行遍历
            print('port : %s\t state : %s\t product : %s\t' % (port,nm[host][proto][port]['state'],nm[host][proto][port]['product']))
            #食醋胡端口号,状态,产品信息

可能会出现的问题: 提示partially initialized module ‘nmap‘ has no attribute ‘PortScanner‘…
解决办法:传送门


0x03.Scapy模块

a.基本操作

scapy可以在kali中直接运行,采用命令行交互模式

┌──(root💀kali)-[~]
└─# scapy            
INFO: Can't import PyX. Won't be able to use psdump() or pdfdump().
                                      
                     aSPY//YASa       
             apyyyyCY//////////YCa       |
            sY//////YSpcs  scpCY//Pp     | Welcome to Scapy
 ayp ayyyyyyySCP//Pp           syY//C    | Version 2.4.4
 AYAsAYYYYYYYY///Ps              cY//S   |
         pCCCCY//p          cSSps y//Y   | https://github.com/secdev/scapy
         SPPPP///a          pP///AC//Y   |
              A//A            cyP////C   | Have fun!
              p///Ac            sC///a   |
              P////YCpc           A//A   | Craft packets before they craft
       scccccp///pSP///p          p//Y   | you.
      sY/////////y  caa           S//P   |                      -- Socrate
       cayCyayP//Ya              pY/Ya   |
        sY/PsY////YCc          aC//Yp 
         sc  sccaCY//PCypaapyCP//YSs  
                  spCPY//////YPSps    
                       ccaacs         
                                       using IPython 7.20.0
>>> 

定义数据包

>>> ip=IP()
>>> ip
<IP  |>
>>> 

IP最重要的就是两个属性,一个src,一个dst
构造一个发往192.168.1.110的ip数据包

>>> ip=IP(dst="192.168.1.110")
>>> ip
<IP  dst=192.168.1.110 |>
>>> 

发给一个ip范围

>>> ip=IP(dst="192.168.1.1/24")
>>> ip
<IP  dst=Net('192.168.1.1/24') |>
>>> 

查看每一个数据包

>>> [p for p in ip]
[<IP  dst=192.168.1.0 |>,
 <IP  dst=192.168.1.1 |>,
 <IP  dst=192.168.1.2 |>,
 <IP  dst=192.168.1.3 |>,
 <IP  dst=192.168.1.4 |>,
 <IP  dst=192.168.1.5 |>,
 <IP  dst=192.168.1.6 |>,
 <IP  dst=192.168.1.7 |>,
 <IP  dst=192.168.1.8 |>,
 <IP  dst=192.168.1.9 |>,
....
 <IP  dst=192.168.1.255 |>]
>>> 

使用Ether命令够着ARP请求和答应包

>>> Ether(dst="ff:ff:ff:ff:ff:ff")
<Ether  dst=ff:ff:ff:ff:ff:ff |>

scapy的分层通过符号“/”实现,一个数据包可以由多层协议组成,下面是构造一个Ether()/IP()/TCP()来完成一个数据包

>>> Ether()/IP()/TCP()
<Ether  type=IPv4 |<IP  frag=0 proto=tcp |<TCP  |>>>
>>> 

构造一个http数据包
IP()TCP()/“GET/HTTP/1.0/r/n/r/n”

使用ls查看类属性,例如Ether

>>> ls(Ether())
WARNING: Mac address to reach destination not found. Using broadcast.
dst        : DestMACField                        = 'ff:ff:ff:ff:ff:ff' (None)
src        : SourceMACField                      = '00:0c:29:0e:a4:2d' (None)
type       : XShortEnumField                     = 36864           (36864)
>>> 

ip属性,并对需要的属性进行设置

>>> IP(src="192.168.1.1",dst="192.168.1.110",ttl=64)
<IP  ttl=64 src=192.168.1.1 dst=192.168.1.110 |>
>>> 

b.发送接收函数

send()和sendp(),前者用来发送IP数据包,在第二层,后者用来发送Ether数据包,在第三层。

>>> send(IP(src="192.168.1.1",dst="192.168.1.110"))
.
Sent 1 packets.
>>> sendp(Ether(dst="ff:ff:ff:ff:ff:ff"))
.
Sent 1 packets.

发送成功会显示Sent 1 packets.
如果希望发送的内容是一个随机填充的数据包,而且要保证数据包的正确性,可以使用fuzz()函数,例如,构造一个发往192.168.1.1的TCP数据包

>>> send(IP(dst="192.168.1.1")/fuzz(TCP()))
.
Sent 1 packets.
>>> 

三个接收发送数据包函数:
sr(),sr1(),srp(),其中sr()和sr1()用于第三层,ip或arp等,arp()用于第二层,Ether
构造一个向192.168.1.110发送一个ICMP数据包

>>> sr(IP(dst="192.168.1.110")/ICMP())
Begin emission:
Finished sending 1 packets.
.*
Received 2 packets, got 1 answers, remaining 0 packets
(<Results: TCP:0 UDP:0 ICMP:1 Other:0>,
 <Unanswered: TCP:0 UDP:0 ICMP:0 Other:0>)

received表示收到的数据包个数,answers表示对应的应答数据包
sr()函数由两个返回值,一个是收到应答的包和对应的应答,一个是未收到应答的包

>>> ans,unans=sr(IP(dst="192.168.1.110")/ICMP())
Begin emission:
Finished sending 1 packets.
...*
Received 4 packets, got 1 answers, remaining 0 packets
>>> ans
<Results: TCP:0 UDP:0 ICMP:1 Other:0>
>>> unans
<Unanswered: TCP:0 UDP:0 ICMP:0 Other:0>
>>> 
>>>> ans.summary()
IP / ICMP 192.168.1.104 > 192.168.1.110 echo-request 0 ==> IP / ICMP 192.168.1.110 > 192.168.1.104 echo-reply 0 / Padding
>>> unans.summary()
>>> 

使用summary可以查看包的内容
sr1()与sr()基本一样,但是只返回一个应答的包

>>> pr =sr1(IP(dst="192.168.1.110")/ICMP())
Begin emission:
Finished sending 1 packets.
.*
Received 2 packets, got 1 answers, remaining 0 packets
>>> pr
<IP  version=4 ihl=5 tos=0x0 len=28 id=28518 flags= frag=0 ttl=128 proto=icmp chksum=0x4754 src=192.168.1.110 dst=192.168.1.104 |<ICMP  type=echo-reply code=0 chksum=0xffff id=0x0 seq=0x0 |<Padding  load='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |>>>                         
>>> 

一般可以使用sr1()函数来测试某个端口是否开放,采用半开扫描(SYN)

>>> sr1(IP(dst="192.168.1.110")/TCP(dport=445,flags="S"))
Begin emission:
Finished sending 1 packets.
.*
Received 2 packets, got 1 answers, remaining 0 packets
<IP  version=4 ihl=5 tos=0x0 len=44 id=28550 flags=DF frag=0 ttl=128 proto=tcp chksum=0x71f src=192.168.1.110 dst=192.168.1.104 |<TCP  sport=microsoft_ds dport=ftp_data seq=1137720698 ack=1 dataofs=6 reserved=0 flags=SA window=65392 chksum=0x9162 urgptr=0 options=[('MSS', 1460)] |<Padding  load='\x00\x00' |>>>
>>> 

445端口开放

>>> sr1(IP(dst="192.168.1.110")/TCP(dport=80,flags="S"))
Begin emission:
Finished sending 1 packets.
............................................................................................................

80端口未开放

c.sniff()函数

捕获的数据包不会实时显示,只有当使用Ctrl+C强制暂停,才会显示

>>> sniff()
^C<Sniffed: TCP:142 UDP:191 ICMP:0 Other:26>

使用参数过滤,例如指捕获192.168.1.110有关的数据包

>>> sniff(filter="host 192.168.1.110")
^C<Sniffed: TCP:17 UDP:7 ICMP:0 Other:0>
>>> 

也可以用来指定协议,可以使用or和and
整合一下:
filter= 筛选ip和协议类型等
iface= 指定进行监听的网卡
count= 指定监听数据包的数量
下面构造一个监听192.168.1.110的3个icmp数据包,使用eth0网卡,由于基本没有人向目标发icmp数据包,要自己构建一个,ping即可

ping 192.168.1.110
>>> sniff(filter="host 192.168.1.110 and icmp",count=3,iface="eth0")
<Sniffed: TCP:0 UDP:0 ICMP:3 Other:0>

这时候,可以使用_来查看结果,并赋值给变量,查看内容

>>> _
<Sniffed: TCP:0 UDP:0 ICMP:3 Other:0>
>>> a=_
>>> a.summary()
Ether / IP / ICMP 192.168.1.104 > 192.168.1.110 echo-request 0 / Raw
Ether / IP / ICMP 192.168.1.110 > 192.168.1.104 echo-reply 0 / Raw
Ether / IP / ICMP 192.168.1.104 > 192.168.1.110 echo-request 0 / Raw
>>> 

d.简单的任务实现

任务一:实现一次ACK类型的端口扫描,例如,对192.168.1.110的21,135,443,445端口是否屏蔽进行扫描,注意是屏蔽不是关闭,采用ACK模式扫描

>>> ans,unans=sr(IP(dst="192.168.1.110")/TCP(dport=[21,135,443,445],flags="A"
...: ))
Begin emission:
Finished sending 4 packets.
...............................................................................................................................................................................................................................................................................................................................................^C

正常应该会有包显示,但是本人这个一直无响应,判定为屏蔽状态


任务二:一个简单的端口扫描器
正常情况下,一个端口处于屏蔽状态,那么它不会产生任何响应报文,如果开放,那么当它收到syn数据包后,会回应个一个ack数据包,反之,端口处于关闭状态时,收到一个syn数据包后,会回应一个rst数据包。(使用fuzz()填充数据包,否则可能端口不响应)

>>> ans,unans=sr(IP(dst="192.168.1.1")/fuzz(TCP(dport=[80],flags="S")))
Begin emission:
Finished sending 1 packets.
..*
Received 3 packets, got 1 answers, remaining 0 packets

接下来,如果r[TCP].flags18,则表示返回数据包的值为0x012(SYN,ACK),为开放状态,如果r[TCP].flags20则表示关闭,数值为0x014(RST,ACK)

>>> for s,r in ans:
...:     if r[TCP].flags==18:
...:         print("port 80 up")
...: 
port 80 up

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我重来不说话

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值