DSLBQ'S_BLOG

分类: 网络

  • CDN ByPass

    CDN ByPass

    简介

    什么是CDN加速

    CDN的全称是 Content Delivery Network,即内容分发网络,这个概念是1998年提出的。当时美国麻省理工大学(MT)的一批研究生通过分析当时 Internet E的网络状况,提出了一套能够实现用户就近访问的解决方案,最终设计并实现了其独有的系统。

    CDN有什么作用

    CDN基本思路就是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。CDN核心的就是使用户可就近访问网络,取得所需内容,解决网络拥挤的状况,明显提高用户访问网站的响应速度或者用户下载速度。

    对用户来说,如果一个网站开启了CDN,用户访问速度或者下载速度相比之前会更快。一般来说,网站开启CDN之后,可以提升用户体验。

    CDN对网站有什么好处

    首先,开启CDN后的网站,会根据用户所在地的不同访问CDN的节点服务器,并不直接访问源服务器,这样可以减少网站服务器宽带资源,降低服务器压力。这也就是大家都在ping百度,但是不同地区得到的反馈ip不一样的原因。

    其次,由于CDN节点的阻挡防护,可以更好的保护员服务器的安全。具体来说,CDN其实是充当了一个替身的角色,无论服务器是渗透还是DD0S攻击,攻击的目标都将是CDN节点,这样一来便间接的保护了网站本身。

    验证是否使用CDN

    多地Ping服务

    使用各种多地 ping 的服务,查看对应 IP 地址是否唯一,如果不唯一,多半是使用了CDN, 多地 Ping 网站有:

    使用nslookup

    使用 nslookup 进行检测,原理同上,如果返回域名解析对应多个 IP 地址多半是使用了 CDN。

    绕过CDN找到真实IP

    一、主动连接我们

    让目标主动暴漏他们的真实IP:

    1. 发邮件
    2. RSS邮件订阅
    3. 利用网站漏洞:比如有代码执行漏洞、SSRF、存储型的XSS都可以让服务器主动访问我们预设的web服务器,那么就能在日志里面看见目标网站服务器的真实IP。

    二、查询DNS历史记录

    1. DNS缓存查询:这里主要是利用管理员疏忽,通过DNS缓存查询,查看 IP 与 域名绑定的历史记录,可能会存在使用 CDN 前的记录,相关查询网站有:
    2. 利用SecurityTrails攻击者就可以精准的找到真实原始IP,只需在搜索字段中输入网站域名,然后按Enter键即可,这时“历史数据”就可以在左侧的菜单中找到。SecurityTrails平台除了过去的DNS记录,即使是当前的记录也可能泄漏原始服务器IP。例如,MX记录是一种常见的查找IP的方式。如果网站在与web相同的服务器和IP上托管自己的邮件服务器,那么原始服务器IP将在MX记录中。

    三、查询子域名

    毕竟 CDN 还是不便宜的,所以很多站长可能只会对主站或者流量大的子站点做了 CDN,而很多小站子站点又跟主站在同一台服务器或者同一个C段内,此时就可以通过查询子域名对应的 IP 来辅助查找网站的真实IP。

    下面介绍些常用的子域名查找的方法和工具:

    1. https://dnsdb.io/zh-cn
    2. Google 搜索;例如:用语法”site:baidu.com -www”就能查看除www外的子域名。
    3. 子域名扫描器

    四、网络空间搜索引擎

    最常见的网络空间搜索引擎有钟馗之眼、shodan、fofa搜索。

    1. 钟馗之眼
    2. Shodan
    3. FOFA

    这里主要是利用网站返回的内容寻找真实原始IP,如果原始服务器IP也返回了网站的内容,那么可以在网上搜索大量的相关数据。只需要浏览网站源代码,寻找独特的代码片段。

    在JavaScript中使用具有访问或标识符参数的第三方服务(例如Google Analytics、reCAPTCHA、统计)是攻击者经常使用的方法。或者说用title,毕竟竟每个网站的title基本上都是独一无二的。 以fofa为例:可以直接以 title=””来搜索。

    再配合最常见的网络空间搜索引擎就可以轻而易举的找到网站的真实的IP。

    五、利用SSL证书寻找真实原始IP

    以CloudFlare这款CDN加速器举例:假如你在 abc.com 上托管了一个服务,原始服务器IP是136.23.63.44。 而CloudFlare则会为你提供DDoS保护,Web应用程序防火墙和其他一些安全服务,以保护你的服务免受攻击。

    为此,你的Web服务器就必须支持SSL并具有证书,此时CloudFlare与你的服务器之间的通信,就像你和CloudFlare之间的通信一样,会被加密(即没有灵活的SSL存在)。这看起来很安全,但问题是,当你在端口443(https://136.23.63.44:443)上直接连接到IP时,SSL证书就会被暴露。

    此时,如果攻击者扫描0.0.0.0/0,即整个互联网,他们就可以在端口443上获取在 aaa.com上的有效证书,进而获取提供给你的Web服务器IP。

    目前Censys工具就能实现对整个互联网的扫描,Censys是一款用以搜索联网设备信息的新型搜索引擎,安全专家可以使用它来评估他们实现方案的安全性,而黑客则可以使用它作为前期侦查攻击目标、收集目标信息的强大利器。

    Censys搜索引擎能够扫描整个互联网,Censys每天都会扫描IPv4地址空间,以搜索所有联网设备并收集相关的信息,并返回一份有关资源(如设备、网站和证书)配置和部署信息的总体报告。

    而攻击者唯一需要做的就是把上面用文字描述的搜索词翻译成实际的搜索查询参数。

    Censys证书查询搜索步骤如下:

    1. aaa.com 证书的搜索查询参数为:parsed.names:aaa.com,只显示有效证书的查询参数为:tags.raw:trusted,攻击者可以在Censys上实现多个参数的组合,这可以通过使用简单的布尔逻辑来完成。
    2. 组合后的搜索参数为:parsed.names: aaa.com and tags.raw: trusted
    3. Censys将向你显示符合上述搜索条件的所有标准证书。要逐个查看这些搜索结果,攻击者可以通过单击右侧的“Explore”,打开包含多个工具的下拉菜单。What’s using this certificate? > IPv4 Hosts

    隐藏服务具有SSL证书,要查找它使用的IPv4,只需将”SHA1 fingerprint”(签名证书的sha1值,也就是SHA1指纹)粘贴到Censys平台IPv4主机搜索中,即可找到证书,使用此方法可以轻松找到配置错误的Web服务器真实IP。

    使用给定的SSL证书查找原始IP可以做很多事情,例如:如果你是执法部门的人员,想要找出一个隐藏在cheesecp5vaogohv.onion下的儿童色情网站。最好的办法,就是找到其原始IP,这样你就可以追踪到其托管的服务器,甚至查到背后的运营商以及金融线索。

    六、全网扫描

    扫描全网开放特定端口的IP,然后获取他们的特定页面的HTM源代码,用这些源代码和目标网站的特定页面的HTM源代码做对比,如果匹配上来了,就很可能是目标网站的真实P,工具匹配会匹配出来很多,最后还是要人工筛选。

    1. 钟馗之眼、Shodan、FOFA空间搜索引擎,这里推荐用FOFA
      第一步:打开fofa;第二步:title=”” 得到IP;第三步:再用  ip==”” 做对比。
    2. 用Zmap扫全网
    wget http://www.ipdeny.com/ipblocks/data/countries/hk.zone #香港IP 
    zmap -w hk.zone -p 80 -B 100M -o hk.res
    ./zgrab -input-file=hk.res -senders=2000 -data-"./http-reg" | grep -E 'memberlogin' >> x.txt
    wget -c http://ftp.apnic.net/stats/apnic/delegated-apnic-latest #全网IP

    七、其它思路

    1. 利用网站敏感信息:比如 phpinfo. php,这个就要看字典了。
    2. 国内很多CDN厂商因为各种原因只做了国内的线路,而针对国外的线路可能几乎没有,此时我们使用国外的主机直接访问可能就能获取到真实IP。
  • 密码保护:Zmap学习笔记

    密码保护:Zmap学习笔记

    此内容受密码保护。如需查阅,请在下列字段中输入您的密码。

  • Shodan手册

    Shodan手册

    前言

    本文主要对Complete Guide to Shodan的内容进行增、删、改,虽篇幅较长,但内容涉及了Shodan的搜索语法、客户端命令行、API编程、工具插件、工控等,较为详细,适合当作Shodan手册。代码和搜索示例均已亲自测试并附截图。

    介绍

    Shodan是一个搜索互联网连接设备的搜索引擎,不同于谷歌、必应、百度这些搜索引擎。用户可以在Shodan上使用Shodan搜索语法查找连接到互联网的摄像头、路由器、服务器等设备信息。在渗透测试中,是个很不错的神器。

    Shodan的搜索流程:

    关于数据

    Shodan采集的基本数据单位是banner。banner是描述设备所运行服务的标志性文本信息。对于Web服务器来说,其将返回标题或者是telnet登陆界面。Banner的内容因服务类型的不同而相异。

    以下这是一个典型的HTTP Banner:

    HTTP/1.1 200 OK
    Server: nginx/1.1.19
    Date: Sat, 03 Oct 2015 06:09:24 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 6466
    Connection: keep-alive
    

    上面的banner显示该设备正在运行一个1.1.19版本的nginx Web服务器软件

    下面是西门子S7工控系统协议的一个banner,这次返回的banner完全不同,提供了大量的详细数据(有关的固件信息、序列号):

    Copyright: Original Siemens Equipment
    PLC name: S7_Turbine
    Module type: CPU 313C
    Unknown (129): Boot Loader           A
    Module: 6ES7 313-5BG04-0AB0  v.0.3
    Basic Firmware: v.3.3.8
    Module name: CPU 313C
    Serial number of module: S Q-D9U083642013
    Plant identification: 
    Basic Hardware: 6ES7 313-5BG04-0AB0  v.0.3
    

    注:Shodan搜索的是联网设备运行服务的banner,不是单一的主机信息。如果单个IP暴露很多服务信息,在指定特定搜索内容的时候,搜索结果只会出现指定的内容,不会显示其他的服务信息。

    设备元数据

    除了获取banner,Shodan还可以获取相关设备的元数据,例如地理位置、主机名、操作系统等信息。大部分元数据可以通过Shodan的官网获取,小部分的可以通过使用API编程获取。

    IPv6

    据统计,截至2015年10月,Shodan每月收集数百万条关于IPv6设备的可用数据。不过与收集的数亿个IPv4 banner相比,这些数字还是苍白。预计在未来几年会有所增长。

    数据采集

    频率

    Shodan的爬虫全天候工作,并实时更新数据库。在任何时候使用Shodan查询,都可以获得最新的结果。

    分布式

    爬虫分布于世界各地,包括:

    • 美国(东海岸和西海岸)
    • 中国
    • 冰岛
    • 法国
    • 台湾
    • 越南
    • 罗马尼亚
    • 捷克共和国

    从世界各地收集数据是为了防止地区各种因素的差异造成数据的偏差。例如,美国的许多系统管理员会封锁整个中国的IP范围,分布在世界各地的Shodan爬虫就可以确保任何全国性的封锁不会影响数据收集。

    随机

    Shodan爬虫的基本算法是:

    1. 生成一个随机的IPv4地址
    2. 从Shodan能解析的端口列表中生成一个随机端口测试
    3. 检测随机端口上的随机IPv4地址,并获取Banner
    4. 继续步骤1

    这意味着爬行器不扫描增量的网络范围。爬行是完全随机的,以确保在任何给定的时间内对因特网进行统一的覆盖,并防止数据的偏差。

    深入SSL

    SSL正在成为互联网上重要的服务,Shodan也随之扩展性地收集其banner,包括收集每个SSL的功能服务及其漏洞信息,比如HTTPS,不仅仅是SSL证书。

    漏洞测试

    心脏出血漏洞

    如果某服务有心脏出血漏洞Heartbleed bug),返回的banner将包含以下2个附加属性。opts.heartbleed包含了对服务进行心脏出血漏洞测试的原始回应(在测试中,爬虫只抓取少量溢出来确认服务是否受到心脏出血的影响,不会获取泄露的私钥)。若设备容易受到攻击,爬虫会将CVE-2014-0160添加到opts.vulns列表中;若不易受到攻击,则会返回!CVE-2014-0160

    {
        "opts": {
            "heartbleed": "... 174.142.92.126:8443 - VULNERABLE\n",
            "vulns": ["CVE-2014-0160"]
        }
    }
    

    Shodan也支持漏洞信息搜索。比如,要搜索美国受心脏滴血漏洞影响可在shodan输入country:US vuln:CVE-2014-0160

    FREAK

    如果服务支持导出密码,则爬虫程序就将“CVE-2015-0204”项添加到opts.vulns属性

    "opts": {
        "vulns": ["CVE-2015-0204"]
    }
    
    Logjam

    爬虫将短暂使用Diffie-Hellman密码连接到SSL服务,若连接成功就存储返回以下信息:

    "dhparams": {
        "prime": "bbbc2dcad84674907c43fcf580e9...",
        "public_key": "49858e1f32aefe4af39b28f51c...",
        "bits": 1024,
        "generator": 2,
        "fingerprint": "nginx/Hardcoded 1024-bit prime"
    }
    
    版本

    通常情况下,当浏览器连接到SSL服务时,它将协商应该与服务器一起使用的SSL版本和密码。然后,他们会就某个SSL版本(如TLSv1.2)达成一致,然后将其用于通信。

    Shodan爬虫开始按照上面所述的正常请求,与服务器进行协商连接SSL。但是,之后,他们还显式地尝试使用其他的SSL版本连接到服务器。换句话说,爬行器尝试使用SSLv2、SSLV3、TLSv1.0、TLSv1.1和TLSv1.2连接到服务器,来确定该SSL服务支持的所有版本。

    收集到的信息将在ssl.versions版本字段中显示:

    {
        "ssl": {
            "versions": ["TLSv1", "SSLv3", "-SSLv2", "-TLSv1.1", "-TLSv1.2"]
        }
    }
    

    如果在版本前面有一个-符号,那么该设备不支持SSL版本。如果版本不以-开头,则服务支持给定的SSL版本。例如,上面的服务器支持: TLSv1SSLv3

    不支持版本:SSLv2TLSv1.1TLSv1.2

    TLS 1.0通常被标示为SSL 3.1,TLS 1.1为SSL 3.2,TLS 1.2为SSL 3.3。见传输层安全性协议

    版本信息可以通过shodan的网站或者API搜索。例如,输入ssl.version:sslv2搜索查询将返回允许使用SSLv2的所有SSL服务(包括HTTP、SMTP、HTTP、POP3、IMAP等)

    遵循链

    证书链是从root到最终用户的SSL证书列表;SSL的banner服务包括一个ssl.chain属性,该属性包含PEM序列化证书中链的所有SSL证书。

    基础之上

    对于大多数服务,爬虫试图分析主要的banner文本,并解析出有用的信息。不过有些情况是,抓取MongoDB的集合名称,从远程桌面服务获取屏幕截图,存储比特币的对等点列表。有两种Shodan使用的高级数据分析技术,我想强调一下:

    Web组件

    爬虫也会尝试确定创建网站的Web技术。对于http和https模块,将分析header和HTML来分解网站的组件。结果信息存储在http.components属性中。该属性是一个技术字典,关键是技术的名称(例如jQuery),值是另一个具有类别属性的字典。categories属性是与技术相关的类别列表。例如

    "http": {
        ...
            "components": {
                "jQuery": {
                    "categories": ["javascript-frameworks"]
                },
                "Drupal": {
                    "categories": ["cms"]
                },
                "PHP": {
                    "categories": ["programming-languages"]
                }
            },
                 ...
        },
    

    http.components表明该网站在运行Drupal内容管理系统,该系统本身使用的jQueryPHPShodan REST API使信息通过过滤器http.component和2个方面(http.componen和http.component_category)进行搜索。要获得所有可能的组件/类别值的完整列表,请使用新的方面。例如,要获得所有可能类别的完整列表,请使用以下shodan命令:

    shodan stats --facets http.component_category:1000 http
    

    级联

    如果一个banner返回了关于对等点的信息,或者有关于另一个运行服务的IP地址的信息,那么爬虫就会试图在这个IP/服务上执行一个banner抓取。例如:主线DHT(过去用于Bittorrent)的默认端口是6881。这样一个DHT节点的banner看起来如下:

    DHT Nodes
    97.94.250.250	58431
    150.77.37.22	34149
    113.181.97.227	63579
    252.246.184.180	36408
    83.145.107.53	52158
    77.232.167.126	52716
    25.89.240.146	27179
    147.23.120.228	50074
    85.58.200.213	27422
    180.214.174.82	36937
    241.241.187.233	60339
    166.219.60.135	3297
    149.56.67.21	13735
    107.55.196.179	8748
    

    以前,抓取工具会抓取上面的banner,然后继续抓取。现通过为DHT banner的抓取启用级联功能,抓取工具现在可以为所有的对等启动新的banner抓取请求。在上面的示例中,搜寻器将使用DHT banner捕获器,在IP为97.94.250.250的58431端口上启动扫描150.77.37.22,继续在端口34149上启动扫描,依此类推。也就是说,如果初始扫描数据包含有关其他潜在主机的信息,对IP的单次扫描可能会导致级联扫描。

    为了跟踪初始扫描请求与任何子级/级联请求之间的关系,我们引入了2个新属性:

    • _shodan.id:banner的唯一ID。如果可以从服务启动级联请求,这个属性就一定存在,但这并不一定意味着级联请求会成功。
    • _shodan.options.referrer:提供触发创建当前banner的banner的唯一ID。即引用者是当前banner的父代。

    Web界面

    访问Shodan收集的数据最简单的方法是通过Web界面。所有的人都可以输入一个需要查询的设备。

    搜索查询说明

    默认情况下,搜索查询仅查看主横幅文本,不搜索元数据。例如,如果您要搜索“Google”,那么搜索结果将只包含标题中显示“Google”文本的结果;它不一定会返回Google网络范围的结果。

    如上所述,搜索“谷歌”返回许多组织购买并连接到Internet的谷歌搜索设备;它不返回谷歌的服务器。

    Shodan将尝试找到匹配所有搜索项的结果,这意味着隐含地在每个搜索项之间存在+AND连接符号。例如,搜索查询“apache + 1.3”相当于“apache 1.3”

    要搜索特定的元数据需要使用搜索过滤器。

    过滤器

    过滤器是Shodan用来根据服务或设备的元数据缩小搜索结果的特殊关键字。输入过滤器的格式是:

    注意:和值之间没有空格

    要使用包含过滤器空间的值,必须将值包含在双引号中。例如搜索圣地亚哥的所有联网设备:

    筛选多个值可以使用,分开。比如要查找23号端口和1023号端口上运行telnet的设备:

    如果过滤语法不允许使用逗号(如port,hostname,net),那么可以使用多个值联合查询:

    port:80,8080  city:"beijing" hostname:"baidu.com"
    

    当然也可以使用-排除结果。比如:

    port:23,1023  -city:"San Diego"
    

    有时候也需要过滤一些主文本标题为空的搜索结果,这时候就需要使用-hash:0。比如:

    Shodan上的每个banner都有一个哈希值,对于空的banner,hash值就为0。若尝试搜索简短的、静态的banner,使用哈希过滤语法就比较便捷。

    shodan支持大量的过滤器,比较常用的是:

    过滤器名描述举例
    category现有的分类:ics, malwarecategory:"malware"
    city城市的名字city:"San Diego"
    country国家简写country:"ES" country:"CN"
    netCIDR格式的IP地址net:190.30.40.0/24
    hostname主机名或域名hostname:"google"
    port端口号port:21
    org组织或公司org:"google"
    ispISP供应商isp:"China Telecom"
    product软件、平台product:"Apache httpd" product:"openssh"
    os操作系统os:"Windows 7 or 8"
    version软件版本version:"2.6.1"
    geo经纬度geo:"46.9481,7.4474"

    搜索引擎

    默认情况下,搜索查询将查看过去30天内收集的数据。

    下载数据

    完成搜索后,顶部将出现一个名为“下载数据”的按钮。点击该按钮将为您提供以JSON,CSV(XML已经弃用)格式下载搜索结果的选项。

    JSON格式的文件,其中每行包括全部的banner和所有附带的元数据收集信息。这是保存所有可用信息的首选格式。格式与Shodan命令行客户端兼容,这意味着可以从Shodan网站下载数据,然后使用终端进一步处理。

    CSV格式的文件,返回包含IP、端口,banner,组织和主机名内容。它不包含由于CSV文件格式的限制收集的所有Shodan信息。如果只关心结果的基本信息,并希望快速将其加载到外部工具(如Excel)中,可以使用此方法。

    下载数据会消耗积分,积分需要在网站上购买。积分与Shodan API没有任何关联,并且不会每月自动更新。1积分可用于下载10000个结果。

    生成报告

    Shodan可让根据搜索查询生成报告。该报告包含图表,可以全面了解互联网上的分发结果。这个功能是免费的,任何人都可以使用。

    分享结果

    搜索完成之后,可以自定义,分享内容给其他Shodan用户。

    共享搜索查询是公开查看的

    例子

    搜索美国的服务器在8080端口上运行8.0版本IIS服务的服务器:

    port:8080 product:"Microsoft-IIS" country:"US" version:"8.0"
    

    搜索可能受到DOUBLEPULSAR攻击的机器:

    port:445 "SMB Version: 1" os:Windows !product:Samba
    

    搜索所有nist.gov域名里的apache服务:

    apache hostname:.nist.gov
    

    图标搜索

    通过已知icon hash搜索目标

    0x01 获取谷歌地址

    ping一下google,获得一个谷歌ip,为172.217.27.174

    0x02 查看原数据

    使用shodan搜索刚才获取的IP,并找到查看原始数据那一行

    0x03 查找favicon hash

    打开原始数据,找到data.1.http.favicon.hash,其值为708578229:

    0x04 图标hash搜索

    在Shodan网页搜索的过滤器处输入http.favicon.hash:708578229就可以搜索shodan所收录的谷歌的网站。

    0x05 favicon data

    data.1.http.favicon.data的值是base64,可以自行验证

    通过未知icon hash搜索目标

    0x01 背景

    在分析一个站点的登陆界面,没有其他信息,只有一个icon的时候,这时候就可以通过shodan搜索相同模板的站来入手,找突破口。

    如果目标已经被shodan收录,直接搜索对应的IP就能通过上述方法进行图标hash搜索。如果是目标未被收录,就可以通过现在这个方法来进行侧面突破。

    0x02 原理

    shodan对icon的处理其实是通过MurmurHash进行存储的。MurmurHash是一种非加密型哈希函数,适用于一般的哈希检索操作。由Austin Appleby在2008年发明,并出现了多个变种,[6]都已经发布到了公有领域(public domain)。与其它流行的哈希函数相比,对于规律性较强的key,MurmurHash的随机分布特征表现更良好。其地址在github

    0x03 icon hash的生成验证

    直接在本地使用pip安装mmh3。

    验证代码如下:

    import mmh3
    import requests
    response = requests.get('https://www.baidu.com/favicon.ico')
    favicon = response.content.encode('base64')
    hash = mmh3.hash(favicon)
    print hash
    

    运行验证代码获得icon hash

    在shodan中进行http.favicon.hash:-1507567067搜索,验证成功

    0x04 扩展

    例如http://common.cnblogs.com/favicon.ico得到博客园的icon,直接将图标地址放入脚本中计算其hash值,得到-395680774,再在shodan中搜索http.favicon.hash:-395680774

    Shodan地图

    https://maps.shodan.io/

    直观的地图界面,显示搜索的结果

    使用可改变显示风格,有卫星、街景选项。

    Shodan Exploits

    https://exploits.shodan.io

    Shodan Exploits收集来自CVE,Exploit DB和Metasploit的漏洞和攻击,使其可通过Web界面进行搜索。

    Shodan Exploit搜索的结果不同于Shodan,Exploit搜索的内容包括exploit的信息和元数据。

    名称描述举例
    author漏洞或exploit的作者author:"Tom Ferris"
    description描述description:"remote"
    platform平台platform:"php" platform:"windows" platform:"Linux"
    type漏洞类型type:"remote" type:"dos"

    Shodan Images

    https://images.shodan.io

    顶部的搜索框使用与Shodan主搜索引擎相同的语法。使用搜索框按组织或网点筛选最有用。但是,它也可以用于过滤显示的图像类型。

    图像数据主要来自:

    • VNC
    • Remote Desktop (RDP)
    • RTSP
    • Webcams
    • X Windows

    每个图像源来自不同的端口/服务,因此具有不同的banner。如果只想看到来自摄像头的图像,你可以搜索:

    查找VNC可以输入RFB,查找RTSP可以使用RTSP

    如果在Shodan中搜索截图,可以使用has_screenshot:true

    has_screenshot:true country:"KR"
    

    共享的Shodan搜索语法

    链接见https://www.shodan.io/explore

    关于Shodan的外部工具

    Shodan命令行界面

    安装最新的Shodan可以通过

    安装该工具之后,使用API对其进行初始化操作:

    alert命令

    alert命令提供创建、列表、清除和删除网络提醒的能力。

    convert命令

    convert命令是导出Shodan的搜索结果文件,比如JSON文件。

    count命令

    统计查询结果

    shodan count microsoft iis 6.0
    

    download命令

    搜索Shodan并将结果导出到JSON文件中(请参阅附录A)。

    默认情况下,只下载1000个结果。如果想导出更多的结果,加上--limit标志。

    download命令可以保存搜索结果到本地,随时使用parse命令处理结果,当再次导出相同搜索内容的时候,就不必再花费积分导出。

    shodan download  microsoft iis 6.0
    

    host命令

    查看有关主机的信息,例如它位于何处,哪些端口是开放的以及哪个组织拥有其IP。

    shodan host 189.201.128.250
    

    honeyscore命令

    检查IP地址是否是蜜罐。

    shodan honeyscore 41.231.95.212
    

    info命令

    查询自己的API账户信息,包括本月剩余的查询次数和扫描积分数量。

    myip命令

    返回本机的出口IP(类似于curl ip.cn

    parse命令

    使用parse来分析使用导出的搜索结果。它可以让过滤出感兴趣的字段,也可以将JSON转换为CSV。这样,对于导入到其他脚本比较友好。

    以下命令输出之前下载的Microsoft-IIS数据,并且将JSON文件转换为的CSV格式的文件。其中包括IP地址,端口和归属组织:

    shodan parse --fields ip_str,port,org --separator , microsoft-data.json.gz
    

    scan命令

    scan命令提供了一些子命令。最重要的一个是submit命令,这个命令可以使用shodan执行网络扫描。

    shodan scan submit 198.20.99.0/24
    

    默认情况下,它将显示IP,端口,主机名和数据。您可以使用--fields来打印感兴趣的任何banner字段。

    search命令

    search命令搜索时候,终端将以友好的方式显示结果。默认情况下,它将显示IP,端口,主机名和数据。不过可以使用--fields参数来打印感兴趣的任何banner字段。

    shodan search --fields ip_str,port,org,hostnames microsoft iis 6.0
    

    stats命令

    提供关于搜索的摘要信息,当然可以用于统计信息。命令显示了Apache Web服务器所在的最常用的国家:

    shodan stats --facets country apache
    

    stream命令

    stream命令提供对Shodan爬虫收集的实时数据流的访问。

    该命令支持许多不同的选项,但有2个是重要的提及:

    • --datadir:可以指定流数据存储的目录,生成的文件格式YYYY-MM-DD.json.gz。每天只要保持数据流运行,就会生成一个新的文件。
      • 例如:从实时数据流保存数据到指定路径,可以使用shodan stream --datadir /var/lib/shodan/
    • --limit:指定应下载多少结果。默认情况下,该stream命令将一直运行,直到退出该工具。但是,如果只想收集数据样本,那么--limit参数可确保收集少量记录。
      • 例如:shodan stream --limit 100可以连接到Shodan实时流,打印出前100条记录,然后退出
    • --ports:接受逗号分隔端口,收集指定端口记录的清单
      • 例如:shodan stream --ports 80,8080

    例子

    官方例子

    官方例子见 28 public asciicasts by Shodan:https://asciinema.org/~Shodan

    网络分析例子

    Shodan最常见的使用案例是使用它来更好地了解公共网络范围内的运行情况。Shodan命令行工具可以快速帮助、处理你的目标。例如,查看78.13.0.0/16段在网上暴露了多少服务。

    shodan count net:78.13/16
    

    count命令提供了关于78.13.0.0/16段暴露了4960个服务

    统计出该网段暴露的最多端口数的top10:

    shodan stats --facets port net:78.13/16
    

    有时候也需要详尽的端口暴露数分配报告,因此指定最大的端口,返回此端口范围的暴露数统计情况:

    shodan stats --facets port:100000 net:78.13/16
    

    该网络上有955个端口被发现暴露,并统计出各自端口暴露数。最多的是7547端口,这个端口是调制解调器的端口,这个端口也有很多的安全问题可以关注。在统计中也有一些非常见的标准端口,这些端口大多是为了掩盖自己真实的Web服务。

    统计该网段的80、443端口上的服务情况:

    shodan stats --facets product "HTTP net:78.13/16 -port:80,443"
    

    这里应将端口号放在引号中,防止bash认为该port是shodan的命令参数。

    分析SSL的例子

    若要了解整个网络的SSL使用情况,可按照以下来查询

    shodan stats --facets ssl.version HTTP net:78.13/16
    

    可以看出大多运行的是TLS1.0及其以上的版本,不过还有一些古老的设备在使用sslv2。

    在web端的shodan搜索出来:

    分析telnet情况

    mkdir telnet-data
    
    shodan stream --ports 23,1023,2323 --datadir telnet-data / --limit 10000
    

    创建一个名为telnet-data的目录来存储telnet数据,然后从实时数据流中导出10000条记录,存储在telnet-data文件夹中

    Maltego扩展组件/assets

    shodan扩展组件为Maltego提供了2/assets新的实体功能(service和exploit)和五个转换:

    • searchShodan
    • searchShodanByDomain
    • searchShodanByNetblock
    • toShodanHost
    • searchExploits

    浏览器插件

    ChromeFirefox都有插件可以使用

    Metasploit

    MSF主要有两个shodan模块:

    1. Shodan的常用搜索:`auxiliary/gather/shodan_search`
    
    use auxiliary/gather/shodan_search
    
    set SHODAN_APIKEY ********************
    
    set QUERY ****
    
    run 
    
    1. Shodan的蜜罐验证:auxiliary/gather/shodan_honeyscore:
    use auxiliary/gather/shodan_honeyscore 
    
    set SHODAN_APIKEY ********************
    
    set TARGET your_target
    
    run
    

    Recon-ng

    先添加shodan API的key:

    keys add shodan_api VZbVJy***n8S****hS1YM1****enTuy
    

    显示可用的模块:

    使用shodan搜索主机名:

    use recon/domains-hosts/shodan_hostname
    

    设置参数,并运行:

    show options
    set SOURCE google
    set LIMIT 1
    run
    

    Developer API

    Shodan提供了一个开发者的API(https://developer.shdan.io/api)来编程,获取所需要的信息。可以通过网站完成的事情都可以通过代码完成。

    该API分为两部分:REST API和Streaming API。REST API提供搜索Shodan的方法,查找主机,获取关于查询的信息的摘要。Streaming API提供Shodan当前收集的数据的原始实时返回。有几个不同的套餐可以获取,该API获取的数据不能被搜索或用其他方式进行交互,适用于需要获取大量数据的人。

    只有购买开发者API计划的人才能获得Streaming API。

    使用限制

    根据API的套餐不同,API会有不同的限制:

    1. 搜索:每月的搜索次数有不同的限制,且需要使用查询积分。如果直接查询不会消耗查询积分,若进行过滤器或者是超过一页的搜索就需要消耗查询积分。搜索apache不需要消耗查询积分,搜apache country:"US"将会消耗一个查询积分,就算查询第二页也只会消耗一个查询积分。
    2. 扫描:按需获得的API也会根据积分限制每月扫描主机的数量。对于每个主机的扫描都需要一个扫描积分才能扫描。
    3. 网络提醒:根据不同的API的使用次数可以使用提醒功能监视所查询的IP。只有付费客户才能使用此功能,且无法在账户中创建超过100条提醒。

    Facets

    过滤器缩小搜索结果。而Facets提供关注的banner字段的聚合信息,会得到一个大的结果视图。例如,Shodan网站使用Facets来提供搜索的统计信息,类似于在左侧显示的:

    Facets有很多可以选择的参数。比如port:22Facetsssh.fingerprint,输出的时候就能显示出网络上SSH的详细条目。

    目前Facet只能在API和Shodan的命令行上使用

    入门

    所有的例子使用python来演示,当然其他的语言也有Shodan的库/客户端

    为python环境安装Shodan库:

    如果已经安装shodan,可以使用:

    初始化

    首先要做的是初始化:

    import shodan
    api = shodan.Shodan('YOUR API KEY')
    

    在https://account.shodan.io获取API密钥

    搜索

    已经拥有API密钥之后,准备进行搜索:

    #将请求包放在一个try/except块中,捕获抛出的异常
    try:
            # Search Shodan
            results = api.search('apache')
     
            # Show the results
            print 'Results found: %s' % results['total']
            for result in results['matches']:
                    print 'IP: %s' % result['ip_str']
                    print result['data']
                    print ''
    except shodan.APIError, e:
            print 'Error: %s' % e
    

    首先调用api对象的Shodan.search()方法,该方法返回的结果放入字典之中。然后,打印出搜索结果数量,最后将返回的结果进行遍历循环,并打印其IP和banner。每一页的搜索结果多达100个。

    当然查询的时候还有很多返回信息。下面是Shodan.search返回的部分信息:

    {
    	'total': 23199543,
    	'matches': [
    		{
    			'data': 'HTTP/1.1 301 Moved Permanently\r\nDate: Thu, 01 Feb 2018 02:43:53 GMT',
    			'hostnames':['mypage.ponparemall.com'],
    			'ip': 2685469827L,
    			'ip_str': '160.17.4.131',
    			'port': 80,443,
    			'isp': Recruit Holdings Co.,Ltd.,
    			'timestamp': '2018-02-01T02:47:34.036371'
    		},
    		...
    	]
    }
    

    有关banner可能包含的属性的完整列表请参阅附录A

    默认情况下,为了节省带宽使用量,banner中的一些大的字段会被截断(比如HTML的)。若想要检索所有的信息,只需使用minify=False禁用概要。例如,用以下代码可以将匿名VNC服务的查询结果全部返回:

    results = api.search('has_screenshot:true', minify=False)
    

    任何错误都会引发异常,将API请求封装在try/except是一种良好的代码习惯,不过为了简单起见,例子暂时不用try/except

    以上脚本仅输出第一页的搜索结果。要想获得第二页或更多的结果,可以使用page参数执行请求:

    results = api.search('apache',page=2)
    

    如果想遍历所有的结果,使用search_cursor()方法会更加便捷:

    for banner in api.search_cursor('apache'):
        print(banner['ip_str']) # 打印出该IP的每个banner
    

    search_cursor()方法只能循环结果,返回banner,不能使用Facets

    主机查找

    要用Shodan查找特定的IP,可用Shodan.host()函数:

    # 查询主机
    host = api.host('217.140.75.46')
    
    # 打印一般信息
    print """
    	IP: %s
    	Organization: %s
    	Operating System: %s
    """ % (host['ip_str'], host.get('org', 'n/a'), host.get('os', 'n/a'))
    
    # 打印所有的banner
    for item in host['data']:
    	print """
    		Port: %s
    		Banner: %s
    		""" % (item['port'], item['data'])
    

    默认情况下,Shodan只返回最近收集的主机的信息。如果想获取IP地址的完整历史记录,就使用history参数。

    host = api.host('217.140.75.46', history=True)
    

    虽然以上代码可以返回所有banner,但其中也包括一些可能不再在主机上活动的服务。

    扫描

    Shodan每月至少爬取一次,但是如果想用Shodan立即扫描网络,就可以使用API​​扫描。(订购的不同API有不同的扫描次数)

    与Nmap等工具扫描不同,使用Shodan进行的扫描是异步完成的,在进行Shodan扫描之后不会马上就收到扫描结果。这取决于开发人员是如何收集扫描结果的,是直接查找IP信息,是用Shodan直接搜索,还是订购实时信息流查找。Shodan命令行界面在启动扫描后,创建临时网络提醒,然后根据实时数据流出扫描结果。

    scan = api.scan('198.20.69.0/24')
    

    也可以使用CIDR表示法的地址来提供扫描目标:

    scan = api.scan(['198.20.49.30', '198.20.74.0/24'])
    

    在向API提交了扫描请求之后,会返回以下信息:

    {
    	'id': 'R2XRT5HH6X67PFAB',
    	'count': 1,
    	'credits_left': 5119
    }
    
    • id:唯一的扫描标识符
    • count: 提交的IP扫描数
    • credits: 剩余的扫描积分

    实时数据流

    Streaming API是一种基于HTTP的服务,可返回Shodan收集的实时数据流。它不提供任何搜索或查找功能,它只是抓取工具收集的所有内容的概要。

    例如,以下是一个脚本的部分代码,可以从容易受到FREAK(CVE-2015-0204)攻击的设备输出banner:

    def has_vuln(banner, vuln):
        if 'vulns' in banner['opts'] and vuln in banner['opts']['vulns']:
            return True
        return False
    
    for banner in api.stream.banners():
        if has_vuln(banner, 'CVE-2015-0204'):
            print banner
    

    在上面的例子中,has_vuln()方法检查服务是否可能存在CVE-2015-0204

    banner中的许多属性是可选的,这样可以节省空间和带宽。为了使可选属性更容易处理,最好在函数中封装对属性的访问。

    注意:常规的API能访问的数量仅仅是订购的API数量的1%,只有订购了API具有许可证的客户才有100%的访问权限

    网络提醒

    要创建网络提醒,需要提供一个提醒名称和一个IP范围。名称应该具有概述性,当受到提醒的时候,就大概知道是什么监视内容被返回了。

    alert = api.create_alert('Production network', '198.20.69.0/24')
    

    正如scan()方法一样,可以提供监视的网络范围列表:

    alert = api.create_alert('Production and Staging network', [
    	'198.20.69.0/24',
    	'198.20.70.0/24',
    ])
    

    只能使用有限数量的监视IP,并且每个帐户不能有超过100个监视提醒在活动。

    将网络提醒与扫描API结合使用时,一个有用的技巧是设置提醒的时间:

    alert = api.create_alert('Temporary alert', '198.20.69.0/24', expires=60)
    

    上述代码可以使得提醒会激活使用60s,60s之后就会停止,不再进行监视。

    成功创建提醒之后,API将返回以下对象:

    {
    	"name": "Production network", 
    	"created": "2015-10-17T08:13:58.924581", 
    	"expires": 0, 
    	"expiration": null, 
    	"filters": {
    		"ip": ["198.20.69.0/24"]
    	},
    	"id": "EPGWQG5GEELV4799",
    	"size": 256
    }
    

    订阅

    一旦创建了提醒,就可以将其用作实时数据流的监视。

    for banner in api.stream.alert(alert['id']):
    	print banner
    

    与常规实时流一样,该alert()方法提供了一个迭代器,其中每个项目都是由Shodan爬虫收集的banner。idalert()方法需要的唯一参数,在有网络提醒时会返回提醒ID。

    使用Shodan命令行界面

    接下来讲述如何使用Shodan的命令行界面快速清除基于Python代码创建的提醒。

    clear命令将会清除电脑上创建的所有alert。

    清除所有alert:

    $ shodan alert clear
    Removing Scan: 198.20.69.0/24 (ZFPSZCYUKVZLUT4F)
    Alerts deleted
    

    列出alert列表,确认有无alert:

    $ shodan alert list
    You haven't created any alerts yet.
    

    创建一个新的alert:

    $ shodan alert create "Temporary alert" 198.20.69.0/24
    Successfully created network alert!
    Alert ID: ODMD34NFPLJBRSTC
    

    最后一步是订阅监视提醒,并存储返回的数据。要为创建的警报传输结果,将ODMD34NFPLJBRSTC的警报ID提供给stream命令:

    $ mkdir alert-data
    $ shodan stream --alert=ODMD34NFPLJBRSTC --datadir=alert-data
    

    上面的命令中,使用ID为ODMD34NFPLJBRSTC的alert提醒,并且使用数据流传输结果。结果将存储在名为alert-data的目录中。每天都会在alert-data目录中生成具有一个当天收集banner的新文件。也就是说,不用关心轮转文件,stream命令会处理这些。几天后,目录将如下所示:

    $ ls alert-data
    2016-06-05.json.gz
    2016-06-06.json.gz
    2016-06-07.json.gz
    

    例子

    常用 Shodan 库函数

    • shodan.Shodan(key):初始化连接API
    • Shodan.count(query, facets=None):返回查询结果数量
    • Shodan.host(ip, history=False):返回一个IP的详细信息
    • Shodan.ports():返回Shodan可查询的端口号
    • Shodan.protocols():返回Shodan可查询的协议
    • Shodan.services():返回Shodan可查询的服务
    • Shodan.queries(page=1, sort='timestamp', order='desc'):查询其他用户分享的查询规则
    • Shodan.scan(ips, force=False):使用Shodan进行扫描,ips可以为字符或字典类型
    • Shodan.search(query, page=1, limit=None, offset=None, ufacets=None, minify=True):查询Shodan数据

    例子——基本的搜索

    #!/usr/bin/env python
    #
    # shodan_ips.py
    # Search SHODAN and print a list of IPs matching the query
    #
    # Author: achillean
    
    import shodan
    import sys
    
    # Configuration
    API_KEY = "VZbVJyrIrn8SCSxHhS1YM1XPeKt5nTuy"
    
    # Input validation
    if len(sys.argv) == 1:
            print 'Usage: %s <search query>' % sys.argv[0]
            sys.exit(1)
    
    try:
            # Setup the api
            api = shodan.Shodan(API_KEY)
    
            # Perform the search
            query = ' '.join(sys.argv[1:])
            result = api.search(query)
    
            # Loop through the matches and print each IP
            for service in result['matches']:
                    print service['ip_str']
    except Exception as e:
            print 'Error: %s' % e
            sys.exit(1)
    

    例子——使用Facets收集概要信息

    Shodan API的强大功能其中之一是获取各种属性的概要信息。若想了解哪些国家的Apache服务器最多,那么可以使用Facets;若想知道哪个版本的nginx最受欢迎,可以使用Facets;若想查看Microsoft-IIS服务器的正常运行时间,那么可以使用Facets

    以下脚本显示了如何使用shodan.Shodan.count()方法在使用Shodan API进行搜索时候不返回任何详细结果,只返回组织、域、端口、ASN和国家的信息:

    #!/usr/bin/env python
    #
    # query-summary.py
    # Search Shodan and print summary information for the query.
    #
    # Author: achillean
    
    import shodan
    import sys
    
    # Configuration
    API_KEY = 'YOUR API KEY'
    
    # 键入想获取的信息
    FACETS = [
        'org',
        'domain',
        'port',
        'asn',
    
        # 只关注前三城市,('country', 3)让Shodan返回前三城市
        # Facet默认五个搜索区域(比如搜索1000个国家,就键入('country', 1000)
    ]
    
    FACET_TITLES = {
        'org': 'Top 5 Organizations',
        'domain': 'Top 5 Domains',
        'port': 'Top 5 Ports',
        'asn': 'Top 5 Autonomous Systems',
        'country': 'Top 3 Countries',
    }
    
    # Input validation
    if len(sys.argv) == 1:
        print 'Usage: %s <search query>' % sys.argv[0]
        sys.exit(1)
    
    try:
        # 键入Shodan API
        api = shodan.Shodan(API_KEY)
    
        # Generate a query string out of the command-line arguments
        query = ' '.join(sys.argv[1:])
    
        # 使用count()方法,因为它不返回结果,不需要通过付费API才能使用
        # count()运行速度快于search().
        result = api.count(query, facets=FACETS)
    
        print 'Shodan Summary Information'
        print 'Query: %s' % query
        print 'Total Results: %s\n' % result['total']
    
        # 从Facets打印摘要信息。
        for facet in result['facets']:
            print FACET_TITLES[facet]
    
            for term in result['facets'][facet]:
                print '%s: %s' % (term['value'], term['count'])
    
            # 在摘要信息之间打印一条空行
            print ''
    
    except Exception, e:
        print 'Error: %s' % e
        sys.exit(1)
    

    例子——利用API编写GIF图片

    Shodan很好得保存了爬取的IP的完整历史记录,可以通过API编写Python脚本,输出Shodan爬虫收集的屏幕截图的。

    环境:

    需要的Python包:

    • shodan:sudo easy_install shodan安装
    • arrow: sudo easy_install arrow安装。arrow包用于将banner的时间戳字段解析为Python datetime对象。

    需要的软件包:

    sudo apt-get install imagemagick //将多个图像合并成一个GIF动画所需要
    
    easy_install -U requests simplejson
    

    代码参见:Timelapse GIF Creator using the Shodan API

    import arrow
    import os
    import shodan
    import shodan.helpers as helpers
    import sys
    
    
    # Settings
    API_KEY = ''
    
    # The user has to provide at least 1 Shodan data file
    if len(sys.argv) < 2:
    	print('Usage: {} <shodan-data.json.gz> ...'.format(sys.argv[0]))
    	sys.exit(1)
    
    # GIFs are stored in the local "data" directory
    os.mkdir('data')
    
    # Setup the Shodan API object
    api = shodan.Shodan(API_KEY)
    
    # Loop over all of the Shodan data files the user provided
    for banner in helpers.iterate_files(sys.argv[1:]):
    	# See whether the current banner has a screenshot, if it does then lets lookup
    	# more information about this IP
    	has_screenshot = helpers.get_screenshot(banner)
    	if has_screenshot:
    		ip = helpers.get_ip(banner)
    		print('Looking up {}'.format(ip))
    		host = api.host(ip, history=True)
    		
    		# Store all the historical screenshots for this IP
    		screenshots = []
    		for tmp_banner in host['data']:
    			# Try to extract the image from the banner data
    			screenshot = helpers.get_screenshot(tmp_banner)
    			if screenshot:
    				# Sort the images by the time they were collected so the GIF will loop
    				# based on the local time regardless of which day the banner was taken.
    				timestamp = arrow.get(banner['timestamp']).time()
    				sort_key = timestamp.hour
    
    				# Add the screenshot to the list of screenshots which we'll use to create the timelapse
    				screenshots.append((
    					sort_key,
    					screenshot['data']
    				))
    
    		# Extract the screenshots and turn them into a GIF if we've got more than a few images
    		if len(screenshots) >= 3:
    			# screenshots is a list where each item is a tuple of:
    			# (sort key, screenshot in base64 encoding)
    			# 
    			# Lets sort that list based on the sort key and then use Python's enumerate
    			# to generate sequential numbers for the temporary image filenames
    			for (i, screenshot) in enumerate(sorted(screenshots, key=lambda x: x[0], reverse=True)):
    				# Create a temporary image file
    				# TODO: don't assume that all images are "jpg", use the mimetype instead
    				open('/tmp/gif-image-{}.jpg'.format(i), 'w').write(screenshot[1].decode('base64'))
    			
    			# Create the actual GIF using the  ImageMagick "convert" command
    			# The resulting GIFs are stored in the local data/ directory
    			os.system('convert -layers OptimizePlus -delay 5x10 /tmp/gif-image-*.jpg -loop 0 +dither -colors 256 -depth 8 data/{}.gif'.format(ip))
    
    			# Clean up the temporary files
    			os.system('rm -f /tmp/gif-image-*.jpg')
    
    			# Show a progress indicator
    			print('GIF created for {}'.format(ip))
    

    使用iterate_files()遍历Shodan数据文件。在shodan.Shodan.host()方法中获取所有Shodan收集的IP的banner历史记录。

    下载屏幕截图的JSON数据包:

    shodan download --limit -1 screenshots.json.gz has_screenshot:true
    

    *例子——公开的MongoDB数据

    MongoDB是一个流行的NoSQL数据库。在很长一段时间内,MongoDB默认是不需要输入用户名和密码,就可以登录。导致了许多MongoDB的服务在互联网上可以被公开访问。(见shodan扫描结果:3万个MongoDB可以无密码访问 大概包含595Tb数据

    使用Shodan抓取这些数据库的banner,其中包含了大量关于存储数据的信息。以下是banner的概要:

    IP: 115.231.180.54
    MongoDB Server Information
    Authentication partially enabled
    {
        "storageEngines": [
            "devnull", 
            "ephemeralForTest", 
            "mmapv1", 
            "wiredTiger"
        ], 
        "maxBsonObjectSize": 16777216, 
        "ok": 1.0, 
        "bits": 64, 
        "modules": [], 
        "openssl": {
            "compiled": "OpenSSL 1.0.1f 6 Jan 2014", 
            "running": "OpenSSL 1.0.1f 6 Jan 2014"
        }, 
        "javascriptEngine": "mozjs", 
        "version": "3.2.18", 
        "gitVersion": "4c1bae566c0c00f996a2feb16febf84936ecaf6f", 
        "versionArray": [
            3, 
            2, 
            18, 
            0
        ], 
        "debug": false, 
        "buildEnvironment": {
            "cxxflags": "-Wnon-virtual-dtor -Woverloaded-virtual -Wno-maybe-uninitialized -std=c++11", 
            "cc": "/opt/mongodbtoolchain/bin/gcc: gcc (GCC) 4.8.2", 
            "linkflags": "-fPIC -pthread -Wl,-z,now -rdynamic -fuse-ld=gold -Wl,-z,noexecstack -Wl,--warn-execstack", 
            "distarch": "x86_64", 
            "cxx": "/opt/mongodbtoolchain/bin/g++: g++ (GCC) 4.8.2", 
            "ccflags": "-fno-omit-frame-pointer -fPIC -fno-strict-aliasing -ggdb -pthread -Wall -Wsign-compare -Wno-unknown-pragmas -Winvalid-pch -Werror -O2 -Wno-unused-local-typedefs -Wno-unused-function -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-missing-braces -fno-builtin-memcmp", 
            "target_arch": "x86_64", 
            "distmod": "ubuntu1404", 
            "target_os": "linux"
        }, 
        "sysInfo": "deprecated", 
        "allocator": "tcmalloc"
    },
    ....
    

    基本上,banner是MongoDB服务器信息和及其3个JSON对象用逗号分隔而组成。或者有的banner里有需要登陆凭据的验证字符——“authentication enabled”。每个JSON对象都包含有关数据库的不同信息,建议在Shodan网站上查看完整的头信息,方法是搜索:

    metrics字符保证了搜索时只搜索不需要认证的MongoDB服务

    接下来使用banner信息统计最流行的数据库名称,以及在互联网上暴露的数据量。基本的工作流程:

    1. 下载所有的MongoDB banner数据
    2. 处理下载的文件,并输出前十个数据库名称的列表以及总数据大小
    shodan download --limit -1 mongodb-servers.json.gz product:mongodb
    

    上述命令功能是,利用Shodan搜索关于mongodb的设备信息,并使用--limit -1指令下载所有的查询结果,输出到mongodb-servers.json.gz文件。

    使用Python脚本处理刚才所下载的数据。

    要轻松遍历文件,将使用shodan.helpers.iterate_files()方法:

    import shodan.helpers as helpers
    import sys
    
    # datafile变量是命令行的第一个参数
    datafile = sys.argv[1]
    
    for banner in helpers.iterate_files(datafile):
        # 获得banner
    

    由于每个banner仅仅是带有头信息的JSON,因此可以使用simplejson库将banner处理为本地的Python字典:

    # 去除Shodan加入的MongoDB的头信息
    data = banner['data'].replace('MongoDB Server Information\n', '').split('\n},\n'\
    )[2]
    # 加载数据库信息
    data = simplejson.loads(data + '}')
    

    接下来的事情就是记录暴露的数据总量和最流行的数据库名称:

    total_data = 0
    databases = collections.defaultdict(int)
    
    ...
    
        # 然后循环
        # 跟踪可访问的数据
        total_data += data['totalSize']
    
        # 跟踪哪些数据库使用最多
        for db in data['databases']:
            databases[db['name']] += 1
    

    Python有一个有用的collections.defaultdict类,该类的功能是,如果字典的键尚不存在,这个类将自动为字典的键创建一个默认值。只需访问 MongoDB banner的totalSizedatabases属性即可收集的信息。最后,我们只需要输出实际结果:

    print('Total: {}'.format(humanize_bytes(total_data)))
    
    counter = 1
    for name, count in sorted(databases.iteritems(), key=operator.itemgetter(1),reverse=True[:10]:
        print('#{}\t{}: {}'.format(counter, name, count))
        counter += 1
    

    首先打印数据总量,然后使用humanize_bytes()方法将字节存储转换为易读的MB、GB等存储格式。

    其次,对数据库集合进行多次逆序遍历排序(key=operator.itemgetter(1)),取结果的TOP10([:10])。

    以下是读取Shodan数据文件并分析banner的完整脚本:

    #!C:\Python27\python.exe
    # -*- coding: utf-8 -*-
    # @Time    : 2018/2/2 10:01
    # @Author  : b404
    # @File    : MongDB_Shodan.py
    # @Software: PyCharm
    
    import collections
    import operator
    import shodan.helpers as helpers
    import sys
    import simplejson
    
    def humanize_bytes(bytes, precision=1):
        """将字节转换为易读的存储单位MB、GB等
    
        Assumes `from __future__ import division`.
    
        >>> humanize_bytes(1)
        '1 byte'
        >>> humanize_bytes(1024)
        '1.0 kB'
        >>> humanize_bytes(1024*123)
        '123.0 kB'
        >>> humanize_bytes(1024*12342)
        '12.1 MB'
        >>> humanize_bytes(1024*12342,2)
        '12.05 MB'
        >>> humanize_bytes(1024*1234,2)
        '1.21 MB'
        >>> humanize_bytes(1024*1234*1111,2)
        '1.31 GB'
         >>> humanize_bytes(1024*1234*1111,1)
            '1.3 GB'
            """
        abbrevs = (
            (1 << 50L, 'PB'),
            (1 << 40L, 'TB'),
            (1 << 30L, 'GB'),
            (1 << 20L, 'MB'),
            (1 << 10L, 'kB'),
            (1, 'bytes')
        )
        if bytes == 1:
            return '1 byte'
        for factor, suffix in abbrevs:
            if bytes >= factor:
                break
        return '%.*f %s' % (precision, bytes / factor, suffix)
    
    total_data = 0
    databases = collections.defaultdict(int)
    for banner in helpers.iterate_files(sys.argv[1]):
        try:
            # 去除Shodan加入的MongoDB的头信息
            data = banner['data'].replace('MongoDB Server Information\n', '').split('\n},\n')[2]
    
            # 加载数据库信息
            data = simplejson.loads(data + '}')
            # 记录公开访问的数据量
            total_data += data['totalSize']
    
            # 跟踪哪些数据库名称最常见
            for db in data['databases']:
                databases[db['name']] += 1
        except Exception, e:
            pass
    
    print('Total: {}'.format(humanize_bytes(total_data)))
    
    counter = 1
    for name, count in sorted(databases.iteritems(), key=operator.itemgetter(1), reverse=True)[:10]:
        print('#{}\t{}: {}'.format(counter, name, count))
    counter += 1
    

    该脚本输出:

    Total: 569.7 GB
    #1	Warning: 1448
    #1	local: 1172
    #1	admin: 488
    #1	README: 113
    #1	config: 67
    #1	test: 43
    #1	DATA_HAS_BEEN_BACKED_UP: 19
    #1	logs: 19
    #1	db_has_been_backed_up: 15
    #1	gpsreal: 11
    

    工业控制系统

    工控指的是工业自动化控制,主要利用电子电气、机械、软件组合实现。打比方说,工业控制系统(ICS)是控制周围世界的计算机。它们负责管理办公室的空调、发电厂的涡轮机、剧院的照明设备或者工厂的机器人。

    可以去灯塔实验室(http://plcscan.org/blog/)和https://cs3sthlm.se/ 了解工控的相关姿势

    SHINE项目(SHodan INTElligence Extraction)研究表明,从2012至2014年,互联网上至少有200万个可公开访问的工控设备。在2012年,第一个包含500,000个ICS设备的数据库被发送到ICS- cert。ICS-CERT认定,在美国50万的设备中,大约有7200个是关键的基础设施。随着对工控安全做出很多努力,越来越多的工控设备进行漏洞修补或者关机下线。但这是一个具有挑战性的问题,而且针对工控安全问题的解决方案没有一个是简单的。

    下图是2014年Shodan爬取的工控全球分布图:

    常用缩写

    以下是一些常用的缩写,有助于后面了解协议,快速找到ICS设备:

    缩写说明
    SCADA数据采集与监视控制系统
    ICS工业控制系统
    DCS分布式控制系统/集散控制系统
    PCS过程控制系统
    ESD应急停车系统
    PLC可编程序控制器(Programmable Logic Controller)
    RTU远程终端控制系统
    IED智能监测单元
    HMI人机界面(Human Machine Interface)
    MIS管理信息系统(Management Information System)
    SIS生产过程自动化监控和管理系统(Supervisory Information System)
    MES制造执行管理系统
    BMS建筑管理系统(uilding Management System)
    VNC虚拟网络计算(Virtual Network Computing)

    协议

    识别联网的控制系统有两种不同的方式:

    1. 在ICS环境中使用的非ICS协议。

    Shodan的ICS搜索结果大部分是通过搜索WEB服务器或其他常用的协议发现的,这些协议并不是直接与ICS相连接,而是可以在ICS网络上看到。例如,运行在HMI上的Web服务器或未经身份验证的Windows远程桌面直接连接在ICS网络上,这些协议将回提供一个ICS的可视化界面。(但大多常用某种形式进行身份验证)

    2. ICS协议

    ICS协议是控制系统使用的原始协议。每个ICS协议都有其独特的标志,它们都有一个共同点:它们不需要任何认证。这意味着,如果可以远程访问工业设备,则可以自动对其进行读取和写入。但是,原始的ICS协议往往很难开发,是独有的,实际也很难与控制系统交互。也就是使用Shodan很容易检查设备是否支持ICS协议。

    下图的banner是一个Siemens S7 PLC设备的Shodan搜索图,banner暴露了其序列号和位置:

    Modbus

    MODBUS协议定义了一个与基础通信层无关的简单协议数据单元(PDU)。特定总线或网络上的MODBUS协议映射能够在应用数据单元(ADU)上引入一些附加域。

    工控安全问题:

    • 缺乏认证:仅需要使用一个合法的Modbus地址和合法的功能码即可以建立一个Modbus会话
    • 缺乏授权:没有基于角色的访问控制机制,任意用户可以执行任意的功能。
    • 缺乏加密:地址和命令明文传输,可以很容易地捕获和解析

    PROFIBUS

    PROFIBUS 一种用于工厂自动化车间级监控和现场设备层数据通信与控制的现场总线技术,可实现现场设备层到车间级监控的分散式数字控制和现场通信网络

    DNP3

    DNP3 DNP(Distributed Network Protocol,分布式网络协议)是一种应用于自动化组件之间的通讯协议,常见于电力、水处理等行业。简化OSI模型,只包含了物理层,数据层与应用层的体系结构(EPA)。SCADA可以使用DNP协议与主站、RTU、及IED进行通讯。

    ICCP

    ICCP 电力控制中心通讯协议。

    OPC

    OPC 过程控制的OLE (OLE for Process Control)。OPC包括一整套接口、属性和方法的标准集,用于过程控制和制造业自动化系统。

    BACnet

    BACnet 楼宇自动控制网络数据通讯协议(A Data Communication Protocol for Building Automation and Control Networks)。BACnet 协议是为计算机控制采暖、制冷、空调HVAC系统和其他建筑物设备系统定义服务和协议

    CIP

    CIP 通用工业协议,被deviceNet、ControINet、EtherNet/IP三种网络所采用。

    Siemens S7

    Siemens S7 属于第7层的协议,用于西门子设备之间进行交换数据,通过TSAP,可加载MPI,DP,以太网等不同物理结构总线或网络上,PLC一般可以通过封装好的通讯功能块实现。

    其他工控协议

    其他工控协议IEC 60870-5-104、EtherNet/IP、Tridium Niagara Fox、Crimson V3、OMRON FINS、PCWorx、ProConOs、MELSEC-Q

    架构缺陷

    • 未经真正安全考验的组件与协议
      • 若有Web服务,那就利用Web服务该有的缺陷
      • 经典渗透技巧大多适用于工控网络
    • 稳定性优先+懒 → 升级难
    • 互联网的便利性,让工控组件暴露在网络空间里
    • 以协议研究为出发点

    工控系统的指纹识别技术

    http://plcscan.org/blog/2017/03/fingerprint-identification-technology-of-industrial-control-system/

    信息探测

    Ethernet/IP

    Port:44818

    • Nmap: enip-enumerate.nse
    • Python: https://github.com/paperwork/pyenip
    • Wireshark dissector
      • src/epan/dissector/packet-etherip.c

    Modbus

    • port:502
    • 抓取设备相关信息
    • Nmap: modicon-info.nse
    • Wireshark dissector
      • src/epan/dissector/packet-mbtcp.c
    • 认证与加密缺失

    IEC 61870-5-101/104

    • Port: 2404
    • 判断是否使用该协议
      • Nmap: iec-identify.nse
      • Wireshark dissector
        • src/epan/dissectors/packet-iec104.c
    • 认证与加密缺失

    Siemens S7

    • key:Siemens S7 PLC(102)
    • 抓取设备相关信息
    • Nmap: s7-enumerate_.nse
      • http://plcscan.org/blog/wp-content/uploads/2014/11/s7-enumerate.nse_.txt
    • Wireshark plugins
      • http://sourceforge.net/projects/s7commwireshark/
    • 弱加密,易破解

    Tridium Niagara Fox

    • port:1911
    • 抓取设备信息
      • Nmap: fox-info.nse

    以下是有关banner的最新属性字段列表(若要查看最新的,请访问在线文档):

    常用属性

    名称描述举例
    asn自治系统号AS4837
    data服务的主要bannerHTTP/1.1 200…
    ip整数型的IP地址格式493427495
    ip_str字符串型IP199.30.15.20
    ipv6字符串型IPv62001:4860:4860::8888
    port服务的端口号80
    timestamp收集信息的日期2014-01-15T05:49:56.283713
    hash数据属性的散列值Numeric hash of the data property
    hostnames目标IP的主机名[“shodan.io”, “www.shodan.io”]
    domains目标IP的所有域名[“shodan.io”]
    link网络连接类型以太网/调制解调器
    location设备的物理地址见下文
    opts补充或者实验数据不包含在主要的banner中 
    org分配IP的组织Google Inc.
    isp负责IP空间的ISPVerizon Wireless
    os操作系统Linux
    uptimeIP上线时间50
    tags描述设备用途的标签列表(仅供企业型账号使用)[“ics”, “vpn”]
    transport用于收集banner的传输协议(UDP或者是TCP)tcp

    Elastic属性

    下列属性是为 Elastic (曾经的 ElasticSearch)收集的:

    名称描述
    elastic.cluster有关集群的一般信息
    elastic.indices集群上可用的索引列表
    elastic.nodes群集的节点/对等点列表及其信息

    HTTP(S)属性

    Shodan遵循HTTP响应的重定向,并将所有中间数据存储在banner中。抓取工具不遵循重定向的情况是HTTP请求被重定向到HTTPS位置,反之亦然:

    名称描述
    http.components用于创建网站的网络技术
    http.host发送主机名来抓取网站的HTML
    http.html网站的HTML内容
    http.html_hashhttp.html属性的数字散列
    http.location最终的HTML响应的位置
    http.redirects遵循的重定向列表。每个重定向项目有3个属性:主机,数据和位置
    http.robotsrobots.txt文件的网站
    http.serverHTTP响应的服务器头
    http.sitemap网站的Sitemap XML
    http.title网站的标题

    位置属性

    名称描述
    area_code设备位置的区号
    city城市名称
    country_code2个字母组成的国家代码
    country_code33个字母组成的国家代码
    country_name国家的全名
    dma_code指定市场区号(仅限美国)
    latitude纬度
    longitude经度
    postal_code邮政编码
    region_code地区代码

    SMB属性

    名称描述
    smb.anonymous服务是否允许匿名连接(true/false)
    smb.capabilities服务支持的功能列表
    smb.shares可用的网络共享列表
    smb.smb_version用于收集信息的协议版本
    smb.software提供服务的软件
    smb.raw服务器发送的十六进制编码数据包列表;如果想做SMB解析,这很有用

    SSH属性

    名称描述
    ssh.cipher协商期间使用的密码
    ssh.fingerprint设备的指纹
    ssh.kex服务器支持的密钥交换算法列表
    ssh.key服务器的SSH密钥
    ssh.mac消息认证码算法

    SSL 属性

    如果服务使用SSL进行包装,则Shodan将执行附加测试,并在以下属性中提供结果:

    名称描述
    ssl.acceptable_cas服务器接受的证书颁发机构列表
    ssl.cert可解析的SSL证书
    ssl.cipherSSL连接的首选密码
    ssl.chain从用户证书到根证书的SSL证书列表
    ssl.dhparamsDiffie-Hellman参数
    ssl.tlsext服务器支持的TLS扩展列表
    ssl.versions支持的SSL版本;如果该值用-开头,则该服务不支持该版本(例如:“-SSLv2”是指不支持SSLv2的服务)

    ISAKMP属性

    以下为使用ISAKMP协议的VPN(例如IKE)收集的属性:

    名称描述
    isakmp.initiator_spi初始化器的hex编码的安全参数索引
    isakmp.responder_spi用于响应器的hex编码的安全参数索引
    isakmp.next_payload启动后发送的下一个载荷
    isakmp.version协议版本;例如“1.0”
    isakmp.exchange_type交换类型
    isakmp.flags.encryption加密设置:true或false
    isakmp.flags.commit提交设置:true或false
    isakmp.flags.authentication认证设置:true或false
    isakmp.msg_id消息的十六进制编码标识
    isakmp.lengthISAKMP数据包的大小

    特殊属性

    _shodan

    _shodan属性包含有关数据如何被Shodan收集的信息。它与其他属性不同,因为它不提供有关设备的信息。相反,它会告诉你Shodan使用哪一个banner抓取器来与目标IP交互。这对于探知服务器上的端口运行服务情况是很重要的。例如,80端口是最知名的Web服务端口,但它也被各种恶意软件用来规避防火墙规则,_shodan属性将让你知道是该端口否用HTTP模块来收集数据或是否使用了反恶意软件模块。

    名称描述
    _shodan.crawler识别Shodan爬取工具的唯一ID
    _shodan.id此banner的唯一ID
    _shodan.module爬虫抓取banner而使用SHodan模块的名称
    _shodan.options数据收集期间使用的配置选项
    _shodan.hostname发送Web请求时使用的主机名
    _shodan.options.referrer为某端口/服务触发扫描的banner的惟一ID

    例子

    {
       "timestamp": "2014-01-16T08:37:40.081917","timestamp": "2014-01-16T08:37:40.081917",
       "hostnames": ["hostnames": [
          "99-46-189-78.lightspeed.tukrga.sbcglobal.net""99-46-189-78.lightspeed.tukrga.sbcglobal.net"
       ],],
       "org": "AT&T U-verse","org": "AT&T U-verse",
       "guid": "1664007502:75a821e2-7e89-11e3-8080-808080808080","guid": "1664007502:75a821e2-7e89-11e3-8080-808080808080",
       "data": "NTP\nxxx.xxx.xxx.xxx:7546\n68.94.157.2:123\n68.94.156.17:123","data": "NTP\nxxx.xxx.xxx.xxx:7546\n68.94.157.2:123\n68.94.156.17:123",
       "port": 123,"port": 123,
       "isp": "AT&T U-verse","isp": "AT&T U-verse",
       "asn": "AS7018","asn": "AS7018",
       "location": {"location": {
          "country_code3": "USA","country_code3": "USA",
          "city": "Atlanta","city": "Atlanta",
          "postal_code": "30328","postal_code": "30328",
          "longitude": -84.3972,"longitude": -84.3972,
          "country_code": "US","country_code": "US",
          "latitude": 33.93350000000001,"latitude": 33.93350000000001,
          "country_name": "United States","country_name": "United States",
          "area_code": 404,"area_code": 404,
          "dma_code": 524,"dma_code": 524,
          "region_code": null"region_code": null
       },},
       "ip": 1664007502,"ip": 1664007502,
       "domains": ["domains": [
          "sbcglobal.net""sbcglobal.net"
       ],],
       "ip_str": "99.46.189.78","ip_str": "99.46.189.78",
       "os": null,"os": null,
       "opts": {"opts": {
          "raw": "\\x97\\x00\\x03*\\x00\\x03\\x00H\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01G\\x06\\xa7\\x8ec.\\xbdN\\x00\\x00\\x00\\x01\\x1dz\\x07\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00q\\x00\\x00\\x00i\\x00\\x00\\x00\\x00\\x00\\x00\\x00XD^\\x9d\\x02c.\\xbdN\\x00\\x00\\x00\\x01\\x00{\\x04\\x04\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00q\\x00\\x00\\x00o\\x00\\x00\\x00\\x00\\x00\\x00\\x00YD^\\x9c\\x11c.\\xbdN\\x00\\x00\\x00\\x01\\x00{\\x04\\x04\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00","raw": "\\x97\\x00\\x03*\\x00\\x03\\x00H\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01G\\x06\\xa7\\x8ec.\\xbdN\\x00\\x00\\x00\\x01\\x1dz\\x07\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00q\\x00\\x00\\x00i\\x00\\x00\\x00\\x00\\x00\\x00\\x00XD^\\x9d\\x02c.\\xbdN\\x00\\x00\\x00\\x01\\x00{\\x04\\x04\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00q\\x00\\x00\\x00o\\x00\\x00\\x00\\x00\\x00\\x00\\x00YD^\\x9c\\x11c.\\xbdN\\x00\\x00\\x00\\x01\\x00{\\x04\\x04\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00",
          "ntp": {"ntp": {
             "more": false"more": false
          }}
       }}
    }}
    
    

    附录B:搜索语法关键词列表

    常用语法

    过滤器名描述类型举例
    after只显示给出日期之后的结果(dd/mm/yyyy)stringafter:"04/02/2017"
    asn自治系统号码stringasn:"AS4130"
    before只显示给出日期之前的结果(dd/mm/yyyy)stringbefore:"04/02/2017"
    category现有的分类:ics,malwarestringcategory:"malware"
    city城市的名字stringcity:"San Diego"
    country国家简写stringcountry:"ES" country:"CN"
    geo经纬度stringgeo:"46.9481,7.4474"
    hash数据的hash值int-hash:0
    has_ipv6是否是IPv6booleanhas_ipv6:true
    has_screenshot是否有截图booleanhas_screenshot:true
    hostname主机名或域名stringhostname:"google"
    ipip地址stringip:"54.67.82.248 "
    ispISP供应商stringisp:"China Telecom"
    org组织或公司stringorg:"google"
    os操作系统stringos:"Windows 7 or 8"
    port端口号intport:21
    postal邮政编码(仅限于美国)stringpostal:"98221"
    product软件、平台stringproduct:"Apache httpd" product:"openssh"
    region地区或国家别名string
    state string
    netCIDR格式的IP地址stringnet:190.30.40.0/24
    version软件版本stringversion:"2.6.1"
    vuln漏洞的CVE IDstringvuln:CVE-2014-0723

    HTTP过滤器

    名称描述类型
    http.component网站上所使用的网络技术名称string
    http.component_category网站上使用的网络组件的类别string
    http.htmlWeb bannerstring
    http.html_hash网站HTML的哈希值int
    http.status响应状态码int
    http.title网站title得bannerstring

    NTP 过滤器

    名称描述类型
    ntp.ip查找在其monlist中NTP服务器的IP 
    ntp.ip_count初始monlist返回的IP数量int
    ntp.more真/假; monlist集是否有更多的IP地址boolean
    ntp.portmonlist中的IP地址使用的端口int

    SSL过滤器

    名称描述类型
    has_ssl有无SSLboolean
    SSL搜索所有SSL的数据string
    ssl.alpn诸如HTTP/2的应用层协议string
    ssl.chain_count链中的证书数量int
    ssl.version可能的值:SSLv2,SSLv3,TLSv1,TLSv1.1,TLSv1.2string
    ssl.cert.alg证书算法string
    ssl.cert.expired是否是过期证书boolean
    ssl.cert.extension证书中的扩展名string
    ssl.cert.serial序列号为整数或十六进制字符串int/string
    ssl.cert.pubkey.bits公钥的位数int
    ssl.cert.pubkey.type公钥类型string
    ssl.cipher.versionSSL版本的首选密码string
    ssl.cipher.bits首选密码中的位数int
    ssl.cipher.name首选密码的名称string

    Telnet 过滤器

    名称描述类型
    telnet.option搜索所有选项string
    telnet.do对方执行的请求或期望对方执行指示的选项string
    telnet.dont对方停止执行的请求或不再期望对方执行指定的选项string
    telnet.will确认现在正在执行指定的选项string
    telnet.wont表示拒绝执行或继续执行指定的选项string

    附录C:Facets搜索

    常用Facets

    名称描述
    asn自治系统号码
    city城市的全名
    country国家的全名
    domain设备的域名
    has_screenshot有无可用的截图
    ispISP管理网络块
    link网络连接的类型
    org拥有该网块的组织
    os操作系统
    port服务的端口号
    postal邮政编码
    product软件/产品的名称
    region地区/国家的名称
    state区域的别名
    uptime主机启动的时间(以秒为单位计算)
    vuln漏洞的CVE ID

    HTTP Facets

    名称描述类型
    http.component网站上使用的网络技术的名称string
    http.component_category网站上使用的网络组件的类别string
    http.html_hashHTML网站的哈希值int
    http.status响应状态码int

    NTP Facets

    名称描述
    ntp.ipmonlist返回的IP地址
    ntp.ip_count初始monlist返回的IP数量
    ntp.more真假; monlist收集的是否有更多的IP地址
    ntp.portmonlist中的IP地址使用的端口

    SSH Facets

    名称描述
    ssh.cipher密码的名称
    ssh.fingerprint设备的指纹
    ssh.mac使用的MAC算法名称(例如:hmac-sha1)
    ssh.type认证密钥的类型(例如:ssh-rsa)

    SSL Facets

    名称描述
    ssl.version支持SSL版本
    ssl.alpn应用层协议
    ssl.chain_count链中的证书数量
    ssl.cert.alg证书算法
    ssl.cert.expired真假; 证书过期与否
    ssl.cert.serial证书序列号为整数
    ssl.cert.extension证书扩展名
    ssl.cert.pubkey.bits公钥的位数
    ssl.cert.pubkey公钥类型的名称
    ssl.cipher.bits首选密码中的位数
    ssl.cipher.name首选密码的名称
    ssl.cipher.versionSSL版本的首选密码

    Telnet Facets

    名称描述类型
    telnet.option显示所有选项string
    telnet.do对方执行的请求或期望对方执行指示的选项string
    telnet.dont对方停止执行的请求或不再期望对方执行指定的选项string
    telnet.will服务器支持指定的选项string
    telnet.wont服务器不支持指定的选项string

    附录D:端口列表

    PortService
    7Echo
    11Systat
    13Daytime
    15Netstat
    17Quote of the day
    19Character generator
    21FTP
    22SSH
    23Telnet
    25SMTP
    26SSH
    37rdate
    49TACACS+
    53DNS
    67DHCP
    69TFTP, BitTorrent
    70Gopher
    79Finger
    80HTTP, malware
    81HTTP, malware
    82HTTP, malware
    83HTTP
    84HTTP
    88Kerberos
    102Siemens S7
    104DICOM
    110POP3
    111Portmapper
    113identd
    119NNTP
    123NTP
    129Password generator protocol
    137NetBIOS
    143IMAP
    161SNMP
    175IBM Network Job Entry
    179BGP
    195TA14-353a
    311OS X Server Manager
    389LDAP
    389CLDAP
    443HTTPS
    443QUIC
    444TA14-353a, Dell SonicWALL
    445SMB
    465SMTPS
    500IKE (VPN)
    502Modbus
    503Modbus
    515Line Printer Daemon
    520RIP
    523IBM DB2
    554RTSP
    587SMTP mail submission
    623IPMI
    626OS X serialnumbered
    636LDAPS
    666Telnet
    771Realport
    789Redlion Crimson3
    873rsync
    902VMWare authentication
    992Telnet (secure)
    993IMAP with SSL
    995POP3 with SSL
    1010malware
    1023Telnet
    1025Kamstrup
    1099Java RMI
    1177malware
    1200Codesys
    1234udpxy
    1400Sonos
    1434MS-SQL monitor
    1515malware
    1521Oracle TNS
    1604Citrix, malware
    1723PPTP
    1741CiscoWorks
    1833MQTT
    1900UPnP
    1911Niagara Fox
    1962PCworx
    1991malware
    2000iKettle, MikroTik bandwidth test
    2081Smarter Coffee
    2082cPanel
    2083cPanel
    2086WHM
    2087WHM
    2123GTPv1
    2152GTPv1
    2181Apache Zookeeper
    2222SSH, PLC5, EtherNet/IP
    2323Telnet
    2332Sierra wireless (Telnet)
    2375Docker
    2376Docker
    2379etcd
    2404IEC-104
    2455CoDeSys
    2480OrientDB
    2628Dictionary
    3000ntop
    3260iSCSI
    3306MySQL
    3310ClamAV
    3386GTPv1
    3388RDP
    3389RDP
    3460malware
    3541PBX GUI
    3542PBX GUI
    3689DACP
    3702Onvif
    3780Metasploit
    3787Ventrilo
    4000malware
    4022udpxy
    4040Deprecated Chef web interface
    4063ZeroC Glacier2
    4064ZeroC Glacier2 with SSL
    4070HID VertX/ Edge door controller
    4157DarkTrack RAT
    4369EPMD
    4443Symantec Data Center Security
    4444malware
    4500IKE NAT-T (VPN)
    4567Modem web interface
    4664Qasar
    4730Gearman
    4782Qasar
    4800Moxa Nport
    4840OPC UA
    4911Niagara Fox with SSL
    4949Munin
    5006MELSEC-Q
    5007MELSEC-Q
    5008NetMobility
    5009Apple Airport Administration
    5060SIP
    5094HART-IP
    5222XMPP
    5269XMPP Server-to-Server
    5353mDNS
    5357Microsoft-HTTPAPI/2.0
    5432PostgreSQL
    5577Flux LED
    5601Kibana
    5632PCAnywhere
    5672RabbitMQ
    5900VNC
    5901VNC
    5938TeamViewer
    5984CouchDB
    6000X11
    6001X11
    6379Redis
    6666Voldemort database, malware
    6667IRC
    6881BitTorrent DHT
    6969TFTP, BitTorrent
    7218Sierra wireless (Telnet)
    7474Neo4j database
    7548CWMP (HTTPS)
    7777Oracle
    7779Dell Service Tag API
    8008Chromecast
    8009Vizio HTTPS
    8010Intelbras DVR
    8060Roku web interface
    8069OpenERP
    8087Riak
    8090Insteon HUB
    8099Yahoo SmartTV
    8112Deluge (HTTP)
    8126StatsD
    8139Puppet agent
    8140Puppet master
    8181GlassFish Server (HTTPS)
    8333Bitcoin
    8334Bitcoin node dashboard (HTTP)
    8443HTTPS
    8554RTSP
    8800HTTP
    8880Websphere SOAP
    8888HTTP, Andromouse
    8889SmartThings Remote Access
    9000Vizio HTTPS
    9001Tor OR
    9002Tor OR
    9009Julia
    9042Cassandra CQL
    9051Tor Control
    9100Printer Job Language
    9151Tor Control
    9160Apache Cassandra
    9191Sierra wireless (HTTP)
    9418Git
    9443Sierra wireless (HTTPS)
    9595LANDesk Management Agent
    9600OMRON
    9633DarkTrack RAT
    9869OpenNebula
    10001Automated Tank Gauge
    10001Ubiquiti
    10243Microsoft-HTTPAPI/2.0
    10554RTSP
    11211Memcache
    12345malware
    17000Bose SoundTouch
    17185VxWorks WDBRPC
    12345Sierra wireless (Telnet)
    11300Beanstalk
    13579Media player classic web interface
    14147Filezilla FTP
    16010Apache Hbase
    16992Intel AMT
    16993Intel AMT
    18245General Electric SRTP
    20000DNP3
    20547ProconOS
    21025Starbound
    21379Matrikon OPC
    23023Telnet
    23424Serviio
    25105Insteon Hub
    25565Minecraft
    27015Steam A2S server query, Steam RCon
    27016Steam A2S server query
    27017MongoDB
    28015Steam A2S server query
    28017MongoDB (HTTP)
    30313Gardasoft Lighting
    30718Lantronix Setup
    32400Plex
    37777Dahuva DVR
    44818EtherNet/IP
    47808Bacnet
    49152Supermicro (HTTP)
    49153WeMo Link
    50070HDFS Namenode
    51106Deluge (HTTP)
    53413Netis backdoor
    54138Toshiba PoS
    55443McAfee
    55553Metasploit
    55554Metasploit
    62078Apple iDevice
    64738Mumble
    {
        "hostnames": [],
        "title": "",
        "ip": 2928565374,
        "isp": "iWeb Technologies",
        "transport": "tcp",
        "data": "HTTP/1.1 200 OK\r\nExpires: Sat, 26 Mar 2016 11:56:36 GMT\r\nExpire\
    s: Fri, 28 May 1999 00:00:00 GMT\r\nCache-Control: max-age=2592000\r\nCache-Cont\
    rol: no-store, no-cache, must-revalidate\r\nCache-Control: post-check=0, pre-che\
    ck=0\r\nLast-Modified: Thu, 25 Feb 2016 11:56:36 GMT\r\nPragma: no-cache\r\nP3P:\
     CP=\"NON COR CURa ADMa OUR NOR UNI COM NAV STA\"\r\nContent-type: text/html\r\n\
    Transfer-Encoding: chunked\r\nDate: Thu, 25 Feb 2016 11:56:36 GMT\r\nServer: sw-\
    cp-server\r\n\r\n",
     "asn": "AS32613",
        "port": 8443,
        "ssl": {
            "chain": ["-----BEGIN CERTIFICATE-----\nMIIDszCCApsCBFBTb4swDQYJKoZIhvcN\
    AQEFBQAwgZ0xCzAJBgNVBAYTAlVTMREw\nDwYDVQQIEwhWaXJnaW5pYTEQMA4GA1UEBxMHSGVybmRvbj\
    ESMBAGA1UEChMJUGFy\nYWxsZWxzMRgwFgYDVQQLEw9QYXJhbGxlbHMgUGFuZWwxGDAWBgNVBAMTD1Bh\
    cmFs\nbGVscyBQYW5lbDEhMB8GCSqGSIb3DQEJARYSaW5mb0BwYXJhbGxlbHMuY29tMB4X\nDTEyMDkx\
    NDE3NTUyM1oXDTEzMDkxNDE3NTUyM1owgZ0xCzAJBgNVBAYTAlVTMREw\nDwYDVQQIEwhWaXJnaW5pYT\
    EQMA4GA1UEBxMHSGVybmRvbjESMBAGA1UEChMJUGFy\nYWxsZWxzMRgwFgYDVQQLEw9QYXJhbGxlbHMg\
    UGFuZWwxGDAWBgNVBAMTD1BhcmFs\nbGVscyBQYW5lbDEhMB8GCSqGSIb3DQEJARYSaW5mb0BwYXJhbG\
    xlbHMuY29tMIIB\nIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxc9Vy/qajKtFFnHxGOFPHTxm\
    \nSOnsffWBTBfyXnK3h8u041VxvZDh3XkpA+ptg2fWOuIT0TTYuqw+tqiDmg8YTsHy\njcpMFBtXV2cV\
    dhKXaS3YYlM7dP3gMmkGmH+ZvCgCYc7L9MIJxYJy6Zeuh67YxEMV\ngiU8mZpvc70Cg5WeW1uBCXtUAi\
    jDLsVWnhsV3YuxlweEvkRpAk3EHehKbvgMnEZS\nQ30QySe0GAqC7bWzKrwsJAOUk/+Js18+3QKb/LmD\
    a9cRjtFCTo6hYfPbfHj8RxQh\n4Xmnn/CtZ48wRQTqKXSO6+Zk3OuU7/jX1Gt/jxN6n77673e6uCsggT\
    wut/EtNwID\nAQABMA0GCSqGSIb3DQEBBQUAA4IBAQBb/yTy76Ykwr7DBOPAXc766n73OsZizjAt\n1k\
    mx7LxgN3X/wFxD53ir+sdOqbPgJl3edrE/ZG9dNl6LhUBbUK+9s6z9QicEfSxo\n4uQpFSywbGGmXInE\
    ZmyT4SsOLi/hNgy68f49LO1h6rn/p7QgIKd31g7189ZfFkFb\nRdD49s1l/Cc5Nm4XapUVvmnS91MlPk\
    /OOIg1Lu1rYkuc8sIoZdPbep52H3Ga7TjG\nkmO7nUIii0goB7TQ63mU67+NWHAmQQ8CtCDCN49kJyen\
    1WFjD6Je2U4q0IFQrxHw\nMy+tquo/n/sa+NV8QOj1gMVcFsLhYm7Z5ZONg0QFXSAL+Eyj/AwZ\n----\
    -END CERTIFICATE-----\n"],
            "cipher": {
                "version": "TLSv1/SSLv3",
                "bits": 256,
                "name": "DHE-RSA-AES256-GCM-SHA384"
            },
            "alpn": [],
            "dhparams": {
                "prime": "b10b8f96a080e01dde92de5eae5d54ec52c99fbcfb06a3c69a6a9dca52\
    d23b616073e28675a23d189838ef1e2ee652c013ecb4aea906112324975c3cd49b83bfaccbdd7d90\
    c4bd7098488e9c219a73724effd6fae5644738faa31a4ff55bccc0a151af5f0dc8b4bd45bf35c1a65e68cfda76d4da708df1fb2bc2e4a4371",
                "public_key": "2e30a6e455730b2f24bdaf5986b9f0876068d4aa7a4e15c9a1b9c\
    a05a420e8fd3b496f7781a9423d3475f0bedee83f0391aaa95a738c8f0e250a8869a86d41bdb0194\
    66dba5c641e4b2b4b82db4cc2d4ea8d9804ec00514f30a4b6ce170b81c3e1ce4b3d17647c8e5b8f6\
    65bb7f588100bcc9a447d34d728c3709fd8a5b7753b",
                "bits": 1024,
                "generator": "a4d1cbd5c3fd34126765a442efb99905f8104dd258ac507fd6406c\
    ff14266d31266fea1e5c41564b777e690f5504f213160217b4b01b886a5e91547f9e2749f4d7fbd7\
    d3b9a92ee1909d0d2263f80a76a6a24c087a091f531dbf0a0169b6a28ad662a4d18e73afa32d779d\
    5918d08bc8858f4dcef97c2a24855e6eeb22b3b2e5",
                "fingerprint": "RFC5114/1024-bit MODP Group with 160-bit Prime Order\
     Subgroup"
            },
            "versions": ["TLSv1", "-SSLv2", "SSLv3", "TLSv1.1", "TLSv1.2"]
        },
        "html": "\n\t\t<html><head>\n\t\t<meta charset=\"utf-8\">\n\t\t<meta http-eq\
    uiv=\"X-UA-Compatible\" 
    content=\"IE=edge,chrome=1\">\n\t\t<title></title>\n\t\t\
    <script language=\"javascript\" type=\"text/javascript\" src=\"/javascript/commo\
    n.js?plesk_version=psa-11.0.9-110120608.16\"/></script>\n\t\t<script language=\"\
    javascript\" type=\"text/javascript\" src=\"/javascript/prototype.js?plesk_versi\
    on=psa-11.0.9-110120608.16\"></script>\n\t\t<script>\n\t\t\tvar opt_no_frames = \
    false;\n\t\t\tvar opt_integrated_mode = false;\n\t\t</script>\n\t\t\n\t\t</head>\
    <body onLoad=\";top.location='/login.php3?window_id=&amp;requested_url=https%3A%\
    2F%2F174.142.92.126%3A8443%2F';\"></body><noscript>You will be redirected to the\
     new address in 15 seconds... If you are not automatically taken to the new loca\
    tion, please enable javascript or click the hyperlink <a href=\"/login.php3?wind\
    ow_id=&amp;requested_url=https%3A%2F%2F174.142.92.126%3A8443%2F\" target=\"top\"\
    >/login.php3?window_id=&amp;requested_url=https%3A%2F%2F174.142.92.126%3A8443%2F\
    </a>.</noscript></html><!--_____________________________________________________\
    ________________________________________________________________________________\
    ________________________________________________________________________________\
    _________________________IE error page size limitation__________________________\
    ________________________________________________________________________________\
    ________________________________________________________________________________\
    ____________________________________________________-->",
        "location": {
            "city": null,
            "region_code": "QC",
            "area_code": null,
            "longitude": -73.5833,
            "country_code3": "CAN",
            "latitude": 45.5,
            "postal_code": "H3G",
            "dma_code": null,
            "country_code": "CA",
            "country_name": "Canada"
        },
        "timestamp": "2016-02-25T11:56:52.548187",
        "domains": [],
        "org": "iWeb Technologies",
         "os": null,
        "_shodan": {
            "options": {},
            "module": "https",
            "crawler": "122dd688b363c3b45b0e7582622da1e725444808"
        },
        "opts": {
            "heartbleed": "2016/02/25 03:56:45 ([]uint8) {\n 00000000  02 00 74 63 6\
    5 6e 73 75  73 2e 73 68 6f 64 61 6e  |..tcensus.shodan|\n 00000010  2e 69 6f 53 \
    45 43 55 52  49 54 59 20 53 55 52 56  |.ioSECURITY SURV|\n 00000020  45 59 fe 7a\
     a2 0d fa ed  93 42 ed 18 b0 15 7d 6e  |EY.z.....B....}n|\n 00000030  29 08 f6 f\
    8 ce 00 b1 94  b5 4b 47 ac dd 18 aa b9  |)........KG.....|\n 00000040  db 1c 01 \
    45 95 10 e0 a2  43 fe 8e ac 88 2f e8 75  |...E....C..../.u|\n 00000050  8b 19 5f\
     8c e0 8a 80 61  56 3c 68 0f e1 1f 73 9e  |.._....aV<h...s.|\n 00000060  61 4f d\
    a db 90 ce 84 e3  79 5f 9d 6c a0 90 ff fa  |aO......y_.l....|\n 00000070  d8 16 \
    e8 76 07 b2 e5 5e  8e 3e a4 45 61 2f 6a 2d  |...v...^.>.Ea/j-|\n 00000080  5d 11\
    74 94 03 3c 5d                              |].t..<]|\n}\n\n2016/02/25 03:56:45\
     174.142.92.126:8443 - VULNERABLE\n",
            "vulns": ["CVE-2014-0160"]
        },
        "ip_str": "174.142.92.126"
    }

    常用命令

    shodan search --limit 10 --fields ip_str,port country:kr device:router
    city:shanghai
    port:8080
    os:windows xp
    device:webcan,router,switch
    has_vuln:true
    
    shodan host ip
    
    Windows RDP CVE-2019-0708(bluekeep):
    shodan search '"x03ixO0lx00lx0blx06lxdO\xOOlx00\x124\x00"'
    shodan download name.file --limit number content 
    shodan parse --fields ip_str file.location > 0708.txt
    msf:
    set rhosts file:file.location
    file formats: 
    ip1
    ip2
    
    shodan search --limit 30 --fields ip_str "authentication disabled" port:5900 #搜索vnc空密码的服务器
    shodan download --limit 30 xxx 
    shodan count xxx
    shodan parse --fileds ip_str "file.location" > vnc.txt #解析下载的文件并把指定字段写入vnc.txt
    shodan honeypot 8.8.8.8 #查看服务器是否是蜜罐
    shodan host 8.8.8.8 --history #查看服务器的历史信息:以前的漏洞,部署过的服务等
    shodan myip #查看联公网的出口ip
    shodan --limit 10 --fields ip_str,port http.title:hacked by
    shodan --limit 10 --fields ip_str,port "cisco -authorized port:23"
    shodan --limit 10 --fields ip_str,port net:208.88.84.0/24 #搜索网段
    has_screenhot:true encrypted attention #搜索有快照的服务器,并且根据快照OCR文字进行过滤,比如回收站
    has_screenhot:true screenshot.label:ics #搜索工控设备
    shodan stats --facets ssl.version country:cn has_ssl:true #统计分析

    VS Google搜索

    https://www.exploit-db.com/google-hacking-database

    有很多google高级语法可以借鉴

  • 密码保护:渗透测试笔记

    密码保护:渗透测试笔记

    此内容受密码保护。如需查阅,请在下列字段中输入您的密码。

  • 计算机网络通讯

    计算机网络通讯

    基本概念

    信道(channel)

    通讯领域的基本概念,信道就是“传送信息的通道”。

    信道的类型

    信道可以从广义上分为“物理信道 & 逻辑信道”。顾名思义,“物理信道”就是直接使用某种【物理介质】来传送信息;至于“逻辑信道”,是基于“物理信道”之上抽象出来。

    信道的带宽

    带宽指的是:某个信道在单位时间内最大能传输多少比特的信息。
    电气领域 & 计算机领域都有“带宽”这个概念,但两者的定义不太一样。电气领域所说的“带宽”指的是“模拟带宽”,单位是“赫兹 / Hz”;计算机领域所说的“带宽”指“数字带宽”,单位是“比特率”或“字节率”。

    带宽的单位

    “比特率”或“字节率”很容易搞混淆。用英文表示:大写字母 B 表示【字节】;小写字母 b 表示【比特】。由于带宽的数字通常很大,要引入“K、M、G”之类的字母表示数量级,于是又引出一个差异:“10进制”与“2进制”的差异。
    【10进制】的 K 表示 1000;M 表示 1000×1000(1百万)
    【2进制】的 K 表示 1024(2的10次方);M 表示 1024×1024(2的20次方)
    为了避免扯皮,后来国际上约定了一个规矩:对【2进制】的数量级要加一个小写字母 i。比如说:Ki 表示 1024;Mi 表示 1024×1024 …… 以此类推。
    举例:
    1Kbps 表示“1000比特每秒”
    1KiBps 表示“1024字节每秒”

    信道的工作模式:单工 VS 半双工 VS 全双工

    再来说说信道的工作模式。大致可以分为如下三种:

    • 单工(simplex)
      比如“电台广播”就是典型的【单工】。“电台”可以发信号给“收音机”,但“收音机”【不能】发信号给“电台”。
    • 半双工(half-duplex)
      比如“单条铁路轨道”,就是典型的【半双工】。火车在单条铁轨上,可以有两种运行方向;但对于同一个瞬间,只能选其中一个方向(否则就撞车了)。
    • 全双工(full-duplex)
      比如“光纤”就是典型的【全双工】。在同一根光导纤维中,可以有多个光束【同时相向】传播,互相不会干扰对方。

    端点

    为了叙述方便,把参与通讯的对象(主体)称作“通讯端点”,简称“端点”。这里的“端点”是广义的,可以是硬件(比如某个网卡),也可以是软件(比如某个应用程序)。

    单播、组播/多播、广播、选播

    对于“网络通讯”,至少得有 N 个端点参与,并且【N ≥ 2】才有意义。当 N 个端点构成一个网络,这时候就会涉及到“单播、组播、广播”这几个概念。

    • 单播(unicast):发送给网络中的指定的【单个】端点
    • 组播/多播(multicast):发送给网络中的指定的【多个】端点
    • 广播(broadcast):发送给网络中的【所有】端点
    • 选播(anycast):发送给网络中随机选择的【单个】端点

    通讯协议(protocol)

    所谓的“通讯协议”就是:参与通讯的各方所采用的某种【约定】。只有大家都遵守这个约定,才有可能相互传递信息。例如:两个人要用自然语言交流,前提是:双方使用相同(或相互兼容)的自然语言。“通讯协议”就类似某种自然语言,参与通讯的多个端点,都必须能理解这个语言。

    从“分层”到“参考模型”

    分层

    在聊“分层”之前,先说说“分工”。例如在一个公司中,通常设有不同的工种/岗位,这就【分工】。对于网络通讯也是如此,不太可能用一种通讯协议完成所有的信息传递任务(注:对于特别简单的网络,或许有可能只用单一协议;但如今的网络通讯已经很复杂,用【单个】通讯协议包办所有事情,已经不太可能)一旦采用了多种通讯协议,这几种协议之间,该如何配合?

    在网络通讯领域,采用的是【分层】的设计思路。多个层次的协议在一起协同工作,技术上称作“协议栈”(Protocol Stack)。

    协议栈的原理

    对于多层次的协议栈。每个层次都有各自的“端点”(进行通讯的主体)。处于【同一层次】的两个端点会使用该层次的协议进行通讯(注:同一个层次的协议,可能只有一个,也可能有多个)。

    除了最顶层,每个层次的端点会向其【直接】上层提供“服务”;除了最底层,每个层次的端点会调用【直接】下层提供的“服务”(“服务”指某种“编程接口”)

    协议栈示意图
    服务与协议之间的关系

    逻辑信道

    每个层次会向上一个层次提供服务(API 调用)。对上层而言,调用下层提供的 API 发送信息,其效果相当于在使用某种【信道】进行通讯,这也就是“逻辑信道”。

    逻辑信道示意图

    数据格式的原理

    大部分协议会把要传送的数据切割为 N 份,每一份就是一个数据包。通常来说,数据包的格式有如下三部分:

    • 头部
    • 身体(也称作“有效载荷”)
    • 尾部(注:很多协议没有尾部)

    可以把“网络数据包”与“快递包裹”作一个对照:数据包的“头/尾”,就类似于快递包裹的【包装袋】。数据包的“身体”,就类似于快递包裹里面的东西。

    对于【相邻】两层的协议,【下】层包含【上】层。也就是说:下层协议的【载荷】就是上层协议的【整体】,举例:

    假设你从网上买了一台笔记本电脑。电脑出厂时,电脑厂商肯定会提供一个包装盒。快递公司在寄送这台笔记本的时候,又会在笔记本的盒子外面再加一个包装袋。对应到网络协议——“快递公司的包装袋”相当于【下层】协议;“电脑厂商的包装盒”,相当于【上层】协议。

    上下层协议的格式及包含关系

    网络分层的参考模型

    上述所说的“分层 & 协议栈”只是一个抽象的(笼统的)思路。具体要分几层?每一层要做什么?这些都是很有讲究,网络技术发展了几十年,已经有很多大神提出了各种不同的划分方案,称之为“网络分层的参考模型”(以下简称“模型”)。

    在各种模型中,名气最大的当然是“OSI 模型”(OSI model)。在后续的章节中,会以这个模型为主体,进行介绍。

    除了“OSI 模型”还有一个很出名的模型是“TCP/IP 模型”。

    对“TCP/IP 模型”的分层,不同的文章或书籍,说法不太一样(“3层、4层、5层”皆有),这就引发了一些争议。表达不同意见。为了避免一家之言,贴出维基百科相关链接,其中给出了几种比较有名的说法。

    OSI 概述

    OSI 的历史

    “OSI”的全称是“Open System Interconnection”。先说说它的历史。

    上世纪70年代,“国际电信联盟”(ITU)想对各国的电信系统(电话/电报)建立标准化的规格;与此同时,“国际标准化组织”(ISO)想要建立某种统一的标准,使得不同公司制造的大型主机可以相互联网。后来,这两个国际组织意识到:“电信系统互联”与“电脑主机互联”的性质差不多。于是 ISO 与 ITU 就决定合作,两家一起干。这2个组织的2套班子,从上世纪70年代开始搞,搞来搞去,搞了很多年,一直到1984年才终于正式发布 OSI 标准。

    OSI 标准的两个组成部分

    严格来讲,OSI 包括两大部分

    • 1. 抽象的概念模型,也就是前面提到的【OSI model】。
    • 2. 针对这个概念模型的具体的通讯协议【OSI protocols】。

    OSI 是由 ISO & ITU 联手搞出来。这两个国际组织里面的人,要么是来自各国的电信部门,要么是来自各国的高校学者。总而言之,既有严重的官僚风气,又有明显的学究风气,正是因为这两种风气叠加,所以搞了很多年,才搞出 OSI。
    OSI 的协议实现(OSI protocols),不客气地说,就是一堆垃圾——据说把 OSI protocols 所有的协议文档,全部打印成 A4 纸,摞起来得有一米多高!是不是很吓人?协议搞得如此复杂,严重违背了 IT 设计领域的 KISS 原则
    由于 OSI protocols 实在太复杂,后来基本没人用。但 OSI model 反而广为流传,并且成为“网络分层模型”中名气最大,影响力最广的一个。
    因此,本文后续章节中,凡是提到 OSI,指的是【OSI model】。

    OSI 模型的7层

    OSI 模型总共分7层,示意图参见如下表格:

    层次中文名洋文名
    第7层应用层Application Layer
    第6层表示层Presentation Layer
    第5层会话层Session Layer
    第4层传输层Transport Layer
    第3层网络层Network Layer
    第2层数据链路层Data Link Layer
    第1层物理层Physical Layer

    (注:在后续章节把“数据链路层”简称为“链路层”)

    物理层:概述

    物理层的必要性

    物里层直接与物理介质打交道的层次,这一层的必要性比较明显。

    因为所有的通讯,归根结底都要依赖于【物理介质】。与物理介质打交道,需要牵涉到很多与【物理学】相关的内容。比如:“无线电通讯”需要关心“频率/波长”;电缆通讯需要跟“电压”打交道;“光纤通讯”需要关心“玻璃的折射率&光线的入射角” 等。
    “物理层”的主要职责是:屏蔽这些细节,使得“物理层”之上的层次不用再去操心物理学。

    物理信道的类型

    对于“物理信道”,可以进一步细分为如下三大类:

    1. 有线信道(比如:双绞线、同轴电缆、光纤、等等)
    2. 无线信道(比如:微波通讯、电台广播、卫星通讯、等等)
    3. 存储信道

    存储信道比较少见,稍微解释一下:假设你要把一堆信息传送给另一个人,除了用“有线 or 无线”这两种通讯方式,还可以把信息先保存到某种【存储介质】(比如硬盘),然后再把存储介质用某种方式(比如快递)转交给对方。这就是所谓的“存储信道”。

    信噪比(Signal-to-noise ratio)

    对于“物理信道”,总是会存在某些环境干扰,称之为“噪声”(Noise)。“信道传输的有用信息”与“无用的干扰噪声”,这两者的比值就是“信噪比”。

    “信噪比”单位是【分贝】(decibel,简称dB)。“deci”表示“十进制”;“bel”是为了纪念大名鼎鼎的贝尔(电话发明者)。

    带宽的限制因素

    “物理信道”要依赖于物理传输介质。不管使用何种物理介质,都要受限于某些基本的物理学定律(比如“光速上限”)。另外,不管何种物理介质,总是会有或多或少的环境干扰(噪声)。这两个因素导致了:任何“物理信道”的最大传输率总是有限的。

    由于物理层是最底下的一层,物理层之上的其它层次总是要直接或间接地依赖【物理信道】。因此,其它层次建立的“逻辑信道”,其带宽只会比“物理信道”的最大带宽更小。“物理信道”的带宽上限也就是整个协议栈的带宽上限。

    多路复用(Multiplexing)

    通常情况,凡是能实现【长距离】通讯的“物理信道”,都有相当的经济成本。比如铺设“光纤、同轴电缆”都要花钱。无线电通讯虽然免去了铺设线路的成本,但需要竞标购买频段。因此,物理信道非常强调“多路复用”。

    所谓“多路复用”,就是尽可能地共享物理信道。“多路复用”有很多种类型;不同的类型,原理也不同。为了展示各种不同的原理,拿【无线通信】来举例。

    无线通信领域的“多路复用”,【至少】有如下几种:

    频分多路复用/FDM(Frequency-Division Multiplexing)

    根据频率拆分。不同的线路占用不同的频段,互不干扰。(电台广播用的就是这个思路)但缺点很明显:

    1. 要依赖足够宽的频段(频段是稀缺资源);
    2. 不同线路的流量可能会动态变化。如果某个线路空闲,其占用的频段就浪费了。(注:光纤通讯中有个“波分多路复用/WDM”,本质上就是 FDM)

    时分多路复用/TDM(Time-Division Multiplexing)

    只用一个很窄的频段。为了在同一个频道发送多个信道,采用【分时机制】,把时间切割成很小的时间片,每个线路占用一个时间片,周而往复。像十字路口的红绿灯——每隔一段时间,其中一条路可以通行。

    • 优点:可以只使用一个很窄的频段。
    • 缺点:线路越多,每条线路等待越久;即使某个线路空闲,依然会占用时间片(浪费了资源)。

    码分多路复用/CDM(Code-Division Multiplexing)

    采用某种【编码】的技巧,使得多个端点可以在同一个时间点使用同一频段发送数据;由于他们采用不同的编码方式,不会相互干扰。一般来说,CDM 要依赖于“扩频技术”(spread spectrum),需占用一个比较宽的频道范围。这算是缺点。

    但其优点很明显:

    1. 可以支持 N 个线路(N 动态变化);
    2. 即使任何一个线路的流量动态变化,也不会浪费物理信道的资源。

    显然,这种思路明显优于 FDM & TDM。如今在移动通讯领域大名鼎鼎的 CDMA(码分多址),采用的就是这个思路。

    物理层:具体实例

    物理层的【协议】

    物理层的协议主要有如下:

    物理层的【协议实现】

    对于电脑主机(含移动设备),“网卡硬件”包含了物理层的协议实现(如下图)另外,还有一些专门的【1层】网络设备,也提供物理层的功能。

    OSI 模型中不同层次的协议实现

    物理层相关的【网络设备】

    调制解调器(modem)
    “调制解调器”用来翻译“数字信号 & 模拟信号”。在发送信息时,modem 把电脑要发送的“字节流”(数字信号)翻译成“模拟信号”,然后通过物理介质发送出去;当它从物理介质收到“模拟信号”,再翻译成“数字信号”,传回给电脑。

    早期的拨号上网,modem 面对的物理介质是“固话线路”;如今家庭宽带普及,光纤入户,modem 面对的物理介质是“光纤线路”。

    老式 modem,用于固定电话线路

    中继器(repeater)
    信号在物理介质中传输,会出现【衰减】(不论是“有线 or 无线”都有可能衰减)。“中继器”的作用是【信号增益】,使得信号能传得更远。另外,比如“微波通讯”是直线传播,而地球表面有弧度,还有地形的起伏。所以每隔一定距离要建“微波塔”,也相当于“中继器”。

    微波塔

    集线器(hub)
    可以把“集线器”视作更高级的“中继器”——“中继器”只有两个口(只能连接两个通讯端点),而“集线器”有多个口(同时连接多个通讯端点)。通常所说的“集线器”是指“以太网集线器”。这种设备如今已经逐步淘汰,很少见到。

    老式10兆以太网集线器

    另外,“USB hub”就是针对 USB 线的“集线器”(“USB 线”也可以视作某种通讯介质)。

    链路层:概述

    链路层的必要性

    对信息的打包

    物理层传输的信息,通俗地说就是【比特流】(也就是一长串比特)。但是对于计算机来说,“比特流”太低级,处理起来极不方便。“链路层”要干的第一个事情,就是把“比特流”打包成更大的包,以方便更上层的协议进行处理。在 OSI 模型中,链路层的一个数据包,称之为“帧”(frame)。

    差错控制

    物理介质的传输,可能受到环境的影响。这种影响不仅仅体现为“噪声”,有时候会出现严重的干扰,导致物理层传输的“比特流”出错(某个比特“从0变1”或“从1变0”)。因此,链路层还需要负责检查物理层的传输是否出错。在 技术行话中,检测是否出错,称之为“差错控制机制”。

    流量控制

    假设两个端点通过同一个物理信道进行通讯,这两个端点处理信息的速度可能不同。如果发送方输出信息的速度超过接收方处理信息的速度,通讯就会出问题。于是就需要有某种机制来协调,确保发送方的发送速度不会超出接收方的处理速度。在技术行话中,这称之为“流量控制”,简称“流控”。

    信道复用

    在上一个章节已经讲到:用于远距离通讯的“物理介质”,总是有成本。因此需要对物理信道进行“多路复用”,就会导致多个端点共用同一个物理信道。如果同时存在多个发送者和多个接收者。接收者如何知道某个信息是发给自己而不是别人?

    另外,某些物理介质可能不支持并发。某些物理介质可能是【半双工】,所有这些物理层的限制,都使得“多路复用”变得复杂。为了解决这些问题,链路层需要提供了某种相应的机制(协议),术语叫做“介质访问控制”(“Media Access Control”,简称 MAC)。

    差错控制

    为了发现传输的信息是否出错,设计了很多相应的数学算法。这些算法大体分为两类:“检错算法 & 纠错算法”。

    简而言之,“检错算法”只能检测出错误,而“纠错算法”不但能检测出错误,还能纠正错误。很显然,“纠错算法”更牛逼,但是它也更复杂。

    常见的“检错算法”对传输的数据计算出一个【校验值】,接收方收到数据会重新计算校验和,如果算出来不对,就把收到的数据丢弃,让对方重发。“校验算法”的原理类似于“散列算法/哈希算法”。“纠错算法”更高级,由于涉及到更多数学,就不一一展开。

    对于【无线】物理信道,由于出错的概率更高,并且重新传输数据的成本也更高。所以【无线】通讯的链路层协议,更倾向于用【纠错】机制;作为对比,【有线】通讯的链路层协议,更倾向于用【检错】机制。

    MAC 协议

    “MAC 协议”用来确保对下层物理介质的使用,不会出现冲突。拿“铁路系统”比喻:

    假设有一条【单轨】铁路连接 A/B 两地。有很多火车想从 A 开到 B,同时还有很多火车想从 B 开到 A。首先,要确保不发生撞车(如果已经有车在 A 开往 B 的途中,那么 B 就不能再发车);其次,即使是同一个方向的车,出发时间也要错开一个时间间隔。所有这些协调工作,都是靠“MAC 协议”来处理。

    MAC 地址

    为了完成上述任务,光有“MAC 协议”还不够,还需要为每一个端点引入【唯一的】标识。这个标识就称作“MAC 地址”。

    每个网卡都内置了一个“MAC 地址”。这个地址是网卡在出厂的时候就已经设置好,并且用某种机制确保该地址【全球唯一】。

    如何保证 MAC 地址全球唯一?MAC 地址包含6个字节(48个比特),分为两半。第一部分称作【OUI】,OUI 的24个比特中,其中2个比特有特殊含义,其它22个比特,用来作为网卡厂商的唯一编号。这个编号由国际组织 IEEE 统一分配。MAC 地址第二部分的24比特,由网卡厂商自己决定如何分配。每个厂商只要确保自己生产的网卡,后面这24比特是唯一的就可以。

    MAC 地址的构成

    顺便说说【虚拟网卡】的 MAC 地址:

    “虚拟网卡”是由【虚拟化软件】创建滴。IEEE 也给每个虚拟化软件的厂商(含开源社区)分配了唯一的 OUI。因此,虚拟化软件在创建“虚拟网卡”时,会使用自己的 OUI 生成前面24个比特;后面的24比特,会采用某种算法使之尽可能【随机化】。由于“2的24次方”很大(224 = 16777216),碰巧一样的概率很低。

    (注:如果手工修改 MAC 地址,故意把两块网卡的 MAC 地址搞成一样,那确实就做不到唯一性。并且会导致链路层的通讯出问题)

    链路层:具体实例

    链路层的【协议】

    链路层的协议主要有如下:

    链路层的【协议实现】

    对于电脑主机(含移动设备),“网卡硬件 & 网卡驱动”会包含链路层协议的实现(如下图)。另外,还有一些专门的【2层】网络设备,也提供链路层的功能。

    OSI 模型中,不同层次的协议实现

    链路层相关的【网络设备】

    网络交换机(network switch)

    (注:一般提到“网络交换机”,如果不加定语,指的就是“2层交换机”;此外还有更高层的交换机,在后续章节介绍)

    为啥要有交换机?以太网刚诞生的时候,称之为“经典以太网”,电脑是通过【集线器】相连。“集线器”前面提到过,工作在【1层】(物理层),并不理解链路层的协议。因此,集线器的原理是【广播】模式——它从某个网线接口收到的数据,会复制 N 份,发送到其它【每个】网线接口。假设有4台电脑(A、B、C、D)都连在集线器上,A 发数据给 B,其实 C & D 也都收到 A 发出的数据。显然,这种工作模式很傻逼(低效)。由于“经典以太网”的工作模式才“10兆”,所以集线器虽然低效,还能忍受。

    后来要发展“百兆以太网”,再用这种广播模式,就过于低效。于是“经典以太网”就发展为“交换式以太网”。用【交换机】代替“集线器”。

    交换机是工作在2层(链路层)的设备,能够理解链路层协议。当交换机从某个网线接口收到一份数据(链路层的“帧”),它可以识别出“链路帧”里面包含的目标地址(接收方的 MAC 地址),然后只把这份数据转发给“目标 MAC 地址相关的网线接口”。

    由于交换机能识别2层协议,它不止比集线器的性能高,而且功能也强得多。比如高级一些的交换机可以实现“MAC 地址过滤、VLAN、QoS”等多种额外功能。

    网桥/桥接器(network bridge)

    “交换机”通常用来连接【同一种】网络的设备。有时候,需要让两台不同网络类型的电脑相连,就会用到【网桥】。

    下面以“操作系统虚拟机”来举例:

    虚拟机的几种“网卡模式”中,有一种模式叫做【bridge 模式】。一旦设置了这种模式,Guest OS 的虚拟网卡,对于 Host OS 所在的外部网络,是【双向】可见的。也就是说,物理主机所在的外部网络,也可以看见这块虚拟网卡。

    假设物理电脑(Host OS)只安装了【无线网卡】(WiFi),而虚拟化软件给 Guest OS 配置的通常是【以太网卡】。显然,这是两种【不同】的网络。为何 Guest OS 的以太网卡设置为“bridge 模式”之后,外部 WiFi 网络可以看到它?

    奥妙在于虚拟化软件在内部悄悄地实现了一个“网桥”。这个网桥把“Host OS 的 WiFi 网卡”与“Guest OS 的以太网卡”关联起来。WiFi 网卡收到了链路层数据之后,如果接收方的 MAC 地址对应的是 Guest OS,网桥会把这份数据丢给 Guest OS 的网卡。

    这种网卡模式之所以称作“bridge 模式”。

    链路层相关的【软件工具】

    嗅探抓包工具(Sniffer)

    要了解链路层的数据包结构,需要用到“嗅探工具”。这类工具能捕获流经你网卡的所有【链路层】数据包。前面聊“协议栈”的时候说过:下层数据包的载荷就是上层数据包的整体。因此,拿到【链路层】数据包也就意味着:已经拿到2层之上的所有数据包的信息。

    有些抓包工具自带图形界面,可以直接显示数据包的内容给你看。还有些只提供命令行(只是把获取的数据包保存为文件),然后要搭配其它图形化的工具来展示数据包的内容。

    抓包的工具有很多,名气最大的是 Wireshark(原先叫做 Ethereal)。

    ARP 命令

    ARP 是“MAC 地址解析协议”的英文简称。该协议根据“IP 地址”解析“MAC 地址”。

    Windows 自带一个同名的 arp 命令,可以用来诊断与“MAC 地址”相关的信息。比如:列出当前子网中其它主机的 IP 地址以及对应的 MAC 地址。这个命令在 Linux & Mac OS 上也有。

    网络层:概述

    网络层的必要性

    路由机制(routing)

    在 OSI 模型中,链路层本身不提供路由功能。可以通俗地理解为:链路层只处理【直接相连】的两个端点(注:这么说不完全严谨,只是帮助新手理解)

    对于某个复杂网络,可能有很多端点,有很复杂的拓扑结构。当拓扑足够复杂,总有一些端点之间【没有直连】。那么,如何在这些【没有直连】的端点之间建立通讯?此时就需要提供某种机制,让其它端点帮忙转发数据。这就需要引入“路由机制”。

    为了避免把“链路层”设讲得太复杂,路由机制放到“链路层”之上来实现,也就是“网络层”。

    基于【路由】的地址编码方式

    链路层已经提供了某种全球唯一的地址编码方式(MAC 地址)。但“MAC 地址”有如下几个问题:

    1. 它是固定的(虽然可以用技术手段去修改 MAC 地址,但很少这么干)
    2. MAC 地址的编码是基于【厂商】,无法体现网络拓扑结构。或者说,“MAC 地址”对于“路由机制”是不够友好。

    因此,需要引入一种更抽象(更高层)的地址,也就是“网络层地址”。我们常说的“IP 地址”是“网络层地址”的实现方式之一,举个例子:

    每个人都有身份证号(这就类似于“MAC 地址”)。当某人加入了某个公司,公司会为此人再分配一个“员工号”(这就类似于“网络地址”)。既然有身份证号,为啥公司还要另搞一套“员工编号”捏?因为“员工编号”有额外的好处。比如说:可以把员工号划分为不同的区间,对应不同的部门。这样一来,只要看到员工号,就知道此人来自哪个部门。

    类似道理,每个网卡都有自己固定的 MAC 地址,当这个网卡接入到不同的网络,每次都可以再分配不同的“网络地址”。通过“网络地址”可以看出这个网卡属于哪个网络(对路由比较方便)。

    网际互联(internetwork

    引入“网络层”的另一个目的是:屏蔽不同类型的网络之间的差异,从而有利于【网际互联】(也就是建立“网络的网络”)。

    一般来说,要想联通【异种】网络,就要求每个网络中都有一台主机充当【网关】(gateway)。网关起到“中介/翻译”的作用——帮不同的网络翻译协议,使得不同的网络可以互相联通。假设没有统一的网络层,网关的工作就很难做。就好比说:如果全球没有某种通用的自然语言,就需要培养非常多不同类型的翻译人才(假设有30种主要语言,任意两种互译,就需要几百种不同的翻译人才)。

    反之,如果有了某种统一的网络层标准,问题就好办许多(还是假设有30种主要语言,只要选定某种作为通用语,然后培养29种翻译人才,就可以实现任意两种语言互译)。如今的互联网时代,【IP 协议】就是那个充当统一标准的网络层协议。

    互联网整合了各种类型的网络

    网络拓扑(network topology)

    网络的拓扑结构有很多种,有简单的,有复杂的。一般来说,再复杂的拓扑,也可以逐步分解为若干简单拓扑的组合。

    常见的网状拓扑结构:星形拓扑、环形拓扑、总线拓扑、网状拓扑等

    如今的互联网,整体的拓扑结构超级复杂。但还是可以逐步分解为上述几种基本的拓扑结构。

    互联网的复杂拓扑,右下角是图中某个小点的放大。点这里看原始图

    互联网的拓扑——从“历史”的角度看其健壮性

    从上面那张图可以看出:互联网拓扑的【局部】有很多是“星形拓扑”(当然也有其它)。但从【宏观】上看,更像是“网状拓扑”。在现实生活中,对于复杂结构,通常都会采用“树状层次结构”,以便于管理。比如:域名系统、公司组织结构等,那为何互联网的【宏观】拓扑结构是“网状”的?这就要说到互联网的历史。

    在上世纪50年代(冷战高峰期),美国军方的指挥系统高度依赖于电信公司提供的电话网络。当时的电话网络大致如下:

    在基层,每个地区有电话交换局,每一部电话都连入当地的交换局。
    在全国,设有若干个长途局,每个交换局都接入某个特定的长途局(不同地区的交换局通过长途局中转)。

    简而言之,当时美国的电话网络是典型的【多级星形拓扑】。这种拓扑的优点是:简单、高效、便于管理;但缺点是:健壮性很差。从这个案例中,大伙儿可以再次体会到“效率”与“健壮性”之间的矛盾。

    话说1957年的时候,苏联成功试射第一颗洲际弹道导弹(ICBM),美国军方开始担心:一旦苏联先用洲际导弹攻击美国,只要把少数几个长途局轰掉,军方的指挥系统就会瘫痪。也就是说,“长途局”已经成为美国军方的【单点故障】。

    1960年,美国国防部找来大名鼎鼎的兰德公司进行咨询,要求提供一个应对核打击的方案。该公司的研究员 Paul Baran 设计了一个方案,把“星形拓扑”改为【网状拓扑】。采用【网状拓扑】的好处在于:即使发生全面核大战,大量骨干节点被摧毁,整个网络也不会被分隔成几个孤岛,军方的指挥系统依然能正常运作。

    左边:互联网诞生前——美国的电话网络  右边:兰德公司的“Baran 方案”

    有了兰德公司的方案,美国军方找到当时最大的电信公司 AT&T,想要实现这个系统,结果被否决了。AT&T 高层认为:搞这样一种系统根本不切实际。于是 Baran 的方案中途夭折。

    为何 AT&T 反对这个方案呢?一方面,成功的大公司总是有很强的思维定势,另一方面,Baran 的设计方案确实很超前——其前瞻性不仅包括“拓扑结构”,而且把当时电信行业的几大核心观念完全颠覆掉了。

    时间一晃又过了好多年,到了60年代末,由于一系列机缘巧合,英国佬发现了“Baran 方案”的价值,并据此搞了一个小型的 NPL 网络(NPL 是“国家物理实验室”的缩写)。然后在某次 ACM 会议上,美国佬看到英国佬的论文,才意识到:Baran 方案完全可行。经历了“出口转内销”的命运之后,该方案重新被美国国防部重视。之后,(国防部下属的)“高级计划研究局”(ARPA)开始筹建“阿帕网”(ARPANET),才有了如今的互联网。

    路由的大致原理

    聊完“拓扑”,再来聊“路由”。

    当主机 A 向主机 B 发送网络层的数据时,大致会经历如下步骤:

    1. A 主机的协议栈先判断“A B 两个地址”是否在同一个子网,如果是同一个子网,直接发给对方;如果不是同一个子网,发给本子网的【默认网关】。(此处所说的“网关”指“3层网关/网络层网关”)
    2. 对于“默认网关”,有可能自己就是路由器;也可能自己不是路由器,但与其它路由器相连。也就是说,“默认网关”要么自己对数据包进行路由,要么丢给能进行路由的另一台设备。(万一找不到能路由的设备,这个数据就被丢弃,于是网络通讯出错)
    3. 当数据到达某个路由器之后,有如下几种可能
      1. 该路由器正好是 B 所在子网的网关(与 B 直连),那就把数据包丢给 B,路由过程就结束。
      2. 或者,路由器会把数据包丢给另一个路由器(另一个路由器再丢给另一个路由器) …… 如此循环往复,最终到达目的地 B。
      3. 还存在一种可能性:始终找不到“主机 B”(有可能该主机“断线 or 关机 or 根本不存在”)。为了避免数据包长时间在网络上闲逛,还需要引入某种【数据包存活机制】(“Time To Live”,简称 TTL)。通常会采用某个整数(TTL 计数)表示数据包能活多久。当主机 A 发出这个数据包的时候,这个“TTL 计数”就已经设置好了。每当这个数据包被路由器转发一次,“TTL 记数”就减一。当 TTL 变为零,这个数据包就被丢弃。

    对于某些大型的复杂网络(比如互联网),每个路由器可能与其它 N 个路由器相连(N 可能很大)。对于上述的 3.2 情形,它如何判断:该转发给谁?这时候,“路由算法”就体现出价值:

    一般来说,路由器内部会维护一张【路由表】。每当收到一个网络层的数据包,先取出数据包中的【目标地址】,然后去查这张路由表,看谁距离目标最近,就把数据包转发给谁。

    上面这段话看起来好像很简单,其实路由算法挺复杂。对此感兴趣的同学,可以去看《计算机网络》的第5章。

    路由算法的演变史(以互联网为例)

    由于互联网的 IP 协议已经成为“网络层协议”的事实标准,简单聊一下互联网的路由机制是如何进化。

    第1阶段:静态全局路由表

    互联网的前身是“阿帕网/ARPANET”。在阿帕网诞生初期(上世纪70年代),全球的主机很少。因此,早期的路由表很简单,既是“全局”,又是“静态”。简而言之,每个路由器内部都维护一张“全局路由表”,这个“路由表”包含了全球所有其它路由器的关联信息。每当来了一个数据包,查一下这张全局路由表,自然就清楚要转发给谁,才能最快到达目的地。

    早期的阿帕网,主机的变化比较少,也很少增加路由器。每当出现一个新的路由器,其它路由器的管理员就手工编辑各自的“全局路由表”。

    为了加深印象,找来两张70年代初的阿帕网拓扑图(注:图中的 IMP 是“Interface Message Processor”的缩写,也就是如今所说的“路由器”)。

    1973年的阿帕网
    1973年的阿帕网

    第2阶段:动态全局路由表

    后来,“阿帕网/互联网”的规模猛增,路由器数量也跟着猛增,隔三差五都有新的路由器冒出来。再用“静态路由表”这种机制,(编辑路由表的)管理员会被活活累死。于是改用“动态路由表”,并引入某种“路由发现机制”。但“路由表”依然是【全局】。

    第3阶段:动态分级路由表

    再到后来,全球的路由器越来越多,成千上万,再搞“全局路由表”已经不太现实了,一方面,“全局路由表”越来越大(查询的速度就越来越慢),另一方面,由于互联网的流量越来越大,每来一个数据包都要查表,查询越来越频繁。

    于是,路由器开始吃不消。为了解决困境,想出一个新招数:引入“分级路由”(hierarchical routing)。所谓的“分级路由”就是:把整个互联网分为多个大区域,每个大区域内部再分小区域,小区域内部再分小小区域 …… 看到这里,熟悉“数据结构与算法”的同学就会意识到——这相当于构造了一个【树状】层次结构。

    有了这个层次结构,每个路由器重点关注:自己所在的那个最小化区域里面的网络拓扑。如此一来,每个路由器的“路由表”都会大幅度减小。

    全局路由表 VS 分级路由表

    互联网的路由——从“CAS”的角度看其健壮性

    互联网的路由机制,其实是一个典型的 CAS:

    如果把互联网视作一个系统,每个公网上的路由器都是一个自适应的主体。假如某个地区的网络流量突然暴涨,骨干网路由器会自动分流;假如因为地震或战争,导致某个地区的骨干网路由器全部下线,周边地区的路由器也会自动避开这个区域。所有这些工作,不需要依靠任何指挥中枢去进行协调。  

    网络层的两种交换技术——电路交换(circuit switching) VS 分组交换(packet switching

    前面聊“互联网诞生”,说到兰德公司的“Baran 方案”。该方案对当时的电信系统提出几大革命性的变化,其中之一就是“分组交换”技术(也称“数据包交换”or“封包交换”)。

    一般来说,网络层的设计有两种截然不同的风格:【电路交换 VS 分组交换】。有时候也分别称之为“有连接的网络层 VS 无连接的网络层”。此处所说的“连接”指的是某种“虚电路”(“virtual circuit”,简称 VC)

    要理解“虚电路”,首先要从老式的电话系统说起:

    最早期的电话,既没有拨号盘也没有按键,全靠一张嘴。当你拿起电话,先告诉接线员你要打给谁,接线员会用一根跳接线,插入电话交换设备的某个插孔,从而把你的电话机与对方的电话机相连。于是建立了一条两人之间的电话通路,也就是“电路”。你可以把“接线员”想象成某种“人肉路由器” 。

    1900年法国巴黎的电话交换局,可以看到接线员在操作电话交换设备

    后来发明了“自动电话交换机”,导致“接线员”全体下岗。虽然自动化了,但原理还是一样:当你在电话上拨了某人的号码,电话局的交换机会自动选择一条线路。只有当这条线路建立起来,对方的电话才会响。一旦双方开始通话,双方之间的语音都是通过这条线路传输。并且这条线路是独占的,只要通话不挂断,这条线路就不会再分配给其他人使用。

    前面提到“互联网诞生的历史”,当时军方推动的“Baran 方案”被 AT&T 断然拒绝。因为这个方案完全颠覆了传统的电话系统:

    1. 把“模拟信号”颠覆为“数字信号”
    2. 把“星形拓扑”颠覆为“网状拓扑”
    3. 把“电路交换”颠覆为“分组交换”

    为了理解第3点,举个例子:

    假设主机 A 要向主机 B 发送一堆数据。因为数据太多,肯定要分成多个数据包。如何把这些数据包发送给对方?

    “电路交换”的实现方式

    在发送数据之前,要先建立连接通道(通过路由算法,找出 A & B 之间的某条通路)。这条通路就是所谓的“虚电路/VC”。一旦 VC 建立,每一个数据包都是从这条拓扑路径进行路由。

    “分组交换”的实现方式

    在发送数据之前,【不需要】建立通道,让每个数据包独立进行路由。这种情况下,这几个数据包可能会走【不同的】拓扑路径。因此,数据包到达的顺序与发送的顺序【不一定】相同。接收方收到所有数据包之后,还要自己进行排序。

    维基百科上有一个 GIF 动画(链接),比较直观地演示“分组交换/封包交换”的效果。

    当时的电话系统主要承载语音传输,“电路交换”显然性能更高。那为啥 Baran 的设计要采用“分组交换”

    对于“电路交换”,一旦建立连接,同一个连接的所有数据都走相同的路径(会经过完全相同的路由器)。也就是说,传输的过程中,如果某个路由器挂掉了(网络掉线 or 硬件当机 or 软件崩溃)。那么,该路由器正在处理的 N 个连接全都要报废。而“分组交换”则更加灵活——即使某个路由器挂掉,后续的数据包会自动转向另外的路由器,损失很小。

    “Baran 方案”之所以采用“分组交换”的设计,因为这个方案是提交给军方用来应对【全面核战争】滴,当然要考虑健壮性。

    话说这两种交换机制,各有很多支持者,并分裂为两大阵营,分别是:“电信阵营 VS 互联网阵营”。两大阵营的争执持续了 N 年,都无法说服对方。到了后来设计 OSI 模型的时候,为了保持中立性与通用性,OSI 模型本身并没有强制要求网络层采用哪一种风格。

    经过几十年之后,咱们已经可以看出来:“互联网阵营”占据主导地位。如今,连电信系统都是架构在互联网之上。

    网络层:具体实例

    网络层的【协议】

    网络层的协议有很多。由于“互联网”已经成为全球的事实标准,因此只列出属于互联网协议族的网络层协议:

    对上述这些协议,最重要的当然是 IP 协议。如果你想要深入了解 IP 协议,可以参考《TCP-IP 详解》。关于 IP 协议的书,此书的影响力最大。这本书共3卷,通常只需看第1卷。

    网络层的【协议实现】

    对于电脑主机(含移动设备),网络层的协议实现通常包含在操作系统自带的网络模块中(也就是“操作系统协议栈”)。具体参见如下示意图。另外,还有一些专门的【3层】网络设备,也提供网络层的功能。

    OSI 模型中不同层次的协议实现

    IP 地址的格式及含义

    当年设计阿帕网的时候,采用了【4字节】(32比特)来表示“网络层地址”(也就是 IP 地址)。“IP 地址”的含义很重要,有必要解释一下:

    我们平时所说的 IP 地址,采用【点分十进制】来表示。就是把地址的4个字节,先翻译为十进制,然后每个字节用一个小数点分隔开(参见如下示意图):

    4字节 IP 地址:“二进制”与“点分十进制”的对照示意图

    “IP 地址”的32比特,分为两部分:

    • 第1部分用来标识【子网】
    • 第2部分用来标识该子网中的【主机】。

    这两部分各占用多少比特,是不确定的。在这种情况下,“操作系统协议栈”如何知道哪些比特标识“子网”,哪些比特标识“主机”?奥妙在于【子网掩码】。所以,在给系统配置 IP 地址的时候,通常都需要再设置一个【子网掩码】,就这个用途。

    IP 地址枯竭,及其解决方法

    前一个小节提到:IP地址包含【4字节】(32比特)。因此,最多只能表示【2的32次方】(42亿左右)的不同地址。考虑到还有很多地址保留给特殊用途,实际可用地址远远不到42亿。到了如今,全球网民都已经几十亿了,IP 地址开始枯竭。怎么办?为了解决这个问题,发展出若干技术手段。简单说一下最常见的几种手段:

    IPv6
    名气最大(最多人知道)的技术手段,大概是 IPv6 了。这招想要一劳永逸地解决地址枯竭的问题,采用了16字节(128比特)来表示 IP 地址。设计 IPv6 的人自豪地宣称:即使给地球上的每一粒沙子分配一个 IPv6 地址,依然绰绰有余(确实没有吹牛,“2的128次方”是天文数字)。

    但 IPv6 的缺点在于,【无法】向下兼容原有的 IP 协议(原有的协议叫“IPv4”)。IPv6 的普及一直比较慢,这是主要原因。

    代理服务器(proxy)

    比如,某个公司有100人,100台电脑。如果每台电脑都分配公网 IP 地址,就要消耗100个公网地址,这样就太浪费。可以只申请一个公网 IP,然后在内网搞一个代理服务器,公网 IP 分配给它(代理服务器有两个网卡,一个接内网,一个接公网)。然后在其它电脑上设置代理,指向这台代理服务器,就都可以上外网。

    网络地址转换(NAT)

    前面的 proxy 有个缺点:内网的每台电脑里面的每个上网软件,都要单独设置代理。实在太麻烦,后来就发明了某种更牛逼的招数——网络地址转换(“Network Address Translation”,简称 NAT)。

    用了NAT,还是只要申请一个公网 IP,分配给内网的网关(网关有两个网卡,一个接内网,一个接公网)。然后在内网的网关配置 NAT 功能,自动就可以让内网的每台电脑访问外网。

    采用了 NAT 技术之后,可能会对某些应用软件(尤其是 P2P 类型的)造成兼容性问题,于是又发明了一些“NAT 穿透技术”(NAT traversal)。

    其它解决方法

    关于“IPv4 地址空间耗尽”,解决方法肯定不止上面这几种。限于篇幅,就此打住。更多的讨论参见维基百科的“这个链接”。

    网络层相关的【网络设备】

    路由器(router)
    3层交换机(Layer 3 switching)

    “3层交换机”是在“2层交换机”的基础上,增加了对网络层的处理。因此,它可以做到类似路由器的效果,在几个子网之间转发数据。与路由器的差别在于:“3层交换机”链接的几个子网是【同种】网络;而路由器可以连接【异种】网络。

    从上面这句话看,“3层交换机”的能力显然不如“路由器”。既然已经有“路由器”,为啥还要发明“3层交换机”捏?这就要说到【单臂路由器】的弊端。

    对于企业内网的“2层交换机”,通常都支持 VLAN 功能。通俗地说:可以在交换机中划分多个【虚拟子网】。其实这些子网的中所有的电脑,都还是接入这台交换机,只不过这些子网配置了不同的网络地址。对于同一个 VLAN 内部的通讯,“2层交换机”自己就可以搞定(只需要用到2层协议);但对于【跨】VLAN 主机之间的通讯,“2层交换机”就无法处理(它没有路由功能)。因此,就必须在它旁边外加一个路由器,形成如下拓扑结构。在这个拓扑中,路由器只与单个设备(2层交换机)相连,所以称之为“单臂”。

    请注意:如下示意图只画了两台电脑,位于两个 VLAN。实际上可能有很多个 VLAN,每个里面有几十台电脑。于是,交换机与路由器之间的传输通道就会成为瓶颈——【跨】VLAN 的任意两台电脑通讯,数据包都要到路由器那里兜一圈。为了消除这种瓶颈,才发明了“3层交换机”——把路由功能直接集成到交换机内部。

    单臂路由器的拓扑结构

    无线热点(Wireless Access Point)

    “无线热点”通常用来提供无线接入,使得某个【无线】设备能接入到某个【有线】网络中。一般来说,热点都内置了路由功能,那么它就是“无线路由器”,对应到“3层”(网络层)。反之,如果没有路由功能,它就是“网桥”,属于“2层”(链路层)。

    网络层相关的【软件工具】

    ping

    这个命令,很多人应该都知道。早在 Win9x 就有这个命令了。它使用(网络层的)ICMP 协议来测试某个远程主机是否可达。注意:如果 ping 命令显示某个 IP 地址不可达,有很多种情况。比如说:

    • 这个 IP 地址对应的主机已经关机
    • 这个 IP 地址对应的主机已经断线
    • 这个 IP 地址对应的主机拒绝响应 ICMP 协议
    • 从本机到这个 IP 地址之间,有某个防火墙拦截了 ICMP 协议
    • ……

    traceroute

    这是一个通用的工具,用来测试路由。很早以前的 Windows 就已经内置了它,命令是 tracert。在 POSIX(Linux&UNIX)上通常叫 traceroute,可以用这个命令,测试本机与互联网另一台主机之间的路由(也就是:从本机到对方主机,要经过哪些路由器)

    传输层:概述

    传输层的必要性

    屏蔽“有连接 or 无连接”的差异

    网络层本身已经屏蔽了【异种网络】的差异(比如“以太网、ATM、帧中继”之间的差异),而且网络层也屏蔽了路由的细节。但网络层本身还有一个差异,也就是网络层的两种交换技术:电路交换(有连接) VS 分组交换(无连接)。

    上述两种交换技术各有很多支持者,并分裂为两大阵营。当年设计 OSI 模型的时候,为了保持中立性与通用性,并没有强制规定“网络层”必须采用何种交换机制。

    对于开发网络软件的程序员来说,当然不想操心“网络层用的是哪一种交换机制”。因此,需要对网络层的上述差异再加一个抽象层(也就是“传输层”)。

    从“主机”到“进程”

    前面介绍的“网络层”,其设计是面向主机(电脑)。“网络层地址”也就是某个主机的地址。而“传输层”是面向【进程】,因为传输层要提供给【网络软件】使用,而网络软件打交道的对象是【另一个网络软件】。因此,传输层必须在“网络层地址”的基础上,再引入某种新的标识,用来区分同一台主机上的不同【进程】。

    传输层的特殊性

    在 OSI 7层模型中,传输层正好居中。这是一个很特殊的位置。OSI 模型最下面3层,与【网络设备】比较密切。这里面所说的“网络设备”,既包括那些独立的主机(比如“路由器、交换机、等”),也包括电脑上的硬件(比如“网卡”)。

    OSI 模型最上面3层,与【网络软件】比较密切(或者说,与“用户的业务逻辑”比较密切)。而中间的传输层,正好是承上启下。对于开发应用软件的程序猿/程序媛,“传输层”是他们能感知的最低一层。

    传输层的【端口】

    刚才谈“传输层的必要性”,提到说:“网络层地址”只能标识【主机】,而传输层必须要能标识【进程】。为了达到这个目的,于是就引入了“传输层端口”这个概念(后续简称为“端口”)。

    在 OSI 模型中,“端口”的官方称呼是“传输服务访问点”( TSAP)。但是作为程序员,俺已经习惯于“端口”这个称呼。后续介绍依然用“端口”一词。

    当程序员使用传输层提供的 API 开发网络软件时,通常把“端口”与“网络地址”一起使用(构成“二元组”),就可以定位到某个主机上的某个进程。

    传输层:具体实例

    传输层的【协议】

    为了让程序员可以更爽地使用传输层来开发网络软件,传输层既要提供“有连接”的风格,也要提供“无连接”的风格。具体到“互联网协议族”,有两个主要的传输层实现,分别是 TCP & UDP(前者是“有连接”,后者是“无连接”)。

    除了 TCP & UDP,“互联网协议族”还提供了其它一些传输层协议。因为比较冷门,就不再一一介绍。

    传输层的【协议实现】

    对于电脑主机(含移动设备),传输层的协议实现通常包含在操作系统自带的网络模块中(也就是“操作系统协议栈”)。具体参见如下示意图。另外,还有一些专门的【4层】网络设备,也提供传输层的功能。

    OSI 模型中不同层次的协议实现

    套接字(socket API)

    传输层是面向程序员(让他们可以更方便地开发网络软件)。因此,就需要提供一些封装传输层的【库】(API)。程序员只需要调用这些【库】,就可以使用传输层的协议进行通讯。影响力最大的传输层封装库,当然是 socket API。它来自加州大学伯克利分校。

    在互联网诞生初期,伯克利分校开发了一个 UNIX 操作系统的的变种,叫做“伯克利 UNIX 发行版”(BSD Unix),也就是如今 BSD 操作系统的前身。伯克利发行版内置了一套用来进行网络编程的 API,当时叫做“伯克利套接字”(Berkeley sockets)。由于这套 API 用起来很方便,很多其它的 UNIX 变种也移植了这套 API,于是就逐渐成了业界的事实标准。到了上世纪90年代,Windows & Linux 也都提供了这套 API。

    传输层相关的【网络设备】

    4层交换机(Layer 4 switching)

    前面已经介绍了“3层交换机”,“4层交换机”是其进一步的改良,可以识别传输层的协议,获取 TCP or UDP 的端口号。有了这个能力,网管就可以在这种交换机上配置一些管理策略。比如说:(根据传输层端口号)过滤掉某种流量,或者对某种流量设置转发的优先级。

    状态防火墙(stateful firewall

    网络防火墙分好几种,大部分属于这种。它能完全处理 TCP 协议的状态,显然它属于“4层”(传输层)。

    传输层相关的【软件工具】

    netcat 家族:传输层的“瑞士军刀”

    netcat的功能的强大——很多与 TCP/UDP 相关的事情,都可以用 netcat 搞定。另外,netcat 还有很多衍生品(衍生的开源项目),构成一个丰富的 netcat 家族。在上述教程也有介绍。

    netstat & ss

    Windows 和 POSIX(Linux&UNIX)都有一个 netstat 命令,可以查看当前系统的 TCP/UDP 状态(包括当前系统开启了哪些监听端口)。另外,Linux 上还有一个 ss 命令,功能更强(但这个命令在 Windows 上默认没有)

    nmap

    这是最著名的开源的扫描器,可以扫描远程主机监听了哪些传输层端口(注:前面提到的“netcat 家族”也可以干这事儿),nmap 的功能很强大,“端口扫描”只是其功能之一。

    业务层(OSI 上三层):概述

    前面的章节说过:【上三层】更接近于“网络软件”,对应的是应用软件的业务逻辑,因此统称为“业务层”。

    注:有些书(比如《计算机网络》)会把 OSI 的上三层统称为“应用层”。由于 OSI 模型中本来就有一个“应用层”,这样容易搞混,所以另外起了一个“业务层”的名称。

    业务层的必要性

    业务层显然是必要的。因为传输层位于操作系统,它不可能去了解网络软件的业务逻辑。为了让网络软件能够相互通讯,肯定要在传输层之上再定义更高层的协议。

    问题在于:网络软件千奇百怪,其业务逻辑各不相同,因此,“业务层如何设计”,【无】一定之规。有些软件只用一个协议来搞定所有的业务逻辑(只有一层);有些软件会参考 OSI,把业务逻辑的协议分为三层;还有些软件可能会分出更多的层次。

    再强调一下:业务层的协议如何分层,完全看具体的业务逻辑,不要生搬硬套任何现有的参考模型。

    会话层 & 表示层 & 应用层

    对于大部分读者来说,【没必要】花时间去了解 OSI 最上面三层之间的区别。你只需把最上面三层视作都是与网络软件的业务逻辑密切相关的。

    那么,哪些人需要详细了解“这三层的差异”?

    如果你是个程序员,并且你正好是开发【网络】软件,俺建议你了解一下 OSI 模型的最上面三层,有助于你更深刻地思考某些网络协议的设计。

    业务层(OSI 上三层):具体实例

    业务层的【协议】

    业务层的协议非常多。即使光把各种协议的名称列出来,也很费劲。这里只点评几个特别重要的协议。

    HTTP 协议

    如果让俺评选最重要的业务层协议,俺首推 HTTP 协议。互联网的普及推动了 Web 的普及,而 Web 的普及使得 HTTP 成为信息时代的重要支柱。当你上网的时候,你看到的网页(HTML 页面)就是通过 HTTP 协议传输到你的浏览器上。

    如今 HTTP 已经不仅仅用来展示网页,还有很多业务层的协议是建立在 HTTP 协议之上。比如RSS 订阅,RSS 阅读器需要调用博客平台提供的 RSS 接口,这些 RSS 接口就是基于 HTTP 协议传输。

    SSL/TLS 协议

    最早的 HTTP 协议是【明文】,为了强化安全性,后来又设计了 SSL 协议,用来【加密】HTTP 流量;再后来,SSL 升级为 TLS(这俩是同义词)。如今经常看到的 HTTPS 相当于“HTTP over TLS”。

    SSL/TLS 设计得比较优雅(很灵活),使得其它业务层的协议可以很方便地架构在 SSL/TLS 之上。这样的好处是:其它协议就不用自己再设计一套加密机制&认证机制。

    域名相关的协议(DNS 及其它)

    域名相关的协议,也很重要。因为域名系统是整个互联网的基础设施。最早的域名查询协议是“DNS 协议”,由于这个协议【没有】加密,导致了一些安全隐患。因此,后来又设计了一系列新的域名协议,引入了加密的机制。

    业务层相关的【网络设备】

    应用层防火墙(application firewall

    前面提到了:大多数网络防火墙处于4层(状态防火墙),另外还有少数处于7层,也就是“应用层防火墙”(有时候也称之为“7层防火墙”)。一般来说,这类防火墙具备了【深度包检测】(deep packet inspection,简称 DPI)的能力,可以分析应用层协议的【内容】。

    简单说一下“深度包检测”:如果某个网络设备,仅仅分析“应用层协议”本身,它还【不够格】称之为 DPI。为了做到 DPI,还要能理解应用层协议所承载的【内容】。

    比如说:某人通过【明文】的 HTTP 协议从网上下载了一个 zip 压缩包。对于这个下载行为,那些做得好的 DPI 设备不光能识别出“HTTP 协议的内容是 ZIP 压缩包”,而且还能从 ZIP 压缩包中提取出里面的文件。

    入侵检测(intrusion detection system

    一般来说,“入侵检测”如果不加定语,通常指“【网络】入侵检测”(NIDS);另外还有一种“【主机】入侵检测”(HIDS)。HIDS 与本文无关。

    “入侵检测”是一种网络安全设备,它通过嗅探(sniffer)的方式抓取网上的数据包,然后进行分析,尝试发现网络中是否存在黑客/骇客的入侵的行为。故名“入侵检测”。

    由于 IDS 需要理解【应用层】(7层)的内容,因此它与“应用层防火墙”有个共同点,需要具备某种程度的 DPI(深度包检测)能力。它俩的一大差异是【部署方式】。简单说一下“旁路部署”,所谓的“旁路部署”类似于电路中的【并联】。通俗地说:IDS 是【并联】部署,防火墙是【串联】部署。

     

    杂项

    代理(proxy)

    代理服务器(proxy server)
    “代理服务器”部署在“客户端 & 服务端”之间,起到某种“中介”的作用。“代理服务器”的类型有很多,干的事情各不相同。

    代理服务器简单示意图

    网关(gateway

    前面的某些章节,已经稍微提及了“网关”这个概念,但还没有具体介绍它。严格来讲,“网关”是一个逻辑概念,【不要】把它当成具体的网络设备。充当“网关”的东东,可能是:路由器 or XX层交换机 or XX层防火墙 or 代理服务器等

    “网关”也分不同的层次。如果不加定语,通常指的是“3层网关”(网络层网关)。列几种比较常见的,供参考:

    • 路由器充当网关:3层(网络层)
    • 3层交换机充当网关:3层(网络层)
    • 4层交换机充当网关:4层(传输层)
    • 应用层防火墙充当网关:7层(应用层)
    • 代理服务器充当网关(取决于代理的层次,参见前一个小节)
    • ……

    隧道协议(tunneling protocol

  • Wireshark抓包实例诊断数据库常见问题(六)

    Wireshark抓包实例诊断数据库常见问题(六)

    介绍

    通常来说,数据库,应用和网络在IT架构中处于不同的分支。数据库的故障排查由DBA来完成,但是网络工程师仍可以从抓包中定位出问题并不出自网络。当IT抱怨“网速慢”,实际并不一定是这样。下文帮助我们验证所谓“网速慢”的问题。

    更多信息

    工作过程:

    对于数据库问题,按照以下步骤:

    1. 当怀疑是“慢速网络响应”时,问以下问题:
      • 问题发生于本地还是全局?是只发生在远端办公室,还是center也有发生?如果整个网络都出现问题,就不会是WAN带宽问题。
      • 对于所有客户端是否都发生了这样的问题?如果只是某些特定用户碰到问题,则可能是这些用户运行了某些应用导致。
      • 客户端和服务器之间通讯链路是否过载?导致过载的应用是什么?
      • 是所有应用都运行缓慢,还是使用特定数据库的应用运行缓慢?是PC比较老旧,还是服务器资源耗尽?
    2. 搞清楚上述问题之后,开始故障排查:
      1. 打开Wireshark开始抓包。可以将对端端口连到PC,服务器,VLAN,或连接远端客户端的路由器。
      2. 在expert info中查看TCP事件。这些事件发生在整个通信链路,或是特定的IP地址,还是特定的TCP端口?此操作能够帮助定位问题并验证是否发生于特定链路,服务器,或是应用。测试连接到Internet的数据流时,可能会得到发往站点或mail server(诸如此类)的很多重传以及重复ACK。在组织内部,重传范围应当在百分之0.1至0.5。连接到Internet时,可能会高得多。
    3. 当你看到网络上有问题时,按照前几张的故障排查步骤给予解决。但是,也有些网络问题会影响数据库操作。下例中,可看到客户端与服务器通信链路往返延时达到35至40ms。
      1. 我们查看TCP stream 8(1),连接开始于TCP SYN/SYN-ACK/ACK。如下图(2)所示。可以看到整个连接花费了371个报文(3)。

    2. 连接继续,可见到DB请求与响应之间时间间隔大约35ms。

    1. 由于往返已经有371个报文,371X35 ms大约是13秒。加上可能发生一些重传导致延时,用户查询一次数据库可能要等待10至15秒。
    2. 这种情况下,应当与DBA讨论怎样大幅减少网络上传输的报文数量,或是改变终端服务器或网络接入的方式。

    4. 另一个可能发生的问题是抓包文件反映出有软件问题。以下截图中可看到5个重传(1),并且客户端打开了一个新的连接(3)。看起来像一个TCP问题但只发生在软件中一个特定窗口。这只是由于一个软件进程停止运行,因此TCP无法对客户端作出响应(2)。

    更多建议:

    右键数据库客户端与服务器会话报文,会打开一个窗口,有助于DBA查看网络问题。当碰到延时问题时,例如,通过移动电话接入Internet,数据库客户端到服务器的通讯可能效率低下。可能需要切换接入方式。

    很重要的一点是搞清楚数据库的工作模式。如果客户端正在接入数据库服务器,数据库服务器正在使用从另一台服务器共享的文件,可能客户端——服务器工作良好,但问题可能出在数据库服务器与文件服务器之间共享文件上。确保在开始测试之前确知所有依赖条件。

  • Wireshark抓包实例分析HTTP问题(五)

    Wireshark抓包实例分析HTTP问题(五)

    介绍

    HTTP的问题可能是由于慢速服务器或客户端,TCP性能问题,本文讨论上述问题以及其他可能因素。

    更多信息

    诊断过程:
    浏览网页性能变差的原因有很多,需要逐步分析。步骤如下:

    1. 首先,不仅要确认网络负载状况,还要注意通信链路上的出错率,以及导致性能变差的最明显的表现;
    2. 诊断TCP问题,检查以下细节:
      • 在Expert info窗口,确保没有太多重传以及重复ACK(百分之0.5至0.8尚可忍受)。
      • 确保HTTP连接上没有reset,可能由于防火墙或站点限制引发。
    3. 确保没有以下DNS问题:
      • 慢速响应时间
      • 域名未找到

    如果以上均不适用,就需要对HTTP深入研究。

    注意:将网络和IT环境看作一个整体。对于慢速网络浏览应用,TCP问题亦不能分离于HTTP,DNS问题。可能是由于慢速HTTP服务器,因服务器的慢速响应而产生了TCP重传。或者,由于DNS慢速服务器,打开网页可能需要好几秒钟。一步步定位问题就好了。

    当你第一次打开一个网页,可能需要几秒钟。在这种情况下,应当查看以下情况:

    1. 检查线路是否过载
    2. 检查线路延时(通过ping工具)
    3. 查看错误代码,通常能看到浏览器报错原因,但并不总是能看到。
    4. 配置过滤器http.response >= 400并查看有多少错误。以下章节,你会看到需要注意的示例。

    Informational codes:

    Success codes:

    Redirect codes:

    Client errors:

    以下示例是一个简单的客户端报错。按照以下步骤进行操作:

    1. 右键有报错的报文。
    2. 选择Follow TCP stream,会看到以下窗口:

    3. 显示以下内容:

    • 客户端尝试浏览URI/poker-client/broadcast.htm(如截屏中1和3所示)
    • URI通过http://www.888poker.com/poker-client/promotions.htm转发(截屏中2所示)
    • 状态码为404 Not Found(如截屏中4所示)

    Client errors:

    服务器不可用(错误代码503)可能有多种原因。以下示例是一个小办公室碰到的问题:员工能够访问Facebook,但当他们点击站点上的链接,则显示页面被拦截。以下截屏中,可看出页面被防火墙拦截:

    工作原理:

    标准的HTTP浏览模式如下:

    1. TCP打开连接(三路握手信号)
    2. HTTP发送GET命令
    3. 数据下载到浏览器

    在一个网页打开多个连接的情况下(大多数网页都是如此)。每个连接需要一个DNS 查询,响应,TCP SYN-SYN/ACK-ACK,以及HTTP GET。之后数据才会出现在显示屏上。

    当你在packet detail面板没有看到显示内容时,右键报文并选择Follow TCP stream,会看到连接的细节数据。另一个广泛应用的工具是Fiddler,Fiddler是HTTP故障排查的免费工具。

  • Wireshark抓包实例分析TCP窗口及reset(四)

    Wireshark抓包实例分析TCP窗口及reset(四)

    介绍

    TCP最重要的机制之一是滑动窗口机制,以及用以控制TCP终端节点愿意接收的数据总量的流控机制。

    TCP reset可以在几种情况下被发送。有一些是协议的正常工作过程,有一些则表明可能有问题。本节中,我们查找问题以及分析解决问题的方法。

    更多信息

    TCP窗口问题:

    TCP零窗口,零窗口探测,零窗口违例

    TCP零窗口:发生于接收方在TCP头部的window字段广播接收窗口零字节的时候。这一事件告知发送方停止发送数据,因为接收方缓存已满。这也表明接收方可能发生以下问题:

    • 服务器无法为进程分配组后的内存
    • 应用碰到没有足够内存的问题,因此TCP需告知发送方停止发送数据
    • 应用消耗太多内存因此操作系统要限制应用资源

    TCP零窗口探测:由发送方发出,以查看接收方的零窗口是否依然存在。这一消息通过发送下一字节数据给接收方,如果接收方回复窗口大小仍然为零,则发送方的探测计时器加倍。

    TCP窗口违例:发送方忽略接收方的零窗口大小并发送额外字节数据。TCP零窗口违例表明
    协议栈中有TCP错误。为了检查是何问题,检查是否有以下事件:

    • 某一终端设备(服务器或客户机)报出终端设备故障
    • 某一应用报出常规应用错误
    • 应用中执行某一操作时报错,例如,打开一个表格,发送一份文件至打印机,创建一个报告,或其他操作。这种情况下,是应用问题。

    TCP窗口更新

    TCP将窗口更新:发送至连接的对端,以表明缓存大小更改,并且准备好接受更高或更低的数据速率(缓存大小决定了发送方被允许的发送速率)。这一情况发生于:

    • TCP接收方从零窗口中恢复,告知发送方重新发送速率。这一情况下,无需进行处理,只需检查第一次导致零窗口的问题。
    • TCP接收方频繁更改窗口大小。该情况下检查接收方被干扰的原因。可能是应用问题,内存问题,或终端设备上的其他问题。

    看到这类现象无需担心,这就是TCP的工作机制。

    TCP窗口已满

    这一信息表明已发送的报文会完全填满接收方的接收缓存。发生于接收方没有对先前接收到的数据发出任何ACK确认信息,因此,这将会成为发送方从接收方收到ACK之前的最后一个报文数据。

    这一事件的触发原因与触发零窗口的原因相同,是服务器或应用无响应的标志。典型实例如下图所示:

    上图中可以看到:

    1. 报文183816,192.168.2.138告知192.168.1.58发送窗口已满。
    2. 下一个报文,192.168.1.58发送一个信号至192.168.2.138,告知对方停止发送数据。这是一个零窗口信号。
    3. 双方继续发送零窗口以及零窗口探测。
    4. 连接的最后一个报文是192.168.2.138发送的RST报文,目的是断开连接。
    5. 某些情况下零窗口可以通过窗口更改信息来回复。某些情况下可通过reset来关闭(可以是应用零窗口从而没有收到任何数据导致)。

    工作原理

    TCP滑动窗口机制如下:

    1. 连接建立之后,发送方将数据发送至接收方,填入接收窗口。
    2. 若干报文之后,接收方发送ACK至发送方,确认接收到其发送的字节数。发送ACK将接收窗口清零。
    3. 这一过程持续下去,发送方向窗口中填入数据,接收方清空并发送确认信息。
    4. 扩大接收窗口大小告知发送方增加吞吐量,减小窗口告知对方减小吞吐量。这一机制按照WS/RTT规则(随着TCP版本不同而有所改变):

    也可以通过TCP吞吐量图表和IO图来查看问题。在TCP吞吐量图表中,使用TCP trace图表,上面一行显示了窗口大小,与下面一行的距离表明窗口的剩余大小。没有距离表示零窗口。

    两行之间的固定距离表明接收方工作良好。当两行渐渐靠近,表明发送方速度高于接收方。只要这两行没有重叠,TCP就会继续发送数据。

    TCP reset及原因:

    在可疑的链路或服务器两端连接Wireshark,开始抓包。观察抓包窗口的每一个窗口信息。TCP reset可以在几种情况下被发送。有一些是协议的正常工作过程,有一些则表明可能有问题。本节中,我们查找问题以及分析解决问题的方法。

    reset是用以告知接收方断开连接的TCP信号,通过将RST标志位置1来发送。正常的操作过程中,TCP通过SYN信号打开连接,通过FIN信号关闭连接。TCP的一大特性在于有问题时,或只是为了更好的性能,它能够快速关闭连接。

    无故障时发送reset

    TCP关闭连接的标准方式是通过FIN和FIN-ACK信号。为了关闭连接,用户需要四个报文:来自一方的FIN/ACK和ACK,以及另一方的同样报文。当你打开一个网页,可能同时打开了数十个连接(主页,新闻,广告,定期更新的图片等),要关闭所有这些有时需要数百个FIN和FIN-ACK报文。为了防止其发生,web服务器在很多情况下会在发送请求数据之后用reset断开连接。这是标准的做法,并取决于应用程序。

    有故障时发送reset

    某些情况下reset表明有故障发生(并不一定是通信故障):

    • 防火墙发送的reset:当远端服务器尝试打开连接但没有结果时,也许会看到返回RST信号。这是防火墙阻隔连接的情况。下图中,可看到发送的每一个SYN都返回以RST。
    • 由于收发一方有问题发送的reset:可能的原因如:
      • 五个连续没有收到ACK回复的重传。当发送方没有收到任何重传回复,它就会发送一个reset信号到对端,告知其断开连接。
      • 另一个原因是连接之上几分钟都没有任何数据(分钟数取决于系统默认)。打开连接的一方通常会发送reset(但并不总是会这样做,取决于实现方式)。
  • Wireshark抓包实例分析TCP重复ACK与乱序(三)

    Wireshark抓包实例分析TCP重复ACK与乱序(三)

    介绍

    TCP的一大常见问题在于重复ACK与快速重传。这一现象的发生也是由于性能问题,本章讨论如何发现这一问题以及他们意味着什么。

    另一个常见问题是前一片段丢失以及乱序片段。某些情况下,这一现象喻示着故障发生,可能是由于网络问题或是抓包中断。

    更多信息

    重复ACK与快速重传:

    当网速变慢时,重复ACK是可能的原因之一。大多数情况下,重复ACK的发生是由于高延时,延迟的变化,或无法响应ACK请求的慢速终端。

    1. 当重复ACK的数量保持在合理范围时,即1或2个百分比,则可能不是本机问题。
    2. 当有大量的重复ACK时(假设有10个),则可能:
      • 通信链路繁忙引起延迟改变
      • 服务器或客户端无响应
    3. 快速重传是对重复ACK的响应报文。
    4. 下图是该问题的示例。本例中51个重复ACK之后发生了快速重传:
    1. 以下是如何解决该问题:
      • 如果重复ACK和重传数量较少(少于1个百分比),是可以接受的。
      • 如果重复ACK发生在无线网络环境,或是Internet之上的连接,延时或是延时的改变对于这类网络来说很常见,所以也没有什么可做的。
      • 如果发生在组织内的网络,则可能有问题。如果发生在LAN之上,检查严重的问题,例如缓存和CPU负载,慢速服务器,等等。如果发生在WAN之上,查看延时,负载以及线路不稳定。

    工作原理

    当发现有丢失报文时(期望的序列号没有收到),或者收到了预期之外的序列号。这种情况下,接收端生成一个ACK,声明自己希望收到的下一个序列号。接收方持续生成丢失片段的ACK请求,直到实际收到。

    在发送方,当它收到三个相同的ACK(初始ACK和两个重复ACK),就会假设有报文丢失并重传该报文,无论重传计时器是否过期。再次发送的报文称为快速重传。

    重复ACK也减少了发往网络的吞吐量。减少了多少吞吐量取决于TCP版本。比较早期的TCP版本中出现了重复ACK,发送方将吞吐量减少为之前的一半。在多个DupACK的情况下,吞吐量减到最小。

    下图显示了重复ACK和重传的典型例子,本图中第一次重复ACK将吞吐量降低至大约40%,之后重传将吞吐量减至最小。

    乱序报文:

    在两端抓包,乱序情况下需要关注三种现象:

    • 先前片段丢失:当前收到报文的序列号高于该连接的下一个期望序列号时,表明之前的一个或多个报文未能到达
    • 乱序报文:当前报文的序列号低于该连接先前收到的报文
    • 先前片段未能捕捉:(Wireshark 1.8.x及以上版本):同先前报文丢失。

    何时发生?

    用户可能在以下情况看到乱序报文:

    • 连接开始时抓包:当建立连接时抓包,这时,看到连接上的报文没有SYN/SYN-ACK/ACK,因此,Wireshark认为连接有问题。
    • 确实有报文丢失:这时会看到丢失报文重传和/或重复ACK告知发送方重传丢失报文。

    上图是报文丢失的典型示例。从图中可见,10.0.0.6尝试浏览站点62.90.90.210。这一过程中, TCP片段每个1420字节发送到web服务器,334到336之间3个报文丢失,338到340之间2个报文丢失。两者Wireshark都有提示:TCP’s previous segment is not captured.

    • 延时变化:这可能是由于报文从源地址到目的地址经由不同的路由。检查这一点可以使用Tracert,在源和目的地址之间查找路由改变。如果在公司内部网络上是可以做到的,例如,在路由器上配置trap。
    • 数据捕捉问题:可能报文正常收发,但Wireshark没有捕捉到。可能有以下几种原因:
      • 数据量比较大时,Wireshark在高比特率的情况下可能会丢失报文(高于150-180Mbps)。要避免这一问题,使用其他工具(大多数需要付费)。
      • 台式机不够强大,内存或CPU无法让Wireshark工作的足够快。这一点很好发现。
      • 当LAN交换机的端口缓存太小,报文可能被丢弃。连接到交换机(用控制台或telnet连接)使用交换机命令行来检查该问题。
      • 无线网络抓包,由于某种原因没有看到所有发送报文。

    总结

    乱序报文的原理很简单。TCP发送以其字节数为编号的报文到接收方。当一个报文没有按照顺序到达时,Wireshark就会注意到。原因有两点:

    • 确实有问题:这时会看到重传和重复ACK,这是TCP对于收到乱序报文的响应。
    • 抓包问题:这时仅看到乱序报文,但没有看到对可能丢失及乱序报文的响应,可能实际上并没有问题。
  • Wireshark抓包实例分析TCP重传(二)

    Wireshark抓包实例分析TCP重传(二)

    介绍

    TCP发送一个或一组报文,会等待收到报文的确认信息。重传,即发生在报文没有到达或确认信息没有及时返回的情况下。当发现网速变慢时,原因之一可能就是重传。发生重传的原因有多种,在客户机或服务器两边端口应用Wireshark有助于诊断问题。本文通过抓包实例阐述各种可能性。

    更多信息

    诊断过程:

    1. 在相应端口开始抓数据。
    2. 找到Analyze | Expert Info菜单。
    3. 在Notes之下,查找Retransmission。
    4. 点击(+)符号即可打开重传列表。鼠标点击各行可在抓包面板看到重传报文。
    5. 现在问题来了,怎样定位问题呢?
    6. 通过以下方式查看重传来自哪里:
      • 在Expert Info窗口一个一个查看报文,在抓包面板查看哪些是重传报文(适合于有经验的用户)
      • 在报文面板,配置显示过滤器expert.message == “Retransmission (suspected)”,即可看到抓包文件中所有重传报文
      • 应用过滤器,在Statistics & Conversations窗口查看Limit to display filter部分。

    Case 1:重传至多个目的地址

    以下截屏中,可看到有多次重传,分布于多台服务器,目的端口号为80(HTTP)。也可以发现重传由端口10.0.0.5发送,因此报文是丢失在发往Internet的途中,或确认信息没有及时从web服务器发回。

    问题发生在发往Internet的线路上,怎样知道是什么问题呢?

    1. 从Statistics菜单,打开IO Graph。
    2. 本例中,可看到链路负载非常低。可能是有故障,或有另一条高负载链路。
    3. 可以通过登录到通信设备或SNMP浏览器查看引起重传的原因:报文丢失及错误。参考以下截屏

    Case 2:重传至单一连接

    如果所有重传发生于同一IP,同一TCP端口号,则可能是慢速应用引起。看以下截屏:

    对于单一连接的重传,进行以下操作:

    1. 从Statistics菜单打开Conversations,选择Limit to display filter,可以看到所有发生重传的会话,本情况下,是一个单一会话。
    2. 如下图所示,通过选择IPv4标签可看到从哪个IP地址重传:

    3. 如下图所示,通过选择TCP标签看到重传来自哪一端口:

    要定位问题,进行以下步骤:

    1. 查看IO graph,确保链路不忙。(链路忙的表征例如流量接近带宽。例如,带宽为10Mbps,在IO graph中看见流量接近10Mbps,这就表明链路负载较高。不忙的链路IO会有很多高低起落,峰值以及空闲间隙)。
    2. 如果链路不忙,则可能是服务器对于IP地址10.1.1.200有问题(10.90.30.12发送了绝大多数重传,所以可能是10.1.1.200响应较慢)
    3. 从报文面板可以看出应用是FTP数据。有可能FTP服务器工作于active模式。因此在端口2350打开连接,服务器将端口更改为1972,所以可能是慢速FTP软件响应问题引起的重传。

    Case 3:重传模式

    观察TCP重传的一个重要考量是是否能看出一些重传模式。在以下截屏中,可以看见所有重传来自单一连接,位于客户端与服务器的NetBIOS会话服务(TCP端口139)。

    看起来像一个简单的服务器/客户端问题,但查看抓包面板,如下图所示:

    可以看见重传总是周期性的每30ms发生一次。问题是由于客户端在软件中执行了财务进程,导致软件每30-36ms就减速一次。

    Case 4:应用无响应导致重传

    另一个可能导致重传的原因是客户端或服务器没有响应请求。这种情况下,会看到五次重传,时间也会逐渐延长。五次连续重传后,发送方认为连接断开(某些情况下,会发送reset来关闭连接,取决于软件实施)。断开连接之后,可能会发生两件事情:

    • 发送SYN请求至客户端,以打开一个新的连接。这种情况下用户会看到应用冻结,过了15-20秒之后重新开始工作。
    • 不发送SYN,用户需要重新运行应用程序(或应用程序的一部分)

    下图显示了打开新连接的情况:

    Case 5:由于延时变化导致重传

    TCP能够充分容忍延时,前提是延时大小不发生变化。当延时改变时,就会发生重传。诊断是否由该原因引起的方法:

    1. 第一件事是ping目的地址,并且得到检查通信链路延时的第一条信息。
    2. 检查延时变量,可能由以下原因引起:
      • 由于不稳定或繁忙通信链路引起。这种情况下,可以看到ping命令的延时变化,通常由于带宽较窄。
      • 由于应用过载或资源不足,这种情况下,只有该应用发生很多重传。
      • 通信设备过载(CPU,缓存)引起延时。检查方式直接连接通信设备。
    3. 使用Wireshark工具诊断延时问题。

    如果重传达到0.5个百分比,性能就会下降,断开连接将会达到5个百分比。这取决于应用及其对于重传的敏感性。

    定位重传问题

    当你看到通信链路上发生重传,进行以下步骤:

    1. 定位问题——是一个特定IP地址,特定连接,特定应用,还是其他问题。
    2. 查看问题是否由于通信链路,丢包,慢速服务器还是PC。查看应用是否慢速。
    3. 如果不是由于上述原因,检查延时变化。

    工作原理:

    TCP序列号/确认机制详见:TCP确认机制 。那么重传是由什么原因引起呢?当报文确认信息丢失,或ACK没有及时到达,发送方会进行以下两步操作:

    1. 再次发送报文
    2. 减少吞吐量。

    以下图中展示了重传减少发送方吞吐量(红色细线):