1-测试 - 服务识别

about

在渗透测试过程中,服务识别是一个很重要的环节,如果能识别出目标主机的服务、版本等信息,对于后续的渗透测试有重要的帮助。
对于入侵者来说,发现这些运行在目标上的服务,就可以利用这些软件上的漏洞入侵目标,对于网络安全的维护者来说,也可以提前发现系统的漏洞,从而预防这些入侵行为。

很多扫描工具都采用了一种十分简单的方式,就是根据端口来判断服务类型,因为通常常见的服务都会运行在固定的端口上,如下面的表中,列举了常见的服务和所占用的端口。

文件共享服务端口:

端口号 说明 作用
21/22/69 FTP/TFTP 允许匿名上传、下载、破解和嗅探攻击
2049 NFS服务 配置不当
139 Samba服务 破解、未授权访问、远程代码执行
389 LDAP(目录访问协议) 注入、允许匿名访问、使用弱口令

远程连接服务端口:

端口号 说明 作用
22 SSH远程连接 破解、SSH隧道及内网代理转发、文件传输
23 Telnet远程连接 破解、嗅探、弱口令
3389 Rdp远程桌面连接 Shift后门(需要Windows service 2003以下的系统)、破解
5900 VNC 弱口令破解
5632 PyAnywhere 抓密码、代码执行

Web应用服务端口:

端口号 说明 作用
80/443/8080 常见Web服务端口 Web攻击、破解、服务器版本漏洞
7001/7002 WebLogic控制台 Java反序列化、弱口令
8080/8089 Jboss/Resin/Jetty/Jenkins 反序列化、控制台弱口令
9090 WebSphere控制台 Java反序列化、弱口令
4848 ClassFish控制台 弱口令
1352 Lotus Domino邮件服务 弱口令、信息泄露、破解
10000 Webmin-Web控制面板 弱口令

数据库服务端口:

端口号 说明 作用
3306 MySQL 注入、提权、破解
1433 MSSQL 注入、提权、SA弱口令、破解
1521 Oracle TNS破解、注入、反弹shell
5432 PostgreSQL 破解、注入、弱口令
27017/27018 MongoDB 破解、未授权访问
6379 Redis 可尝试未授权访问、弱口令破解
5000 SysBase/DB2 破解、注入

邮件服务端口:

端口号 说明 作用
25 SMTP邮件服务 邮件伪造
110 POP3协议 破解、嗅探
143 IMAP协议 破解

网络常见协议端口:

端口号 说明 作用
53 DNS域名系统 允许区域传送、DNS劫持、缓存投毒、欺骗
67/68 DHCP服务 劫持、欺骗
161 SNMP协议 破解、搜集目标内网信息

特殊服务端口:

端口号 说明 作用
2181 Zookeeper服务 未授权访问
8069 Zabbix服务 远程执行、SQL注入
9200/9300 Elasticsearch 远程执行
11211 Memcache服务 未授权访问
512/513/514 Linux Rexec服务 破解、Rlogin登录
873 Rsync服务 匿名访问、文件上传
3690 SVN服务 SVN泄露、未授权访问
50000 SAP Management Console 远程执行

了解了常见的服务及所占端口号,就可以向目标开放的端口发送探针数据包,根据目标主机返回的banner信息与存储总结的banner信息进行对比,进而确定运行的服务类型。
著名的nmap扫描工具就是采用这种方法,它包含一个十分强大的banner库,而且这个库仍然在不断的完善中。
接下来,就按照上面介绍的思路来编写对目标服务进行扫描的程序。

手动实现

centos7.3 + python3.6.8

思路:

  1. 使用socket确认指定的host:port是否开放
  2. 如果是开放端口,则发送探测信息,获取返回的banner信息
  3. 对返回的banner信息去指纹库进行匹配,识别服务类型

具体代码如下:

#!/bin/bash
# -*- coding: utf-8 -*-
# @Time    : 2020/12/9 9:56
# @Author  : 张开
# File      : service_idt.py


import re
import socket
from argparse import ArgumentParser
from os import cpu_count
from concurrent.futures import ThreadPoolExecutor

# banner指纹库,用于匹配开放端口的服务类型,可以自行扩展,该库越大匹配精度越高
SIGNS = (
    # 协议 版本 关键字
    b'FTP|FTP|^220.*FTP',
    b'MySQL|MySQL|mysql_native_password',
    b'oracle-https|^220- ora',
    b'Telnet|Telnet|Telnet',
    b'Telnet|Telnet|^\r\n%connection closed by remote host !\x00$',
    b'VNC|VNC|^RFB',
    b'IMAP|IMAP|^\* OK.*?IMAP',
    b'POP|POP|^\+OK.*?',
    b'SMTP|SMTP|^220.*?SMTP',
    b'Kangle|Kangle|HTTP.*Kangle',
    b'SMTP|SMTP|^554 SMTP',
    b'SSH|SSH|^SSH-',
    b'HTTPS|HTTPS|Location: https',
    b'HTTP|HTTP|HTTP/1.1',
    b'HTTP|HTTP|HTTP/1.0',
)


def regex(response, port, host):
    """
    利用re.search将返回的banner信息与SIGNS包含的指纹信息进行正则匹配
    如果匹配到了,就输出该端口和识别结果,如 [3306] open MySQL
    如果没有匹配到,说明SIGNS指纹库没有记录该服务,输出端口和Unrecognized,表示没有识别出来服务类型
    """
    # 首先判断判断探测是否被拒绝
    if re.search(b'<title>502 Bad Gateway', response):
        console = "Service failed to access!!!"
    # 循环指纹库进行匹配,匹配到就打印匹配结果,并不在往下进行匹配
    for pattern in SIGNS:
        pattern = pattern.split(b'|')
        if re.search(pattern[-1], response, re.IGNORECASE):
            console = "[{}:{}] open {}".format(host, port, pattern[1].decode())
            break
    # 如果循环完整个指纹库,也没有匹配上,说明该开放端口没有识别出来服务类型
    else:
        console = "[{}:{}] open {}".format(host, port, 'Unrecognized')
    print(console)


def send_msg(host, port):
    """
    首先调用socket.connect_ex探测目标主机端口是否开放,如果端口开放,则利用sock.sendall将PROBE探针发送给目标端口
    并用sock.recv接收返回的指纹信息
    再将指纹信息交给regex进行指纹匹配识别服务类型
    """
    PROBE = 'GET / HTTP/1.0\r\n\r\n'
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(10)
    result = sock.connect_ex((host, port))
    if result == 0:
        try:
            sock.sendall(PROBE.encode())
            response = sock.recv(512)
            if response:
                regex(response, port, host)
        except (ConnectionResetError, socket.timeout) as e:
            print('[{}:{}] detect error!! {}'.format(host, port, e))
    sock.close()


def main(args):
    """
    从args中读取port端口范围,判断是单个端口还是范围端口,然后将端口存储到临时的列表中
    使用线程池来处理大量的端口
    """
    port_list = []
    print('host:{} port: {}'.format(args.host, args.port))
    if '-' in args.port:
        startPort, endPort = args.port.split('-')
        for i in range(int(startPort), int(endPort) + 1):
            port_list.append(int(i))
    else:
        # 如果是单个端口,没有必要使用线程池
        send_msg(args.host, int(args.port))
        return

    # 为了性能考虑,如果端口数量小于cpu_count() * 5, 线程池中线程的数量等于端口的数量
    if len(port_list) <= args.threadNum:
        threadNum = len(port_list)
    else:
        # 否则线程池中线程的数量等于cpu_count() * 5
        threadNum = args.threadNum
    t = ThreadPoolExecutor(threadNum)
    for i in port_list:
        t.submit(send_msg, args.host, i)


if __name__ == '__main__':
    try:
        parse = ArgumentParser()
        parse.add_argument('--host', dest='host', default='127.0.0.1', type=str, help='获取host')
        parse.add_argument('--port', dest='port', default="900-1000", type=str, help='获取port')
        parse.add_argument('--threadNum', dest='threadNum', default=cpu_count() * 5, type=str, help='获取port')
        args = parse.parse_args()
        main(args)
    except Exception as e:
        print(e)
    
    
    """
    [root@cs tmp]# python3 service_idt.py --port 1-20000
    host:127.0.0.1 port: 1-20000
    [127.0.0.1:21] open FTP
    [127.0.0.1:25] open SMTP
    [127.0.0.1:22] open SSH
    [127.0.0.1:3306] open MySQL
    [127.0.0.1:5672] open Unrecognized
    [127.0.0.1:5676] open Unrecognized
    [127.0.0.1:5674] detect error!! [Errno 104] Connection reset by peer
    [127.0.0.1:5675] detect error!! [Errno 104] Connection reset by peer
    [127.0.0.1:5673] open Unrecognized
    [127.0.0.1:6379] open Unrecognized
    [127.0.0.1:15672] open HTTP
    [127.0.0.1:15675] detect error!! [Errno 104] Connection reset by peer
    [127.0.0.1:15674] detect error!! [Errno 104] Connection reset by peer
    [127.0.0.1:15676] open HTTP
    [127.0.0.1:15673] open HTTP
    """

PS:windows环境代码运行很慢,Linux系统就很快了.....

使用nmap模块实现

centos7.3 + python3.6.8
nmap模块的安装及使用:https://www.cnblogs.com/Neeo/articles/14105947.html

import nmap3
nmap = nmap3.Nmap()
nmap.scan_top_ports("127.0.0.1")
"""
{
	'127.0.0.1': [{
		'host': '127.0.0.1',
		'protocol': 'tcp',
		'portid': '21',
		'state': 'open',
		'reason': 'syn-ack',
		'reason_ttl': '64',
		'service': {
			'name': 'ftp',
			'method': 'table',
			'conf': '3'
		}
	}, {
		'host': '127.0.0.1',
		'protocol': 'tcp',
		'portid': '22',
		'state': 'open',
		'reason': 'syn-ack',
		'reason_ttl': '64',
		'service': {
			'name': 'ssh',
			'method': 'table',
			'conf': '3'
		}
	}, {
		'host': '127.0.0.1',
		'protocol': 'tcp',
		'portid': '23',
		'state': 'closed',
		'reason': 'reset',
		'reason_ttl': '64',
		'service': {
			'name': 'telnet',
			'method': 'table',
			'conf': '3'
		}
	}, {
		'host': '127.0.0.1',
		'protocol': 'tcp',
		'portid': '25',
		'state': 'open',
		'reason': 'syn-ack',
		'reason_ttl': '64',
		'service': {
			'name': 'smtp',
			'method': 'table',
			'conf': '3'
		}
	}, {
		'host': '127.0.0.1',
		'protocol': 'tcp',
		'portid': '80',
		'state': 'closed',
		'reason': 'reset',
		'reason_ttl': '64',
		'service': {
			'name': 'http',
			'method': 'table',
			'conf': '3'
		}
	}, {
		'host': '127.0.0.1',
		'protocol': 'tcp',
		'portid': '110',
		'state': 'closed',
		'reason': 'reset',
		'reason_ttl': '64',
		'service': {
			'name': 'pop3',
			'method': 'table',
			'conf': '3'
		}
	}, {
		'host': '127.0.0.1',
		'protocol': 'tcp',
		'portid': '139',
		'state': 'closed',
		'reason': 'reset',
		'reason_ttl': '64',
		'service': {
			'name': 'netbios-ssn',
			'method': 'table',
			'conf': '3'
		}
	}, {
		'host': '127.0.0.1',
		'protocol': 'tcp',
		'portid': '443',
		'state': 'closed',
		'reason': 'reset',
		'reason_ttl': '64',
		'service': {
			'name': 'https',
			'method': 'table',
			'conf': '3'
		}
	}, {
		'host': '127.0.0.1',
		'protocol': 'tcp',
		'portid': '445',
		'state': 'closed',
		'reason': 'reset',
		'reason_ttl': '64',
		'service': {
			'name': 'microsoft-ds',
			'method': 'table',
			'conf': '3'
		}
	}, {
		'host': '127.0.0.1',
		'protocol': 'tcp',
		'portid': '3389',
		'state': 'closed',
		'reason': 'reset',
		'reason_ttl': '64',
		'service': {
			'name': 'ms-wbt-server',
			'method': 'table',
			'conf': '3'
		}
	}],
	'runtime': {
		'time': '1607490186',
		'timestr': 'Wed Dec  9 13:03:06 2020',
		'summary': 'Nmap done at Wed Dec  9 13:03:06 2020; 1 IP address (1 host up) scanned in 0.07 seconds',
		'elapsed': '0.07',
		'exit': 'success'
	},
	'stats': {
		'scanner': 'nmap',
		'args': '/usr/bin/nmap -oX - --top-ports 10 127.0.0.1',
		'start': '1607490186',
		'startstr': 'Wed Dec  9 13:03:06 2020',
		'version': '7.91',
		'xmloutputversion': '1.05'
	}
}
"""
posted @ 2020-12-08 22:10  听雨危楼  阅读(265)  评论(0编辑  收藏  举报