[TOC]
0x00 前言
在安全工作者或者渗透测试中,我们常常需要自己造轮子来写自动化利用的脚本,所以Python脚本能更快的帮助我们编写响应扫描器以及可利用脚本;
扩展包:
- https://www.lfd.uci.edu/~gohlke/pythonlibs/
0x01 IP地址处理模块
描述:在对很多业务进行扫描的时候,我们可能需要输入一个IP段对其扫描,在写Python脚本中免不了进行IP地址的计算包括网段/网络掩码/广播地址/子网数/IP类型等等;
因此Python给我们提供了一个强大的第三方模块IPy,安装模块执行pip install IPy
即可;
(1) IP地址/网段基本处理:
代码语言:javascript复制#/usr/bin/env python
from IPy import IP
#1.分辨IPv4还是IPv6以及IP类型
ipv4=IP('192.168.1.0/24').version()
ipv6=IP('::1').version()
#4 代表IPv4 6 代表IPv6
print(ipv4," ",ipv6) # 4 6
iptype = ip.iptype() #'PRIVATE' 代表私有地址
IP('132.54.56.25').iptype() #'PUBLIC' 代表公有地址
print(IP('::1').iptype()) #LOOPBACK
print(IP('2001:0658:022a:cafe:0200::1').iptype()) #ALLOCATED RIPE NCC
#2.网段IP数以及IP地址清单
ip=IP('192.168.10.0/24')
len(ip) #也是网络子网数
print(ip.len()) #输入该网段的IP数量 256
for x in ip: #地址清单
print(x)
print(str(ip[2]))
#打印结果
# 192.168.10.0
# ....
# 192.168.10.255
#3.IP反向解析名称
ip=IP('192.168.1.8')
revname = ip.reverseNames() #['8.1.168.192.in-addr.arpa.']
#4.IP转换
IP("192.168.1.1").int() #3232235777 IP地址转整形
IP("192.168.1.1").strHex() #'0xc0a80101' #IP地址转十六进制
IP("192.168.1.1").strBin() #'11000000101010000000000100000001' #转二进制
print(IP(0xc0a80101)) #十六进制转成IP 192.168.1.1 | IP('192.168.1.1')
print(IP(3232235777)) #十进制转成IP192.168.1.1
#5.网络地址子网掩码生成网段格式
IP('192.168.1.0').make_net('255.255.255.0') #IP('192.168.1.0/24')
IP('192.168.1.0/255.255.0.0',make_net=True) #IP('192.168.0.0/16')
IP('10.10.0.0/255.0.0.0',make_net=True) #IP('10.0.0.0/8')
IP('10.10.0.0-10.10.255.255',make_net=True) #IP('10.10.0.0/16')
#6.通过网络转换成IP以及子网掩码
IP('10.0.0.0/8').net() #IP('10.0.0.0')
IP('10.0.0.0/8').broadcast() #IP('10.255.255.255') 根据网段求得子网掩码
#通过StrNormal方法指定不同的wantprefixlen参数值定制不同的输出类型的网段
#wantprefixlen取值
0 : 无返回,如192.168.1.0
1 :prefix格式 a.b.c.0/24 | 2001:658:22a:cafe::/64 #默认格式
2 :decimal netmask格式 a.b.c.d/255.255.255.0
3 :lastIP格式 a.b.c.0-a.b.c.255 2001:658:22a:cafe::-2001:658:22a:cafe:ffff:ffff:ffff:ffff
#示例演示:
IP('192.168.1.0/30').strNormal(0) #'192.168.1.0' 这里需要知道子网掩码的知识点
IP('192.168.1.4/30').strNormal(0) #'192.168.1.4' 2 ^ (32-30 = 2) = 4 IP为一组
IP('192.168.1.0/30').strNormal(1) #'192.168.1.0/30'
IP('192.168.1.0/30').strNormal() #'192.168.1.0/30'
IP('192.168.1.0/30').strNormal(2) #'192.168.1.0/255.255.255.252'
IP('192.168.1.0/30').strNormal(3) #'192.168.1.0-192.168.1.3' #根据子网掩码换算主机个数
(2) 多网络计算对比: 比较两个网段是否存在包含重叠等关系,IPy支持蕾仕于数值型数据的比较,可以帮助IP对象进行比较
代码语言:javascript复制#!/usr/bin/env python
#示例1.判断网段的区间
IP("192.168.0.0/16") < IP("192.168.1.0/24") #True
IP("192.168.0.0/16") > IP("192.168.1.0/24") #False
#判断IP地址或者网段是否包含在另外一个网段:
IP("192.168.0.0/16") in IP("192.168.1.0/24") #False
IP("192.168.1.0/32") in IP("192.168.1.0/24") #True
#判断两个网段是否重叠,采用IP提供的overlaps方法
IP("192.168.1.0/32").overlaps("192.168.1.0/24") #1 包含
IP("192.168.2.5").overlaps("192.168.1.0/24") #0 不包含
实际案例:
IPy模块使用案例查看
代码语言:javascript复制Useage: > ipinfo.py -t/-m 192.168.1.1
-t 指定IP类型地址进行相互转换二进制IP/整数IP/十六进制
-m 指定IP类地址或者IP段查看信息
IP格式1:192.168.1.1
IP格式2:192.168.1.0/24
IP格式3:192.168.1.1-192.168.1.254
0x02 DNS处理模块
描述:Python中的dbspython是实现一个DNS工具包,支持所有的记录类型,用于查询/传输并动态更新ZONE信息,同时支持所有的记录类型;
模块安装:pip install dnspython
1.方法详解
dns提供一个DNS解析类-resolver,使用它的query方法来实现查询功能,query方法定义如下:
代码语言:javascript复制import dns.resolver
def query(qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN,
tcp=False, source=None, raise_on_no_answer=True,
source_port=0, lifetime=None):
rdclass参数用于指定网络类型,可选值有IN,CH与HS,其中IN为默认; tcp参数表示是否启用TCP协议; 其中rdtype参数用来指定RR资源类型:
- A 记录 : 将主机名转换成为IP地址
- MX 记录 :邮件交换记录,定义邮件服务器的域名
- CNAME 记录 : 指定别名记录,实现域名间的映射
- NS 记录 : 标记区域的域名服务器及授权子域名
- PTR 记录 :反向解析与A记录相反,将IP地址转换为主机名
- SOA 记录 :SOA标记一个起始授权区的定义
示例演示:
代码语言:javascript复制#示例1.A记录 通过reponse.answer方法获取查询回应信息
for i in dns.resolver.query('www.qq.com.cn','A').response.answer:
for j in i.items:
print("A记录:%s" % j.address) #A记录:61.129.226.218
for i in dns.resolver.query('qq.com','A').response.answer:
for j in i.items:
print("A记录:%s" % j.address)
# A记录:59.37.96.63
# A记录:58.60.9.21
# A记录:180.163.26.39
#示例2.MX记录
for i in dns.resolver.query('qq.com','MX'):
print("MX preference = %s , mail exchanger = %s" %(i.preference,i.exchange))
#遍历出首选项以及邮件交换服务器
# MX preference = 20 , mail exchanger = mx2.qq.com.
# MX preference = 30 , mail exchanger = mx1.qq.com.
# MX preference = 10 , mail exchanger = mx3.qq.com.
#示例3.NS记录 (输入根域名)
for i in dns.resolver.query('qq.com','NS').response.answer:
for j in i.items:
print("NS记录:%s" %j)
#执行结果
NS记录:ns2.qq.com.
NS记录:ns1.qq.com.
NS记录:ns4.qq.com.
NS记录:ns3.qq.com.
#示例4.CNAME记录
for i in dns.resolver.query('weiyigeek.github.io','CNAME').response.answer:
for j in i.items:
print("CNAME记录:%s" %j) #CNAME记录:www.weiyigeek.github.io.
#示例5.SOA授权区域定义
for i in dns.resolver.query('baidu.com','SOA'):
print(i)
#dns.baidu.com. sa.baidu.com. 2012141218 300 300 2592000 7200
实际案例: Github查看
WeiyiGeek.dnsinfo信息查看
0x01 web探测模块
pycurl 模块
描述:pycurl是一个用C语言写的libcurl Python实现,功能强大支持多种通信协议,类似于linux下Curl命令功能的Python封装简单易用; 模块安装:
代码语言:javascript复制#安装
pip install pycurl #可能会报错 Please specify --curl-dir=/path/to/built/libcurl (安装后重新执行)
#如果报错访问:https://www.lfd.uci.edu/~gohlke/pythonlibs/#pycurl 下载pycurl-7.43.0.3-cp37-cp37m-win32.whl (根据您Python版本位数)
Processing c:usersweiyigeekdownloadspycurl-7.43.0.3-cp37-cp37m-win32.whl
Installing collected packages: pycurl
Successfully installed pycurl-7.43.0.3
#查看版本
python -c "import pycurl;print(pycurl.version)"
'PycURL/7.43.0.3 libcurl/7.64.1 OpenSSL/1.1.1c zlib/1.2.11 c-ares/1.15.0 libssh2/1.8.2'
主要功能:
- web服务质量探测:HTTP状态码/请求延时/HTTP头信息/下载速度等等
- 探测服务的可用性以及服务响应速度
模块常用方法:
代码语言:javascript复制pcurl = pycurl.Curl #创建对象
pcurl.setopt(option,value) #curl_easy_setopt 方法,value值会依赖option
pcurl.perform() #实现pycurl对象的请求提交
pcurl.getinfo(option) #获取pycurl对象请求响应信息
pcurl.close()
利用libcurl包提供的常量值来达到探测Web服务质量的目的:
代码语言:javascript复制#setopt
pc.setopt(pycurl.URL, URL) #定义请求的URL
pc.setopt(pycurl.USERAGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0") #设置http请求头USERAGENT
pc.setopt(pycurl.CONNECTTIMEOUT, 5) #连接等待时间,0为不等待
pc.setopt(pycurl.TIMEOUT, 5) #请求超时时间
pc.setopt(pycurl.MAXREDIRS, 1) #最大的重定向数
pc.setopt(pycurl.NOPROGRESS, 1) #是否屏蔽下载进度条 非0则屏蔽
pc.setopt(pycurl.MAXREDIRS, 1) #指定HTTP重定向的最大数为1
pc.setopt(pycurl.DNS_CACHE_TIMEOUT, 30) #报错DNS信息为30s
pc.setopt(pycurl.FORBID_REUSE, 1) #完成交互后断开连接不重用
pc.setopt(pycurl.FERSH_CONNECT, 1) #强制获取新的连接,即代替缓存中的连接
pc.setopt(pycurl.HEADERFUNCTION, getheader) #将返回的HTTP HEADER定向到回调环境getheader
pc.setopt(pycurl.WRITEFUNCTION, getbody) #将返回的HTTP BOBY定向到回调环境getboby
pc.setopt(pycurl.WRITEHEADER, index) #将返回HTTP HEADER定向到indexfile文件对象
pc.setopt(pycurl.WRITEDATA, index) #将返回的HTML内容定向到indexfile文件对象中
#getinfo
print("HTTP状态码: %s" %(pc.getinfo(pc.HTTP_CODE)))
print("DNS解析时间: %.2f ms" %(pc.getinfo(pc.NAMELOOKUP_TIME)*1000))
print("建立连接时间: %.2f ms" %(pc.getinfo(pc.CONNECT_TIME)*1000))
print("准备传输时间: %.2f ms" %(pc.getinfo(pc.PRETRANSFER_TIME)*1000))
print("传输开始时间: %.2f ms" %(pc.getinfo(pc.STARTTRANSFER_TIME)*1000))
print("传输结束总时间: %.2f ms" %(pc.getinfo(pc.TOTAL_TIME)*1000))
print("重定向消耗的时间: %.2f ms" %(pc.getinfo(pc.REDIRECT_TIME)*1000))
print("下载数据包大小: %d bytes/s" %(pc.getinfo(pc.SIZE_DOWNLOAD)))
print("上传数据包大小: %d bytes/s" %(pc.getinfo(pc.SIZE_UPLOAD)))
print("平均下载速度: %d bytes/s" %(pc.getinfo(pc.SPEED_DOWNLOAD)))
print("平均上传速度: %d bytes/s" %(pc.getinfo(pc.SPEED_UPLAOD)))
print("HTTP头部大小: %d byte" %(pc.getinfo(pc.HEADER_SIZE)))
实际案例:
代码语言:javascript复制#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File : pycurldemo.py
# @CreateTime : 2019/7/31 15:23
# @Author : WeiyiGeek
# @Function : 实现探测Web服务质量与网页截图
# @Software: PyCharm
import sys, time
import pycurl
URL="http://www.weiyigeek.github.io"
def request():
"""
构建请求
:return:
"""
pc = pycurl.Curl() #构建一个Curl对象
pc.setopt(pycurl.URL, URL) #定义请求的URL
pc.setopt(pycurl.CONNECTTIMEOUT, 5) #连接等待时间,0为不等待
pc.setopt(pycurl.TIMEOUT, 5) #请求超时时间
pc.setopt(pycurl.NOPROGRESS, 1) #疲敝下载进度条 与 curl 相似
pc.setopt(pycurl.FORBID_REUSE, 1) #完成交互后断开连接不重用
pc.setopt(pycurl.MAXREDIRS, 1) #指定HTTP重定向的最大数为1
pc.setopt(pycurl.DNS_CACHE_TIMEOUT, 30) #报错DNS信息为30s
pc.setopt(pycurl.USERAGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0")
#创建一个文件对象以'wb'方式打开,存储返回的http头部信息以及页面内容;
with open('content.txt', 'wb') as index:
pc.setopt(pycurl.WRITEHEADER, index) #将返回HTTP HEADER定向到indexfile文件对象
pc.setopt(pycurl.WRITEDATA, index) #将返回的HTML内容定向到indexfile文件对象中
try:
pc.perform() #提交请求
except Exception as e:
print("connect Error:" str(e))
sys.exit()
return pc
def reponse(pc):
"""
返回请求响应数据解析
:param pc:
:return:
"""
print("HTTP状态码: %s" %(pc.getinfo(pc.HTTP_CODE)))
print("DNS解析时间: %.2f ms" %(pc.getinfo(pc.NAMELOOKUP_TIME)*1000))
print("建立连接时间: %.2f ms" %(pc.getinfo(pc.CONNECT_TIME)*1000))
print("准备传输时间: %.2f ms" %(pc.getinfo(pc.PRETRANSFER_TIME)*1000))
print("传输开始时间: %.2f ms" %(pc.getinfo(pc.STARTTRANSFER_TIME)*1000))
print("传输结束总时间: %.2f ms" %(pc.getinfo(pc.TOTAL_TIME)*1000))
print("下载数据包大小: %d bytes/s" %(pc.getinfo(pc.SIZE_DOWNLOAD)))
print("HTTP头部大小: %d byte" %(pc.getinfo(pc.HEADER_SIZE)))
print("平均下载速度: %d bytes/s" %(pc.getinfo(pc.SPEED_DOWNLOAD)))
print("重定向消耗的时间: %.2f ms" % (pc.getinfo(pc.REDIRECT_TIME) * 1000))
pc.close()
def main():
"""
请求函数调用
响应函数调用
:return:
"""
pcurl = request()
reponse(pcurl)
return 0
if __name__ == '__main__':
main()
WeiyiGeek.pycurl模块