浅谈扫描器原理

安全 · 2021-11-24

一。我们为什么要用扫描器

​ 扫描器是检测远程或本地系统安全脆弱性的软件;通过与目标主机TCP/IP端口建立连接和并请求某些服务(如TELNET、FTP等),记录目标主机的应答,搜集目标主机相关信息(如匿名用户是否可以登录等),从而发现目标主机某些内在的安全弱点。

  扫描器的重要性在于把极为烦琐的安全检测,通过程序来自动完成,这不仅减轻管理者的工作,而且缩短了检测时间,使问题发现更快。当然,也可以认为扫描器是一种网络安全性评估软件。一般而言,扫描器可以快速、深入地对网络或目标主机进行评估。

二。我们能接触到哪些扫描器

可以按照功能分类为那种单一功能扫描器

  • 端口扫描器
  • 子域名扫描器
  • 旁站扫描器
  • 简单漏洞扫描器
  • 内网扫描器

另外的一些大型扫描器其实就是把这些功能进行集成

三。主流开源扫描器简单介绍

Nmap

https://nmap.org/

Nmap,也就是Network Mapper,最早是Linux下的网络扫描和嗅探工具包。其基本功能有三个,一是探测一组主机是否在线;其次是扫描 主机端口,嗅探所提供的网络服务;还可以推断主机所用的操作系统 。Nmap可用于扫描仅有两个节点的LAN,直至500个节点以上的网络。Nmap 还允许用户定制扫描技巧。通常,一个简单的使用ICMP协议的ping操作可以满足一般需求;也可以深入探测UDP或者TCP端口,直至主机所 使用的操作系统;还可以将所有探测结果记录到各种格式的日志中, 供进一步分析操作。

四。样例分析:子域名扫描器

思路:不与目标机直接进行扫描,而进行ping扫描,使用字典内的三级域名库与用户输入的一二级域名(主域名)进行拼接形成一个完成的域名,进行解析操作,如果DNS服务器有返回该域名的解析记录则证明这个域名存在,若返回找不带主机则证明该域名不存在。从而达到子域名扫描的功能。

具体程序内容分析:

#scanner.py
import socket
import sys
import time

#传入参数为主域名(一二级域名)
domain_main = sys.argv[1]

print("\033[1;32;43m %s \033[0m" % ("program starting..."))
print("")
time.sleep(1)

print("   _____       _         _                       _          _____                                 ")
print("  / ____|     | |       | |                     (_)        / ____|                                ")
print(" | (___  _   _| |__   __| | ___  _ __ ___   __ _ _ _ __   | (___   ___ __ _ _ __  _ __   ___ _ __ ")
print("  \___ \| | | | '_ \ / _` |/ _ \| '_ ` _ \ / _` | | '_ \   \___ \ / __/ _` | '_ \| '_ \ / _ \ '__|")
print("  ____) | |_| | |_) | (_| | (_) | | | | | | (_| | | | | |  ____) | (_| (_| | | | | | | |  __/ |   ")
print(" |_____/ \__,_|_.__/ \__,_|\___/|_| |_| |_|\__,_|_|_| |_| |_____/ \___\__,_|_| |_|_| |_|\___|_|   ")
print("                                                                                                  ")
print("             Power By Rther      2021/11/14       copyright@2021                ")
print("")
print("")

time.sleep(1)

print("The scanner is working now , please wait .")
print("")
print("\033[1;33;40m %s \033[0m" % ("Here is thr result:"))

time.sleep(1)

with open('domain.txt','r') as stringIO:   #打开并读取字典内容
    for i in stringIO:
        i = i.strip()
        domain = i + '.'+domain_main   #与字典内字符拼接组成完整域名
        time.sleep(0.2)   #线程控制
        try:
            ip = socket.gethostbyname(domain)      #获取目标域名IP
            print("\033[1;32;40m %s \033[0m" % (domain+'   '+"ip地址:"+ip))
        except Exception as e:
            pass    #占位补全语句,即不抛出错误

print("All works is done !")
print("\033[0;33;40m注意:扫描结果并非最终结果,请与网站实际情况相结合!!!\033[0m")

其实扫出来的结果并不是最终结果,有的域名是僵尸域名,他能解析,能访问,但是没有任何内容,那这样的域名网站对我们来说也是没有任何意义的

五。样例分析:TCP端口扫描器

TCP端口扫描器的原理是尝试与目标主机进行三次握手连接,客户端先发送一个SYN=1请求,若服务器端该端口运行有基于TCP的服务,那么服务器就会响应这个请求,返回SYN=1和ACK=1,反之,若没有,那么服务器要么就让防火墙拦下来,要么就是发回来ACK=1和RST=1,就代表reset,无法完成三次握手连接,由于现在对公网服务器的服务器一般都有防火墙,会屏蔽开放策略组以外的端口请求,所以第一种情况居多,我们就要设置一个超时检测,提高效率,以免挂起太多服务或者引发TCP泛洪。

代码分析:

from socket import *
import threading

lock = threading.Lock()
openNum = 0
threads = []

def portScanner(host,port):
    global openNum
    try:
        s = socket(AF_INET,SOCK_STREAM)
        s.connect((host,port))
        lock.acquire()
        openNum+=1
        print("\033[1;32;40m %s \033[0m" % ('[+] %d open' % port))
        lock.release()
        s.close()
    except:
        pass

def main():
    setdefaulttimeout(1)
    ip = input('please enter your host: ')
    for p in range(1,4000):
        t = threading.Thread(target=portScanner,args=(ip,p))
        threads.append(t)
        t.start()     

    for t in threads:
        t.join()

    print('[+] The scan is complete!')
    print('[+] A total of %d open port ' % (openNum))

if __name__ == '__main__':
    main()

当然,一样的,有可能我们扫到他开放的端口,但是这个端口上啥玩楞也没跑,就有个建联和监听,那咱们也没辙,得手动去排除。

六。样例分析:局域网资源扫描器

局域网的扫描器就有很多讲究了,可以运用到内网打点这个上面,主要用途就是扫描内网中存活的主机,那些主机对内网开放服务的端口。有目标了咱们才好去揍人。

代码分析:

import socket
 
def main():
    ip_start = input('请输入开始的IP地址(默认为本机IP):')
    if ip_start == '':
        ip_start = socket.gethostbyname(socket.gethostname())
        ip_end = socket.gethostbyname(socket.gethostname())
    else:
        ip_end = input('请输入结束IP(默认为本机IP):')
        if ip_end == '':
            ip_end = socket.gethostbyname(socket.gethostname())
    s = input('请输入目标主机端口,(默认扫描常用端口)')
    if s == '':
        portlist = [21,22,23,80,135,139,445,1433,1502,3306,3389,8080,9015]
    else:
        startport = int(s)
        s = input('请输入目标主机结束端口:(默认:65535)')
        if s =='':
            endport = 65535
        else:
            endport = int(s)
        portlist = [i for i in range(startport,endport+1)]
    pre_ip='.'.join(ip_start.split('.')[:-1])
    start=int(ip_start.split('.')[-1])
    end=int(ip_end.split('.')[-1])
    for i in range(start,end+1):
        ip = pre_ip+'.'+str(i)
        for port in portlist:
            try:
                sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
                sk.settimeout(0.1)
                sk.connect((ip,port))
                sk.settimeout(None)
                print('Server %s port %d ok!'%(ip,port))
                sk.close()
                #结果保存在文件中
                f = open("IP_Port.txt",'a')
                f.write(ip+' : '+str(port)+'\n')
                f.close()
            except Exception:
                # print('Server %s port %d Not ok!'%(ip,port))
                # print('*',end=' ')
                pass
 
if __name__ == '__main__':
    main()
    print("ALL done!")
Theme Jasmine by Kent Liao