带上你的千军万马,即使最后难免孤军奋战。

阅读提要

全文约1.5W字,大致阅读完约15分钟,包含主要知识点:Nmap命令详解Masscan命令详解python调用Nmap、python调用Masscan、端口运行服务识别、IPY库生成相关IP段,其中关键部位文字使用橙色重点标注。

Nmap功能

端口扫描:扫描开放的端口并且识别运行服务

主机探测:Nmap可査找目标网络中的在线主机。默认情况下,Nmap通过4种方式—— ICMP echo请求(ping)、向443端口发送TCP SYN 包、向80端口发送TCP ACK包和ICMP 时间戳请求——发现目标主机。

服务/版本检测:在发现开放端口后,Nmap可进一步检查目标主机的检测服务协议、应用 程序名称、版本号等信息。

操作系统检测:Nmap 向远程主机发送一系列数据包,并能够将远程主机的响应与操作系统 指纹数据库进行比较。如果发现了匹配结果,它就会显示匹配的操作系统。它确实可能无法 识别目标主机的操作系统;在这种情况下,如果您知道目标系统上使用的何种操作系统,可 在它提供的 URL 里提交有关信息,更新它的操作系统指纹数据库。

网络路由跟踪:它通过多种协议访问目标主机的不同端口,以尽可能访问目标主机。Nmap 路由跟踪功能从TTL的高值开始测试,逐步递减TTL,直到它到零为止。

Nmap脚本引擎:这个功能扩充了Nmap的用途。如果您要使用Nmap实现它(在默认情况 下)没有的检测功能,可利用它的脚本引擎手写一个检测脚本。目前,Nmap可检査网络服务 的漏洞,还可以枚举目标系统的资源。

常用功能

直接扫描

nmap 118.24.11.235

获取开放端口与运行服务

检测指定端口

nmap -p 8080 118.24.11.235

检测8080端口是否开放

-p端口范围:只扫描指定的端口。扫描1〜1024号端口,可设定该选项为–p 1-1024。扫描1 〜65535端口时,可使用-p-选项。

扫描网段

扫描网段的信息

nmap  -p 22,21,80 192.168.1.1-253

识别运行服务

服务版本识别(-sV),Nmap可以在进行端口扫描的时候检测服务端软件的版本信息。版本信息将使后续的漏 洞识别工作更有针对性。

nmap -sV 118.24.11.235 -p 80

识别操作系统

操作系统检测(-O),Nmap还能识别目标主机的操作系统。

nmap -O 118.24.11.235

强力优化检测

强力检测选项(-A),启用-A选项之后,Nmap将检测目标主机的下述信息
服务版本识别(-sV);
操作系统识别(-O);
脚本扫描(-sC);
Traceroute(–traceroute)

可以看到获取了更多详细的数据

nmap -A 118.24.11.235

禁用主机检测

禁用主机检测(-Pn),如果主机屏蔽了ping请求,Nmap可能会认为该主机没有开机。这将使得Nmap无法进行进一 步检测,比如端口扫描、服务版本识别和操作系统识别等探测工作。为了克服这一问题,就 需要禁用Nmap的主机检测功能。在指定这个选项之后,Nmap会认为目标主机已经开机并会 进行全套的检测工作

nmap -Pn -A 118.24.11.235

常用片段

nmap -sP 192.168.0.0/24   判断哪些主机存活
nmap -sT 192.168.0.3   开放了哪些端口
nmap -sS 192.168.0.127 开放了哪些端口(隐蔽扫描)
nmap -sU 192.168.0.127 开放了哪些端口(UDP)
nmap -sS -O  192.168.0.127 操作系统识别

输出选项

Nmap可以把扫描结果保存为外部文件。在需要使用其他工具处理Nmap的扫描结果时,这一 功能十分有用。即使您设定程序把扫描结果保存为文件,Nmap还是会在屏幕上显示扫描结果。

Nmap支持以下几种输出形式。

正常输出(-oN):不显示runtime信息和警告信息。XML 文件(-oX):生成的 XML 格式文件可以转换成   HTML    格式文件,还可被Nmap    的图 形用户界面解析,也便于导入数据库。本文建议您尽量将扫描结果输出为XML文件。生成便于Grep使用的文件(-oG):虽然这种文件格式已经过时,但仍然很受欢迎。这种格 式的文件,其内容由注释(由#开始)和信息行组成。信息行包含6个字段,每个字段的字段 名称和字段值以冒号分割,字段之间使用制表符隔开。这些字段的名称分别为Host、Ports、Protocols、Ignored State、OS、Seq Index、IP ID   Seq 和Status。这种格式的文件便于 grep或awk之类的UNIX指令整理扫描结果。输出至所有格式(-oA)利用-oA<basename>选项 可将扫描结果以标准格式、XML格式和Grep格式一次性输出。分别存放在 <basename>.nmap,<basename>.xml和 <basename>.gnmap文件中。也可以在文件名前 指定目录名,如在UNIX中,使用~/nmaplogs/foocorp/, 在Window中,使用c:\hacking\sco on Windows。

为使用方便,利用-oA选项 可将扫描结果以标准格式、XML格式和Grep格式一次性输出。分别存放在.nmap,.xml和.gnmap文件中。

时间排程控制选项

Nmap可通过-T选项指定时间排程控制的模式。它有6种扫描模式。

paranoid(0):每5分钟发送一次数据包,且不会以并行方式同时发送多组数据。这种模式 的扫描不会被IDS检测到。sneaky(1):每隔15秒发送一个数据包,且不会以并行方式同时发送多组数据。polite(2):每0.4  秒发送一个数据包,且不会以并行方式同时发送多组数据。normal(3):此模式同时向多个目标发送多个数据包,为   Nmap    默认的模式,该模式能自 动在扫描时间和网络负载之间进行平衡。aggressive(4):在这种模式下,Nmap   对每个既定的主机只扫描5    分钟,然后扫描下一 台主机。它等待响应的时间不超过1.25秒。insane(5):在这种模式下,Nmap   对每个既定的主机仅扫描75   秒,然后扫描下一台主 机。它等待响应的时间不超过0.3秒。

默认的扫描模式通常都没有问题。除非您想要进行更隐匿或更快速的扫 描,否则没有必要调整这一选项。

脚本引擎功能(Nmap Scripting Engine,NSE)

Nmap本身已经很强大了,但是加上它的脚本引擎更加开挂了,NSE 可使用户的各种网络检査工作更为自动化,有助于识别应 用程序中新发现的漏洞、检测程序版本等Nmap原本不具有的功能。虽然Nmap软件包具有各 种功能的脚本,但是为了满足用户的特定需求,它还支持用户撰写自定义脚本。

auth:此类脚本使用暴力破解等技术找出目标系统上的认证信息。default:启用--sC  或者-A    选项时运行此类脚本。这类脚本同时具有下述特点:执行速度快;输出的信息有指导下一步操作的价值;输出信息内容丰富、形式简洁;必须可靠;不会侵入目标系统;能泄露信息给第三方。discovery:该类脚本用于探索网络。dos:该类脚本可能使目标系统拒绝服务,请谨慎使用。exploit:该类脚本利用目标系统的安全漏洞。在运行这类脚本之前,渗透测试人员需要获取 被测单位的行动许可。external:该类脚本可能泄露信息给第三方。fuzzer:该类脚本用于对目标系统进行模糊测试。instrusive:该类脚本可能导致目标系统崩溃,或耗尽目标系统的所有资源。malware:该类脚本检査目标系统上是否存在恶意软件或后门。safe:该类脚本不会导致目标服务崩溃、拒绝服务且不利用漏洞。version:配合版本检测选项(-sV),这类脚本对目标系统的服务程序进行深入的版本检 测。vuln:该类脚本可检测检査目标系统上的安全漏洞。
在Kali   Linux系统中,Nmap脚本位于目录/usr/share/nmap/scripts。-sC 或--script=default:启动默认类NSE  脚本。--script    <filename>|<category>|<directories>:根据指定的文件名、类别名、目录名,执行 相应的脚本。--script-args   <args>:这个选项用于给脚本指定参数。例如,在使用认证类脚本时,可通过 这个选项指定用户名和密码

使用方法:

nmap --script http-enum,http-headers,http-methods,http-php-version  -p  80 192.168.1.101

增强版漏洞扫描

上提供的脚本虽然强啊,但是数量相对较少,于是乎我们来隆重推荐一下Vulscan,它是Nmap的一个漏洞扫描增强模块,通过它可以把Nmap打造成一款实用高效免费的漏洞扫描器。Vulscan目前包含了CVE、OSVDB、Exploit-db、openvas等多个漏洞平台指纹数据,具备离线扫描功能,对主机系统漏洞有很好的探测识别效果。

下载地址:https://github.com/scipag/vulscan

安装

通过其程序Github或官网压缩包下载,解压后把其中的文件释放到以下Nmap文件夹内:

Nmap\scripts\vulscan\*

使用1

如下命令对目标主机开始扫描:

nmap -sV –script=vulscan/vulscan.nse www.example.com

该-sV是绝对必要的。使用-sV,我们告诉Nmap探测版本信息的目标地址。如果Nmap不生成版本信息,nmap-vulners将不会有任何数据来查询Vulners数据库。使用这些NSE脚本时始终使用-sV

我们可以像nmap-vulners一样使用vulscan NSE脚本:

nmap --script vulscan -sV <目标IP>

默认情况下,vulscan会一次查询所有前面提到的数据库!正如我们在上面的图片中看到的那样,消化的信息量非常大。这比我们需要的信息要多得多。我强烈建议一次只查询一个数据库。我们可以通过将vulscandb参数添加到我们的Nmap命令并指定数据库来实现此目的,如下面的示例所示。

nmap --script vulscan --script-args vulscandb = database_name -sV <目标IP>
nmap --script vulscan --script-args vulscandb = scipvuldb.csv -sV <目标IP>
nmap --script vulscan --script-args vulscandb = exploitdb.csv -sV <目标IP>
nmap --script vulscan --script-args vulscandb = securitytracker.csv -sV <目标IP>

使用2

合并为一个命令,NSE脚本作为安全扫描器显着提高了Nmap的多功能性,范围。为了充分利用Nmap的版本扫描,我们可以在一个命令中使用nmap-vulners和vulscan。要执行此操作,请在终端中输入以下命令。

nmap --script nmap-vulners,vulscan --script-args vulscandb = scipvuldb.csv -sV <目标IP>

漏洞库数据

scipvuldb.csv – https://vuldb.comcve.csv – http://cve.mitre.orgosvdb.csv – http://www.osvdb.orgsecurityfocus.csv – http://www.securityfocus.com/bid/securitytracker.csv – http://www.securitytracker.comxforce.csv – http://xforce.iss.netexpliotdb.csv – http://www.exploit-db.comopenvas.csv – http://www.openvas.org

单个漏洞库使用命令

--script-args vulscandb=your_own_database

漏洞库升级

需要在官网下载或通过以下链接手动下载数据库文件到/vulscan/目录中保持数据更新:

http://www.computec.ch/projekte/vulscan/download/cve.csvhttp://www.computec.ch/projekte/vulscan/download/exploitdb.csvhttp://www.computec.ch/projekte/vulscan/download/openvas.csvhttp://www.computec.ch/projekte/vulscan/download/osvdb.csvhttp://www.computec.ch/projekte/vulscan/download/scipvuldb.csvhttp://www.computec.ch/projekte/vulscan/download/securityfocus.csvhttp://www.computec.ch/projekte/vulscan/download/securitytracker.csvhttp://www.computec.ch/projekte/vulscan/download/xforce.csv

版本检测功能

版本检测功能在于对软件版本和漏洞数据库的具体信息进行探测,关闭该功能可能会导致误报,减少漏报提高运行效率,你可以使用以下命令把该功能关闭:

--script-args vulscanversiondetection=0

优先匹配功能

该功能在于对漏洞检测进行最优匹配扫描,可能会引起误报,但有利于对漏洞进行全面识别,使用以下命令开启该功能:

--script-args vulscanshowall=1

交互模式

该功能可以涵盖所有端口的检测结果,使用以下命令开启该功能:

--script-args vulscaninteractive=1

规避检测的选项

在渗透测试的工作中,目标主机通常处于防火墙或 IDS 系统的保护之中。在这种环境中使用 Nmap 的默认选项进行扫描,不仅会被发现,而且往往一无所获。此时,我们就要使用Nmap 规避检测的有关选项。

-f(使用小数据包):这个选项可避免对方识别出我们探测的数据包。指定这个选项之后, Nmap将使用8字节甚至更小数据体的数据包。--mtu:这个选项用来调整数据包的包大小。MTU(Maximum   Transmission    Unit,最大传输 单元)必须是8的整数倍,否则Nmap将报错。-D(诱饵):这个选项应指定假 IP,即诱饵的 IP。启用这个选项之后,Nmap    在发送侦测 数据包的时候会掺杂一些源地址是假IP(诱饵)的数据包。这种功能意在以藏木于林的方法 掩盖本机的真实 IP。也就是说,对方的log还会记录下本机的真实IP。您可使用RND生成随机 的假IP地址,或者用RND:number的参数生成<number>个假IP地址。您所指定的诱饵主机 应当在线,否则很容易击溃目标主机。另外,使用了过多的诱饵可能造成网络拥堵。尤其是 在扫描客户的网络的时候,您应当极力避免上述情况。--source-port   <portnumber>或-g(模拟源端口):如果防火墙只允许某些源端口的入站流 量,这个选项就非常有用。--data-length:这个选项用于改变Nmap  发送数据包的默认数据长度,以避免被识别出来是 Nmap的扫描数据。--max-parallelism:这个选项可限制Nmap   并发扫描的最大连接数。--scan-delay    <time>:这个选项用于控制发送探测数据的时间间隔,以避免达到IDS/IPS端 口扫描规则的阈值。

TCP/UDP扫描

TCP扫描选项

1.TCP连接扫描(-sT):指定这个选项后,程序将和目标主机的每个端口都进行完整的三次 握手。如果成功建立连接,则判定该端口是开放端口。由于在检测每个端口时都需要进行三 次握手,所以这种扫描方式比较慢,而且扫描行为很可能被目标主机记录下来。如果启动 Nmap的用户的权限不足,那么默认情况下Nmap程序将以这种模式进行扫描。

2.SYN扫描(-sS):该选项也称为半开连接或者SYN stealth。采用该选项后,Nmap将使用 含有SYN标志位的数据包进行端口探测。如果目标主机回复了SYN/ACK包,则说明该端口处 于开放状态:如果回复的是RST/ACK包,则说明这个端口处于关闭状态;如果没有任何响应 或者发送了ICMP unreachable信息,则可认为这个端口被屏蔽了。SYN模式的扫描速度非常 好。而且由于这种模式不会进行三次握手,所以是一种十分隐蔽的扫描方式。如果启动Nmap 的用户有高级别权限,那么在默认情况下Nmap程序将以这种模式进行扫描。

3.TCP NULL(-sN)、FIN(-sF)及XMAS(-sX)扫描:NULL 扫描不设置任何控制位;FIN扫描仅设置FIN标志位:XMAS扫描设置FIN、PSH和URG的标识位。如果目标主机返回 了含有RST标识位的响应数据,则说明该端口处于关闭状态;如果目标主机没有任何回应, 则该端口处于打开|过滤状态。

4.TCP Maimon扫描(-sM):Uriel Maimon 首先发现了TCP Maimom扫描方式。这种模式的 探测数据包含有FIN/ACK标识。对于BSD衍生出来的各种操作系统来说,如果被测端口处于 开放状态,主机将会丢弃这种探测数据包;如果被测端口处于关闭状态,那么主机将会回复 RST。

5.TCPACK扫描(-sA):这种扫描模式可以检测目标系统是否采用了数据包状态监测技术 (stateful)防火墙,并能确定哪些端口被防火墙屏蔽。这种类型的数据包只有一个ACK标识 位。如果目标主机的回复中含有RST标识,则说明目标主机没有被过滤。

6.TCP窗口扫描(-sW):这种扫描方式检测目标返回的RST数据包的TCP窗口字段。如果目 标端口处于开放状态,这个字段的值将是正值;否则它的值应当是0。

7.TCP Idle扫描(-sI):采用这种技术后,您将通过指定的僵尸主机发送扫描数据包。本机 并不与目标主机直接通信。如果对方网络里有IDS,IDS将认为发起扫描的主机是僵尸主机。

UDP扫描选项

Nmap有多种TCP扫描方式,而UDP扫描仅有一种扫描方式(-sU)。虽然UDP扫描结果没有 TCP扫描结果的可靠度高,但渗透测试人员不能因此而轻视UDP扫描,毕竟UDP端口代表着 可能会有价值的服务端程序。但是UDP扫描的最大问题是性能问题。由于Linux内核限制1秒内最多发送一次ICMP Port Unreachable信息。按照这个速度,对一台主机的65536个UDP端口进行完整扫描,总耗时必 定会超过18个小时。

优化方法主要是:

1.进行并发的UDP扫描;
2.优先扫描常用端口;
3.在防火墙后面扫描;
4.启用--host-timeout选项以跳过响应过慢的主机。

假如我们需要找到目标主机开放了哪些 UDP端口。为提高扫描速度,我们仅扫描 53端口 (DNS)和161端口(SNMP)。

可以使用命令nmap -sU 192.168.1.103 -p 53,161

Python-Nmap

Nmap提供给Python调用的API,方便自定义快速扫描,获取数据结果更加方便。

安装:

pip3 install python-nmap

然后安装nmap并添加到系统环境变量

扫描单个开放端口获取服务

代码:

import nmap
nm = nmap.PortScanner()
ip = '118.24.11.235'
res = nm.scan(ip,ports='1-500')
# 扫面主机的1~500号端口
r = res['scan'][ip]['tcp']
# 获取扫描结果详细数据
for k,v in r.items():print('端口:'+str(k))print('服务:'+v['name'])print('产品:'+v['product'])print('版本:'+v['version'])print('信息:'+v['extrainfo'])print('扫描地址:'+res['scan'][ip]['addresses']['ipv4'])print('扫描命令:'+res['nmap']['command_line'])print('扫描方式:'+res['nmap']['scaninfo']['tcp']['method'])print('主机存活:'+res['nmap']['scanstats']['uphosts'])print('扫描时间:'+res['nmap']['scanstats']['timestr'])print('*'*10)ports = list(res['scan'][ip]['tcp'].keys())
print('开放端口:'+str(ports))

扫描结果:

端口:80
服务:http
产品:nginx
版本:1.15.11
信息:
扫描地址:118.24.11.235
扫描命令:nmap -oX - -p 1-500 -sV 118.24.11.235
扫描方式:syn
主机存活:1
扫描时间:Fri Feb 26 18:16:14 2021
**********
端口:445
服务:microsoft-ds
产品:
版本:
信息:
扫描地址:118.24.11.235
扫描命令:nmap -oX - -p 1-500 -sV 118.24.11.235
扫描方式:syn
主机存活:1
扫描时间:Fri Feb 26 18:16:14 2021
**********
开放端口:[42, 80, 135, 136, 137, 138, 139, 445]

扫描网段信息

代码:

import nmap
nma = nmap.PortScanner()
result = nma.scan(hosts='192.168.1.0/24', arguments='-n -sP -PE')
AliveHost = list(result['scan'].keys())
print('存活主机:{}'.format(AliveHost))
# ['192.168.1.1', '192.168.1.103']
# 获取到网段存活的主机
for k,v in (result['scan']).items():print('当前ip:{}'.format(k))print('地址:'+str(v['addresses']))print('版本:'+str(v['vendor']))print('存活状态:'+v['status']['state'])print('*'*10)

扫描结果:

存活主机:['192.168.1.1', '192.168.1.102', '192.168.1.103', '192.168.1.106']
当前ip:192.168.1.1
地址:{'ipv4': '192.168.1.1', 'mac': '48:8A:D2:C2:94:98'}
版本:{'48:8A:D2:C2:94:98': 'Mercury Communication Technologies'}
存活状态:up
**********
当前ip:192.168.1.102
地址:{'ipv4': '192.168.1.102', 'mac': '38:D2:CA:B5:A9:4E'}
版本:{'38:D2:CA:B5:A9:4E': 'Zhejiang Tmall Technology'}
存活状态:up
**********
当前ip:192.168.1.103
地址:{'ipv4': '192.168.1.103', 'mac': '4A:41:85:3B:5D:27'}
版本:{}
存活状态:up
**********
当前ip:192.168.1.106
地址:{'ipv4': '192.168.1.106'}
版本:{}
存活状态:up
**********

扫描网段并且获取详细信息【较慢】

代码:

import nmap
nm = nmap.PortScanner()
result = nm.scan(hosts='192.168.1.0/24', arguments='-sV -A')
# 耗时比较久
AliveHostCount = result['nmap']['scanstats']['uphosts']
# 获取C段内存活主机数量
print('存活主机数量:{}'.format(AliveHostCount))
scaninfo = result['scan']
# 获取详细扫描结果
for k,v in scaninfo.items():print(k,v)

扫描结果:

存活主机数量:2
192.168.1.1 {'hostnames': [{'name': 'localhost', 'type': 'PTR'}], 'addresses': {'ipv4': '192.168.1.1', 'mac': '48:8A:D2:C2:94:98'}, 'vendor': {'48:8A:D2:C2:........

异步多进程实现及时获取

# coding:utf-8
import nmap,multiprocessing
nm = nmap.PortScannerAsync()
def callback_result(host, scan_result):print(host, scan_result)
if __name__ == '__main__':multiprocessing.freeze_support()nm.scan(hosts='192.168.1.0/24', arguments='-sP', callback=callback_result)while nm.still_scanning():nm.wait(2)

使用生成器及时获取

# coding:utf-8
import nmap
nm = nmap.PortScannerYield()
for progressive_result in nm.scan('192.168.1.0/24', '0-100'):print(progressive_result)

使用内置多线程

# coding:utf-8
import nmap
def scan(ip):nm = nmap.PortScanner()print(nm.scan(ip))
import time
t1 = time.time()
n = nmap.Process(target=scan,args=('192.168.1.0/24',))
n.run()
print('耗时:{}'.format(time.time()-t1))

使用漏扫模块

# coding:utf-8
import nmap
common = '--script vulscan --script-args vulscandb=cve.csv -sV'
nm = nmap.PortScanner()
result = nm.scan(hosts='192.168.200.130',arguments=common)
print(result)
res = result['scan']
for k,v in res.items():print(k)print(v)

IPy

负责对IP处理的一个库

获取网段的IP地址

获取C段

import IPy
ip = IPy.IP('192.168.0.0/24')
print( ip.len())
print(ip[0:10])

返回结果

256
[IP('192.168.0.0'), IP('192.168.0.1'), IP('192.168.0.2'), IP('192.168.0.3'), IP('192.168.0.4'), IP('192.168.0.5'), IP('192.168.0.6'), IP('192.168.0.7'), IP('192.168.0.8'), IP('192.168.0.9')]

获取B段

import IPy
ip = IPy.IP('192.168.0.0/16')
print( ip.len())
print(ip[0:10])

返回结果

65536
[IP('192.168.0.0'), IP('192.168.0.1'), IP('192.168.0.2'), IP('192.168.0.3'), IP('192.168.0.4'), IP('192.168.0.5'), IP('192.168.0.6'), IP('192.168.0.7'), IP('192.168.0.8'), IP('192.168.0.9')]

获取A段

ip_address = '192.0.0.0/8'
ip = IPy.IP(ip_address)
print(len(ip))

返回

16777216

还可以通过这种方式生成

ip = IPy.IP('10.2.32.0-10.2.32.3')

判断包含关系

'10.0.0.1' in IP('10.0.0.0/24')

返回结果

true

判断内网or外网

import IPy
ip_address = '192.168.1.102'
ip = IPy.IP(ip_address)
print(ip.iptype())

内网返回:PRIVATE 外网返回:PUBLIC

Masscan

简单使用

masscan相比nmap之所以快很多,masscan采用了异步传输方式,无状态的扫描方式。nmap需要记录tcp/ip的状态,os能够处理的TCP/IP连接最多为1500左右。

masscan -p0-65535 192.168.1.0/24 --banners --rate 10000

扫描192.168.1.*这个C段的所有主机的所有端口,并获取返回的banner,设置发包量为10000s

masscan --ping 192.168.1.0/24 --rate 10000 #主机存活

扫描192.168.1.*这个C段的所有存活的主机

默认情况下,Masscan扫描速度为每秒100个数据包

masscan -p443 192.168.1.0/24 --banners --heartbleed #--banners 

进行漏洞扫描任务,--heartbleed masscan仅支持该漏洞扫描选项,首先监测端口,软后发送漏洞探测数据包,扫描这个C段443端口对应的心脏滴血漏洞

masscan -p80 192.168.1.0/24 -oX xx.xml (-oJ xx.json -oL xx.list)

扫描192.168.1.*这个C段的的数据,然后结果保存在xx.xml文件中。

使用参数

IP地址范围,有三种有效格式:

1、单独的IPv4地址
2、类似"10.0.0.1-10.0.0.233"的范围地址
3、CIDR地址 类似于"0.0.0.0/0",多个目标可以用都好隔开-p  指定端口进行扫描
--banners 获取banner信息,支持少量的协议
--rate 指定发包的速率
-c,--conf 读取配置文件进行扫描
--echo 将当前的配置重定向到一个配置文件中
-e,--adapter 指定用来发包的网卡接口名称
--adapter-ip 指定发包的IP地址
--adapter-port 指定发包的源端口
--adapter-mac 指定发包的源MAC地址
--router-mac 指定网关的MAC地址
--exclude IP地址范围黑名单,防止masscan扫描
--excludefile 指定IP地址范围黑名单文件
--includefile,-iL 读取一个范围列表进行扫描
--ping 扫描应该包含ICMP回应请求
--append-output 以附加的形式输出到文件
--iflist 列出可用的网络接口,然后退出
--retries 发送重试的次数,以1秒为间隔
--nmap 打印与nmap兼容的相关信息
--http-user-agent 设置user-agent字段的值
--show [open,close] 告诉要显示的端口状态,默认是显示开放端口
--noshow [open,close] 禁用端口状态显示
--pcap 将接收到的数据包以libpcap格式存储
--regress 运行回归测试,测试扫描器是否正常运行
--ttl 指定传出数据包的TTL值,默认为255
--wait 指定发送完包之后的等待时间,默认为10秒
--offline 没有实际的发包,主要用来测试开销
-sL 不执行扫描,主要是生成一个随机地址列表
--readscan 读取从-oB生成的二进制文件,可以转化为XML或者JSON格式
--connection-timeout 抓取banners时指定保持TCP连接的最大秒数,默认是30秒

获取banner

masscan 10.0.0.0/8 -p80 --banners

排除指定文本内的IP

masscan 0.0.0.0/0 -p0-65535 --excludefile exclude.txt

提高运行速度

masscan 0.0.0.0/0 -p0-65535 --max-rate 100000

异常处理

nmap以及masscan都依赖winpcap,扫描的时候,如果安装了多个网卡或者虚拟网卡,则会报错:

'FAIL: failed to detect IP of interface "\\Device\\xxxxxxxxxxxx"\r\n [hint] did you spell the name correctly?\r\n [hint] if it has no IP address, manually set with "--adapter-ip 192.168.100.5"\r\n'

这个时候把所有的虚拟网卡,无线网卡全部禁用,只留下一个网卡就好了。

常用命令搭配

扫描指定IP文件中的地址

./masscan -iL ip.txt -oX result.txt -p1-65535 --banners --rate=10000

其中ip.txt内容为:

1.1.0.0/16
192.168.1.1/24

Masscan-python

masscan-python是Masscan提供给Python调用的API,方便自定义快速扫描,获取数据结果更加方便。

安装命令:

pip3 install python-masscan

如果安装失败,则直接下载安装包即可,下载地址:http://www.langzi.fun/upload/python-masscan-master.rar

下载解压后,使用命令:

python3 setup.py install

即可安装

这个安装的只是masscan的python整理api。你其实还要安装masscan,在巡风扫描器的masscan中下载了win10的编译好的masscan.exe,然后把masscan.exe所在的文件夹加入系统环境变量。cmd下运行masscan.exe提示确实wpacp.dll,网络流量嗅探劫持扫描都依赖这个dll文件,安装nmap,wireshark也都需要这个的,安装就ok了。

常用方法

使用方法如下:

import masscan
mas = masscan.PortScanner()
mas.scan('110.0.0.0',ports='3389,80')
print mas.scan_result

上面代码中ports是可选参数,如果不填的话,默认全端口。返回对象是字典格式,解析这个字典看看结果。

import masscan
mas = masscan.PortScanner()
mas.scan('110.0.0.0')
result = mas.scan_result()
d = result['masscan']
for x in d:print x + ':' + str(d[x])
print d.keys()
print '-'*50d1 = result['scan']
for x in d1:print x + ':' + str(d1[x])print d1.keys()

result字典有两个键,分别是masscan和scan。结构分支如下:

masscan:1. scanstats(一些结果参数)1. timestr(时间)2. uphosts(存活主机数量)3. downhosts(关闭的主机数量)4. totalhosts(总数)5. elapsed(不明白意思)2. command_line(在masscan的参数指令,不重要)scan:1. 110.0.0.0 键就是传入的ip,他下面有多个键1. tcp(tcp方式扫描)1. 3389(开放端口)1. services(服务信息) 2. state(开放情况)3. reason(请求方式)4. reson_ttl(返回长度)2. 80(开放端口)1. services(服务信息) 2. state(开放情况)3. reason(请求方式)4. reson_ttl(返回长度)

这就是传入一个ip,扫描全端口返回的结果,扫描一个ip段返回的数据估计也差不多….

传入一个ip,然后获取所有的开放情况代码如下:

re = result['scan'][ip]['tcp'].keys()

返回对象是一个列表

[5985, 3389, 80]

就是开放的端口,总结一下用法:

import masscan
mas = masscan.PortScanner()
ip = '118.24.11.235'
mas.scan(ip, ports='80,1000-8888',arguments='--max-rate 2000')
# 扫描ip为:118.24.11.235
# 除了单个IP,还能直接扫描C/B段,直接修改传入的参数即可
# 扫描端口为:80,1000-8888
# 额外命令为:--max-rate 2000 设置最大发包量为2000
Results = mas.scan_result['scan']
# 获取扫描结果
for k,v in Results.items():print('当前IP:{}'.format(k))print('开放端口:{}'.format(list(v['tcp'].keys())))

扫描结果:

当前IP:118.24.11.235
开放端口:[5985, 3389, 80]

拓展之端口对应服务识别

对一个IP的开放端口扫描完成后,除去开放的端口数据,还需要识别端口对应的服务,常规的识别方法如下:

  1. 默认的端口对应服务数据库

  2. 对端口进行发起连接,对返回的banner进行指纹识别

  3. Nmap识别开放端口与运行服务

Nmap同样能识别出开放的端口和服务,原理也就是上面说的,许多思路就是利用Masscan高速性快速扫描出开放的端口,然后使用Nmap扫描这些端口,对结果中提取出运行的服务,然后整理结果。

但是按照经验,对端口发起连接识别指纹准确率较高,其次是Nmap识别端口服务,最后再是使用默认的数据库。

端口服务数据库

方法一

整理了一下常见端口对应的服务保存为字典格式:

PortLib={'21': 'ftp', '22': 'ssh', '23': 'telnet', '25': 'smtp', '53': 'dns', '68': 'dhcp', '8080': 'http', '69': 'tftp', '995': 'pop3', '135': 'rpc', '139': 'netbios', '143': 'imap', '443': 'https', '161': 'snmp', '489': 'ldap', '445': 'smb', '465': 'smtps', '512': 'linuxrrpe', '513': 'linuxrrlt', '514': 'linuxrcmd', '873': 'rsync', '993': 'imaps', '1080': 'proxy', '1099': 'javarmi', '1352': 'lotus', '1433': 'mssql', '1521': 'oracle', '1723': 'pptp', '2082': 'cpanel', '2083': 'cpanel', '2181': 'zookeeper', '2222': 'dircetadmin', '2375': 'docker', '2604': 'zebra', '3306': 'mysql', '3312': 'kangle', '3389': 'rdp', '3690': 'svn', '4440': 'rundeck', '4848': 'glassfish', '5432': 'postgresql', '5632': 'pcanywhere', '5900': 'vnc', '5984': 'couchdb', '6082': 'varnish', '6379': 'redis', '9001': 'weblogic', '7778': 'kloxo', '10050': 'zabbix', '8291': 'routeros', '9200': 'elasticsearch', '11211': 'memcached', '27017': 'mongodb', '27018': 'mongodb', '50070': 'hadoop'}

调用方法十分简单,如果开放的端口是 22 ,那么运行的服务就是

print(PortLib.get('22'))

返回结果:

ssh

方法二

对存活的ip解析其功能,如果自定义数据指纹的话,工程量大,并且不易维护。网上刚好有个whatportis的库,可以提供端口对应的常见服务。安装方法如下:

pip3 install whatportis

然后会直接加入环境变量,比如cmd输入 whatportis 3389,会输出:

+---------------+------+----------+---------------+
| Name          | Port | Protocol | Description   |
+---------------+------+----------+---------------+
| ms-wbt-server | 3389 |   tcp    | MS WBT Server |
| ms-wbt-server | 3389 |   udp    | MS WBT Server |
+---------------+------+----------+---------------+

格式化输出依赖pretty库。然而我只想要description的信息啊,详细的api懒得看,直接输入:

>>> import whatportis
>>> print help(whatportis)whatportis - # -*- coding: utf-8 -*-FILEf:\python27\lib\site-packages\whatportis\__init__.pyPACKAGE CONTENTS__main__coreserverFUNCTIONSget_ports(port, like=False)This function creates the SQL query depending on the specified port andthe --like option.:param port: the specified port:param like: the --like option:return: all ports matching the given ``port``:rtype: listDATA__all__ = ['get_ports']

原来类下面有个get_ports()方法,接受一个参数端口,返回对象是列表,如果没有匹配到端口的服务,就返回一个空的列表。所以使用方法如下:

import whatportis
d = whatportis.get_ports('23')
print(d)
if d != []:print(d[0][3])

查看源码后发现可以完全移植一下代码,将whatportis目录下的指纹库文件port.json保存到自己的代码目录下,调用方法代码:

from tinydb import TinyDB, where
from tinydb.storages import JSONStorage
from tinydb.middlewares import CachingMiddleware
from collections import namedtuple
import os
Port = namedtuple("Port", ["name", "port", "protocol", "description"])__BASE_PATH__ = os.path.dirname(os.path.abspath(__file__))
__DATABASE_PATH__ = os.path.join(__BASE_PATH__, 'ports.json')
__DB__ = TinyDB(__DATABASE_PATH__, storage=CachingMiddleware(JSONStorage))def GetPortInfo(port, like=False):"""判断端口服务,传入参数为 字符串类型的数字返回服务名称  'http',没有则返回  '检测失效'"""where_field = "port" if port.isdigit() else "name"if like:ports = __DB__.search(where(where_field).search(port))else:ports = __DB__.search(where(where_field) == port)try:return ports[0]['name']  # flake8: noqa (F812)except:return '识别端口异常'

调用方法十分简单,如果开放的端口是 22 ,那么运行的服务就是

print(GetPortInfo('22'))

返回结果:

ssh

指纹库文件下载地址:http://www.langzi.fun/upload/ports.json

Banner指纹识别

Banner指纹识别:banner 信息来表示欢迎语,其中会包含一些敏感信息,比如不同的端口你请求连接后,返回的Banner是不一样的,所以可以根据这个Banner指纹来断定该端口运行的服务。

在Python使用socket库可以简单的对主机加端口进行访问请求,然后对返回的信息匹配指纹即可,下面代码中的指纹信息是我在GitHub、相关博客收集整理而来,相对全面完善,大家也可以自行补充。

Banner =  {b'http': [b'^HTTP/.*\nServer: Apach', b'^HTTP/.*\nServer: nginx', b'HTTP.*?text/html', b'http.*?</html>'], b'ssh': [b'^SSH-.*openssh', b'^ssh-', b'connection refused by remote host.'], b'netbios': [b'\xc2\x83\x00\x00\x01\xc2\x8f', b'^y\x08.*browse', b'^y\x08.\x00\x00\x00\x00', b'^\x05\x00\r\x03', b'^\x82\x00\x00\x00', b'\x83\x00\x00\x01\x8f'], b'backdoor-fxsvc': [b'^500 Not Loged in'], b'backdoor-shell': [b'^sh[$#]'], b'bachdoor-shell': [b'[a-z]*sh: .* command not found'], b'backdoor-cmdshell': [b'^Microsoft Windows .* Copyright .*>'], b'db2': [b'.*SQLDB2RA', b'.*sqldb2ra'], b'db2jds': [b'^N\x00', b'^n\x00'], b'dell-openmanage': [b'^N\x00\r'], b'finger': [b'finger: GET: ', b'^\r\n\tline\t  user', b'line\t user', b'login name: ', b'login.*name.*tty.*idle', b'^no one logged on', b'^\r\nwelcome', b'^finger:', b'^must provide username', b'finger: get: '], b'ftp': [b'^220 .* UserGate', b'^220.*\n331', b'^220.*\n530', b'^220.*ftp', b'^220 .* microsoft .* ftp', b'^220 inactivity timer', b'^220 .* usergate', b'^220.*filezilla server', b'^220-', b'^220.*?ftp', b'^220.*?filezilla'], b'http-iis': [b'^<h1>Bad Request .Invalid URL.</h1>'], b'http-jserv': [b'^HTTP/.*Cookie.*JServSessionId'], b'http-tomcat': [b'.*Servlet-Engine'], b'http-weblogic': [b'^HTTP/.*Cookie.*WebLogicSession'], b'http-vnc': [b'^HTTP/.*RealVNC/'], b'ldap': [b'^0E', b'^0\x0c\x02\x01\x01a', b'^02\x02\x01', b'^03\x02\x01', b'^08\x02\x01', b'^0\x84', b'^0e'], b'smb': [b'^\x00\x00\x00.\xc3\xbfSMBr\x00\x00\x00\x00.*', b'^\x00\x00\x00.\xffsmbr\x00\x00\x00\x00.*', b'^\x83\x00\x00\x01\x8f'], b'msrdp': [b'^\x03\x00\x00\x0b\x06\xc3\x90\x00\x004\x12\x00'], b'msrdp-proxy': [b'^nmproxy: Procotol byte is not 8\n$'], b'msrpc': [b'\x05\x00\r\x03\x10\x00\x00\x00\x18\x00\x00\x00....\x04\x00\x01\x05\x00\x00\x00\x00$', b'^\x05\x00\r\x03\x10\x00\x00\x00\x18\x00\x00\x00\x00\x00', b'\x05\x00\r\x03\x10\x00\x00\x00\x18\x00\x00\x00....\x04\x00\x01\x05\x00\x00\x00\x00$'], b'mssql': [b';MSSQLSERVER;', b'^\x05n\x00', b'^\x04\x01', b';mssqlserver;', b'mssqlserver'], b'telnet': [b'^\xc3\xbf\xc3\xbe', b'telnet', b'^\xff[\xfa-\xff]', b'^\r\n%connection closed by remote host!\x00$'], b'mysql': [b"whost '", b'mysql_native_password', b'^\x19\x00\x00\x00\n', b'^,\x00\x00\x00\n', b"hhost '", b"khost '", b'mysqladmin', b"whost '", b'^[.*]\x00\x00\x00\n.*?\x00', b'this mysql server', b'mariadb server', b'\x00\x00\x00\xffj\x04host'], b'mysql-blocked': [b'^\\(\x00\x00'], b'mysql-secured': [b'this MySQL'], b'mongodb': [b'^.*version.....([\\.\\d]+)', b'mongodb'], b'nagiosd': [b'Sorry, you \\(.*are not among the allowed hosts...', b'sorry, you \\(.*are not among the allowed hosts...'], b'nessus': [b'< NTP 1.2 >\nUser:', b'< ntp 1.2 >\nuser:'], b'oracle-tns-listener': [b'\\(ADDRESS=\\(PROTOCOL=', b'\\(error_stack=\\(error=\\(code=', b'\\(address=\\(protocol='], b'oracle-dbsnmp': [b'^\x00\x0c\x00\x00\x04\x00\x00\x00\x00', b'^\x00\x0c\x00\x00\x04\x00\x00\x00\x00'], b'oracle-https': [b'^220- ora', b'^220- ora'], b'oracle-rmi': [b'^N\x00\t'], b'postgres': [b'^EFATAL'], b'rlogin': [b'^\x01Permission denied.\n', b'login: ', b'rlogind: ', b'^\x01permission denied.\n'], b'rpc-nfs': [b'^\x02\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00', b'^\x02\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00'], b'rpc': [b'^\xc2\x80\x00\x00', b'\x01\x86\xa0', b'\x03\x9beb\x00\x00\x00\x01', b'^\x80\x00\x00'], b'rsync': [b'^@RSYNCD:.*', b'^@rsyncd:', b'@rsyncd:'], b'smux': [b'^A\x01\x02\x00', b'^a\x01\x02\x00'], b'snmp-public': [b'public\xc2\xa2', b'public\xa2'], b'snmp': [b'A\x01\x02', b'a\x01\x02'], b'socks': [b'^\x05[\x00-\x08]\x00', b'^\x05[\x00-\x08]\x00'], b'ssl': [b'^\x16\x03\x00..\x02...\x03\x00', b'^..\x04\x00.\x00\x02', b'^\x16\x03\x01..\x02...\x03\x01', b'^\x16\x03\x00..\x02...\x03\x00', b'ssl.*get_client_hello', b'^-err .*tls_start_servertls', b'^\x16\x03\x00\x00j\x02\x00\x00f\x03\x00', b'^\x16\x03\x00..\x02\x00\x00f\x03\x00', b'^\x15\x03\x00\x00\x02\x02\\.*', b'^\x16\x03\x01..\x02...\x03\x01', b'^\x16\x03\x00..\x02...\x03\x00'], b'sybase': [b'^\x04\x01\x00', b'^\x04\x01\x00'], b'tftp': [b'^\x00[\x03\x05]\x00', b'^\x00[\x03\x05]\x00'], b'uucp': [b'^login: password: ', b'^login: password: '], b'vnc': [b'^RFB.*', b'^rfb'], b'webmin': [b'^0\\.0\\.0\\.0:.*:[0-9]', b'.*miniserv', b'^0\\.0\\.0\\.0:.*:[0-9]'], b'websphere-javaw': [b'^\x15\x00\x00\x00\x02\x02\n', b'^\x15\x00\x00\x00\x02\x02\n'], b'xmpp': [b"^\&lt;\\?xml version='1.0'\\?\\&gt;"], b'backdoor': [b'^500 not loged in', b'get: command', b'sh: get:', b'^bash[$#]', b'^sh[$#]', b'^microsoft windows'], b'bachdoor': [b'*sh: .* command not found'], b'rdp': [b'^\x00\x01\x00.*?\r\n\r\n$', b'^\x03\x00\x00\x0b', b'^\x03\x00\x00\x11', b'^\x03\x00\x00\x0b\x06\xd0\x00\x00\x12.\x00$', b'^\x03\x00\x00\x17\x08\x02\x00\x00z~\x00\x0b\x05\x05@\x06\x00\x08\x91j\x00\x02x$', b'^\x03\x00\x00\x11\x08\x02..}\x08\x03\x00\x00\xdf\x14\x01\x01$', b'^\x03\x00\x00\x0b\x06\xd0\x00\x00\x03.\x00$', b'^\x03\x00\x00\x0b\x06\xd0\x00\x00\x00\x00\x00', b'^\x03\x00\x00\x0e\t\xd0\x00\x00\x00[\x02\xa1]\x00\xc0\x01\n$', b'^\x03\x00\x00\x0b\x06\xd0\x00\x004\x12\x00'], b'rdp-proxy': [b'^nmproxy: procotol byte is not 8\n$'], b'rmi': [b'\x00\x00\x00vinva', b'^n\x00\t'], b'postgresql': [b'invalid packet length', b'^efatal'], b'imap': [b'^\\* ok.*?imap'], b'pop': [b'^\\+ok.*?'], b'smtp': [b'^220.*?smtp', b'^554 smtp'], b'rtsp': [b'^rtsp/'], b'sip': [b'^sip/'], b'nntp': [b'^200 nntp'], b'sccp': [b'^\x01\x00\x00\x00$'], b'squid': [b'x-squid-error'], b'vmware': [b'vmware'], b'iscsi': [b'\x00\x02\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'], b'redis': [b'^-err unknown command', b'^-err wrong number of arguments', b'^-denied redis is running'], b'memcache': [b'^error\r\n'], b'websocket': [b'server: websocket'], b'https': [b'instead use the https scheme to accesshttps', b'http request to an https server', b'location: https'], b'svn': [b'^\\( success \\( 2 2 \\( \\) \\( edit-pipeline svndiff1'], b'dubbo': [b'^unsupported command'], b'elasticsearch': [b'cluster_name.*elasticsearch'], b'rabbitmq': [b'^amqp\x00\x00\t\x01'], b'zookeeper': [b'^zookeeper version: ']}def GetBannerServer(ip, port):try:s = socket.socket()s.settimeout(5)s.connect((ip, int(port)))s.send(b'langzi\r\n')SocketRecv = (s.recv(1024))s.close()for k, v in Banner.items():for b in v:banner = re.search(b, SocketRecv, re.I | re.S)if banner:return k.decode()return '获取失败'except Exception as e:return '获取失败'finally:s.close()
print(GetBannerServer(ip='118.24.11.235',port='80'))

返回结果:

http

拓展

LangNetworkTopologys是一款调用MASSCAN对内网主机进行如下任务,完成内网主机资产快速获取的工具,具有如下功能:

  1. 开放端口扫描

  2. 运行服务检测,指纹识别

  3. 开放端口二次复检

  4. 主机部署网站探测

  5. 自动生成扫描结果报表

可以参考具体代码,了解端口扫描与运行服务获取的大致思路

具体代码地址:

https://github.com/LangziFun/LangNetworkTopologys/blob/master/Project/LangNetworkTopology3/Lib/source/LangNetworkTopology3.py

欢迎关注公众号:【安全研发】获取更多相关工具,课程,资料分享哦~

NMAP Masscan python识别端口运行服务 常用命令速查表相关推荐

  1. 全套Python数据分析常用命令速查表!PDF文档限时分享

    当下利用python学习数据分析的热度越来越高,对于很多新手而言,大量要学习的库和工具的命令繁杂,用起来不是很顺手. 今天给大家分享一份python数据分析常用命令速查表. 一共6张表,包括:Jupy ...

  2. Git 常用命令速查表(图文+表格)

    一. Git 常用命令速查 git branch 查看本地所有分支 git status 查看当前状态  git commit 提交  git branch -a 查看所有的分支 git branch ...

  3. Git 常用命令速查表(图文+表格)【转】

    转自:http://www.jb51.net/article/55442.htm 一. Git 常用命令速查 git branch 查看本地所有分支 git status 查看当前状态  git co ...

  4. 转收藏:Git常用命令速查表

    一. Git 常用命令速查 git branch 查看本地所有分支 git status 查看当前状态  git commit 提交  git branch -a 查看所有的分支 git branch ...

  5. 红队常用命令速查表-常见工具使用命令

    command 收集渗透中会用到的常用命令 . 更新时间:2022.2.27 Table of Contents command nmap 存活主机 bypass gobuster dirsearch ...

  6. PostgreSQL 常用命令速查表

    文章目录 连接服务器 查看帮助 查看连接 查看版本 配置参数 退出客户端 角色.用户和组 创建角色 查看角色 修改密码 设置密码失效时间 用户授权 查看权限 撤销权限 设置当前角色 删除角色 数据库和 ...

  7. git常用命令速查表【转】

    [作者]张昺华 [出处]http://www.cnblogs.com/sky-heaven/ [博客园] http://www.cnblogs.com/sky-heaven/ [新浪博客] http: ...

  8. [No0000176]Git常用命令速查表(收藏大全)

    名词 master: 默认开发分支 origin: 默认远程版本库 Index / Stage:暂存区 Workspace:工作区 Repository:仓库区(或本地仓库) Remote:远程仓库 ...

  9. Git常用命令速查表

    转载于:https://www.cnblogs.com/ZengYunChun/p/5680870.html

  10. MySQL 常用命令速查表:日常开发、求职面试必备良方!

    备注:PDF 版本点此下载. 文章目录 连接服务器 查看帮助 查看连接 退出连接 账户和权限 创建用户 查看用户 修改密码 锁定/解锁用户 用户授权 查看权限 撤销权限 管理角色 删除用户 管理数据库 ...

最新文章

  1. HTTP状态 500之java.lang.StackOverflowErro
  2. 制药企业正在基于AI与基因测序发现真菌更多药用价值
  3. python开发需要掌握哪些知识-研究深度学习的开发者,需要对 Python 掌握哪些知识?...
  4. Codeforces 1012A Photo of The Sky
  5. JAVA volatile关键字正确使用姿势
  6. 前端学习(2352):view组件的使用
  7. Redis锁的简单应用
  8. 2018-03-28 Linux学习
  9. python3常用内置函数总结
  10. iOS开发之tableHeaderView的那些坑
  11. linux hdfs授予文件夹权限,修修改hdfs上的文件所属用户、所属组等读写执行控制权限...
  12. erp采购总监个人总结_ERP采购总监总结
  13. MSN账号被盗,成功找回记
  14. 道哥亲笔:谈谈为什么要做弹性安全网络
  15. “AI复活了我的妻子,但我决定跟她说再见了”
  16. matlab出图时汉字都变成方框,linux下Matlab 2020中文字体方框问题解决方法
  17. eating的中文意思_eating是什么意思_eating的翻译_音标_读音_用法_例句_爱词霸在线词典...
  18. 《HTML与CSS网站设计实践之旅》读书笔记
  19. 国际数据保护日,数据安全谁来守护?
  20. 王阳明:人心本是光明之镜 奈何因私欲黯淡无光

热门文章

  1. 手机业务的趋势:移动互联
  2. 2个74151实现16位数据选择器以及在Multisim的演示
  3. 制作u盘winpe启动盘_微PE工具箱 (WePE),绿色纯净的WinPE启动盘/U盘重装系统工具...
  4. 以MQL5 编写的EA 交易程序的测试与优化指南
  5. php微信聊天机器人_使用图灵机器人api搭建微信聊天机器人php实现
  6. 【Blender】UV贴图相关学习
  7. matlab中使用xlsread导入excel数据
  8. 二阶带阻有源滤波器设计与仿真测试
  9. 使用JavaScript打开Chrome的设置页面
  10. SSIM结构相似性算法