网络安全-scapy学习笔记

目录

scapy信息

函数汇总

数据包

Ether

IP

ICMP

TCP

内核的TCP堆栈

发送函数

send

sendp

发送接收函数

sr1

应用

地址段IP发现-Ping

端口扫描

Fuzz

缺点


scapy信息

官网:scapy

用户手册:scapy docs

一个python库,用于发送Tcp消息、Udp消息,进行fuzz等。

函数汇总

scapy函数汇总
函数 作用

数据包

生成数据包
IP IP数据包
TCP TCP数据包,基于IP
ICMP ICMP数据包,基于IP
   
   
发送 发送数据包
send 发送数据包,三层
sendp 发送数据包,两层
sr1 发送三层数据包并接收一个数据包

数据包

Ether

还没填过参数

IP

IP数据包
参数 含义
version   = 4 版本
  ihl       = None  
  tos       = 0x0  
  len       = None  
  id        = 1  
  flags     =  
  frag      = 0  
  ttl       = 64  
  proto     = tcp 协议
  chksum    = None  
  src       = 39.156.69.79 源IP地址
  dst       = 121.17.123.130 目的IP地址

目的IP一般是我们想要发送数据包的,一般是指定的,我们可以伪造源IP地址,比如ping下百度的,以后进行主机发现之类的,源地址可以写百度的ip。

ICMP

还没填过参数

ping的ICMP

PING的时候是ICMP数据包,在应用的时候就写了脚本,发送的ICMP,但是也没填参数

TCP

TCP数据包
参数 含义

     sport     = ftp_data

源端口号
     dport     = http 目的端口号
     seq       = 0  
     ack       = 0  
     dataofs   = None  
     reserved  = 0  
     flags     = S  
     window    = 8192  
     chksum    = None  
     urgptr    = 0  
     options   = []  

内核的TCP堆栈

import socket
from scapy.packet import Raw
from scapy.sendrecv import sr1
from scapy.supersocket import StreamSocket


def tcpStack():
    s = socket.socket()
    s.connect(("www.httpbin.org", 80))
    ss = StreamSocket(s, Raw)
    ss.sr1(Raw("GET /get HTTP/1.1\r\n" + \
                     "Host: httpbin.org\r\n" + \
                     "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0\r\n" + \
                     "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n" + \
                     "Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2\r\n" + \
                     "Accept-Encoding: gzip, deflate\r\n" + \
                     "Connection: keep-alive\r\n" + \
                     "Upgrade-Insecure-Requests: 1\r\n" + \
                     "Cache-Control: max-age=0\r\n"))


if __name__ == "__main__":
    tcpStack()

发送函数

send

@conf.commands.register
def send(x, inter=0, loop=0, count=None,
         verbose=None, realtime=None,
         return_packets=False, socket=None, *args, **kargs):
    """Send packets at layer 3
send(packets, [inter=0], [loop=0], [count=None], [verbose=conf.verb], [realtime=None], [return_packets=False],  # noqa: E501
     [socket=None]) -> None"""
    need_closing = socket is None
    socket = socket or conf.L3socket(*args, **kargs)
    results = __gen_send(socket, x, inter=inter, loop=loop,
                         count=count, verbose=verbose,
                         realtime=realtime, return_packets=return_packets)
    if need_closing:
        socket.close()
    return results
send

 从图中可以看出send函数是发送三层的数据包,例如IP()/TCP()/PACKET

syn泛洪攻击时可以使用,只发送不接收,自然也不回复,去消耗资源。

sendp

@conf.commands.register
def sendp(x, inter=0, loop=0, iface=None, iface_hint=None, count=None,
          verbose=None, realtime=None,
          return_packets=False, socket=None, *args, **kargs):
    """Send packets at layer 2
sendp(packets, [inter=0], [loop=0], [iface=None], [iface_hint=None], [count=None], [verbose=conf.verb],  # noqa: E501
      [realtime=None], [return_packets=False], [socket=None]) -> None"""
    if iface is None and iface_hint is not None and socket is None:
        iface = conf.route.route(iface_hint)[0]
    need_closing = socket is None
    socket = socket or conf.L2socket(iface=iface, *args, **kargs)
    results = __gen_send(socket, x, inter=inter, loop=loop,
                         count=count, verbose=verbose,
                         realtime=realtime, return_packets=return_packets)
    if need_closing:
        socket.close()
    return results

发送接收函数

sr1

@conf.commands.register
def sr1(x, promisc=None, filter=None, iface=None, nofilter=0, *args, **kargs):
    """Send packets at layer 3 and return only the first answer"""
    iface = _interface_selection(iface, x)
    s = conf.L3socket(promisc=promisc, filter=filter,
                      nofilter=nofilter, iface=iface)
    ans, _ = sndrcv(s, x, *args, **kargs)
    s.close()
    if len(ans) > 0:
        return ans[0][1]
    else:
        return None
sr1

发送,并只保存接收的第一个数据包。

from scapy.layers.inet import IP, TCP
from scapy.sendrecv import sr1

SRC_IP = "192.168.31.164"
DST_IP = "121.17.123.130"


def visitBaidu():
    pkt = IP(src=SRC_IP, dst=DST_IP) / TCP()
    print(pkt.show())
    res = sr1(pkt)
    print(res.summary())


if __name__ == "__main__":
    visitBaidu()
sr1抓包结果

应用

地址段IP发现-Ping

import ipaddress
import multiprocessing
import random
from scapy.layers.inet import IP, ICMP
from scapy.sendrecv import sr1

DIP = "121.17.123.1/24"
BNUM = 20
TNUM = 64


def getBytes(num):
    res = ''.join(random.sample('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567', num))
    return bytes(res, encoding='utf-8')


def ping(ip):
    pkt = IP(dst=ip) / ICMP() / getBytes(BNUM)
    res = sr1(pkt, timeout=5, verbose=False)
    if res:
        return True, ip
    else:
        return False, ip


def getIpList(ip):
    temp = ipaddress.ip_network(ip, False).hosts()
    ipList = []
    for i in temp:
        ipList.append(str(i))
    return ipList


def ipScan(ip, num):
    ipList = getIpList(ip)
    pool = multiprocessing.Pool(processes=int(TNUM))
    result = pool.map(ping, ipList)
    pool.close()
    pool.join()
    for res, ip in result:
        if res:
            print(ip)


if __name__ == "__main__":
    ipScan(DIP, TNUM)
ip发现

 采用了进程池,有时间再整理下进程(池),线程(池)

端口扫描

# /usr/bin/env python3
# _*_ coding:utf-8 _*_
# auther: saucerman
# project: https://github.com/saucer-man/penetration-script

"""
基于python-nmap的端口扫描器
pip install python-nmap
"""

import sys
import time
from colorama import init, Fore, Back, Style
import getopt

# 颜色定义
init(autoreset=True)


class Colored(object):
    def red(self, s):
        return Fore.RED + s + Fore.RESET

    def blue(self, s):
        return Fore.BLUE + s + Fore.RESET

    def yellow(self, s):
        return Fore.YELLOW + s + Fore.RESET


color = Colored()

try:
    import nmap
except:
    print("FATAL: Module nmap missing (python-nmap)")
    sys.exit(1)


# 使用说明
def usage():
    print(color.blue('Usage: port scanner'))
    print(color.blue('\t-h/--host:\tpoint the target to scan'))
    print(color.blue('\t-p/--port:\tpoint the port to scan(not nessesary)'))
    print(color.blue('Examples:'))
    print(color.blue('\tpython port_scanner.py -h 10.10.10.1'))
    print(color.blue('\tpython port_scanner.py -h 10.10.10.1 -p 80,443,8080'))
    print(color.blue('\tpython port_scanner.py -h 10.10.10.1 -p 1-1024'))
    print(color.blue('\nSEE THE MAN PAGE (https://github.com/saucer-man/saucer-frame) FOR MORE OPTIONS AND EXAMPLES'))
    sys.exit(0)


# 扫描
def scanner(host, ports):
    nm = nmap.PortScanner()
    try:
        print('Scanner report for %s\n' % host)
        if len(ports) == 0:
            result = nm.scan(host)
        else:
            result = nm.scan(host, ports)
        if result['nmap']['scanstats']['uphosts'] == '0':
            print(color.red('Host seems down'))
        else:
            print('Host is up')
            print("{:<7}\t{:<7}\t{:<7}\t{:<7}".format('PORT', 'STATE', 'SERVICE', 'VERSION'))
            for k, v in result['scan'][host]['tcp'].items():
                if v['state'] == 'open':
                    print(color.yellow("{:<7}\t{:<7}\t{:<7}\t{:<7}".format(str(k), v['state'], v['name'],
                                                                           v['product'] + v['version'])))
                else:
                    print(color.yellow("{:<7}\t{:<7}".format(str(k), v['state'])))
    except Exception as e:
        print(color.red("unhandled Option"))
        usage()


def main():
    start = time.time()

    # 解析命令行
    if not len(sys.argv[1:]):
        usage()
    try:
        opts, args = getopt.getopt(sys.argv[1:], "h:p:",
                                   ["host=", "port="])
    except:
        print(color.red("unhandled Option"))
        usage()

    ports = ''
    for o, a in opts:
        if o == "-h" or o == "--host":
            host = a
        elif o == "-p" or o == "--port":
            ports = a

    print("Starting port scanner...")
    scanner(host, ports)

    end = time.time()
    print('\n\nScanner down with %0.6f seconds.' % (end - start))


if "__main__" == __name__:
    main()
端口发现

这个脚本不是我写的,使用了nmap包,我还没看过命令解析的内容。

403

以为谁写的网站,结果给我403了

更多脚本查看:网络安全-python脚本资源整理

嗅探(抓包与解析)

sniff

@conf.commands.register
def sniff(*args, **kwargs):
    sniffer = AsyncSniffer()
    sniffer._run(*args, **kwargs)
    return sniffer.results

 实例化了一个AsyncSniffer类,并运行

sniff参数
参数 含义
count 要捕获的数据包数。 0表示无穷大。
store 存储嗅探的数据包还是丢弃它们
prn 应用于每个数据包的功能。如果有返回则展示。
例如:prn = lambda x:x.summary()
session 一个会话,用于处理数据包流的流解码器。
例如:IPSession(对流进行碎片整理)或NetflowSession
filter 要应用的BPF过滤器。
lfilter 适用于每个数据包的Python函数,以确定是否
可以采取进一步的措施。
例如:lfilter = lambda x:x.haslayer(填充)
offline PCAP文件(或PCAP文件列表),用于从中读取数据包。
timeout 在给定时间后停止嗅探(默认值:None)
L2socket 使用提供的L2socket(默认值:use conf.L2listen)
open_socket 提供一个准备使用的对象(或对象列表).recv()开启
stop_filter

将Python函数应用于每个数据包以确定是否
我们必须在此数据包之后停止捕获。

例如:stop_filter = lambda x:x.haslayer(TCP)

iface 接口或接口列表(默认值:None for sniffing on all interfaces)。
monitor 使用监视模式。可能并非在所有操作系统上都可用
starts_callback 嗅探器开始嗅探后立即调用(默认值:None)
from scapy.all import *


def tcpSniff():
    packets = sniff(filter="ip.src == 192.168.31.164 and ip.dst==192.168.31.174 and tcp and tcp.dstport==6633", count=20)
    for pkt in packets:
        pkt.show()
        # print(pkt)


def main():
    print('1.tcp sniff')
    choice = int(input('please input number:'))
    if choice == 1:
        tcpSniff()


if __name__ == '__main__':
    main()

 开启了python-网络编程之socket中写的Tcp服务器和客户端,然后运行了上面的代码

抓包结果

但是

部分抓包

这个UDP是什么鬼????在这个filter和wireshark的还不一样,效果不是很好

wireshark

wireshark同样的过滤器,显示的效果就很好。

Fuzz

def Tcpfuzz(dip, dport, payload):
    try:
        pkt = fuzz(IP(dst=dip) / TCP(dport=dport) / payload)
        pkt1 = IP(dst=dip) / fuzz(TCP(dport=dport) / payload)
        # fuzz 参数必须是scapy中的Packet对象
        # pkt2 = IP(dst=dip) / TCP(dport=dport) / fuzz(payload)
        send(pkt)
        send(pkt1)
        # send(pkt2)
    except Exception as e:
        print(e)


if __name__ == "__main__":
    for i in range(10):
        Tcpfuzz('192.168.31.164', 6633, bytes("fuzz".encode(encoding='utf-8')))
抓包

我开了自己写的TCP服务器,python-网络编程之socket中有提到,不然的话抓包都是红色是Tcp错误。

只对数据进行fuzz时会出现'bytes' object has no attribute 'copy',根据官方用户手册

fuzz举例
fuzz参数

 fuzz只能对Packet的对象进行默认值的替换,copy函数是Packet的。到应用层,把数据包作为http协议的参数进行fuzz时可能可以,还未尝试。

缺点

无法进行持续Tcp连接,在发送连接函数中有socket.close(),Tcp层传输的数据无法fuzz

可能更新syn扫描,http等内容

未完待续...

更多内容查看:网络安全-自学笔记

数据结构专栏:数据结构(严蔚敏版)与算法的实现(含全部代码)

STL专栏:C++ STL容器用法示例大全

OpenGL专栏:现代OpenGL入门教程

有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。

猜你喜欢

转载自blog.csdn.net/lady_killer9/article/details/106874235