美文网首页Web攻防
浅谈端口渗透那些事

浅谈端口渗透那些事

作者: book4yi | 来源:发表于2020-07-21 11:14 被阅读0次

    前期准备


    通过扫描端口快速发现目标薄弱点,在这之前,我们得准备好端口扫描工具。
    我接触的扫描工具也不多,常用的端口扫描工具有:

    nmap+masscan、御剑端口扫描工具2020

    御剑端口扫描似乎不会显示协议,仅凭端口号判断不够精准,这时我们可以再用nmap的-sV识别具体服务。该工具主要用于快速扫描发现

    在挖掘SRC的过程中,往往需要对整个C段进行端口扫描,这时我们对扫描速度的要求没那么高,可以追求更高的精确度。我们可以结合masscan的扫描速度和nmap的端口识别功能写一个脚本,采用同步多线程,线程数默认为5,masscan扫描速度默认为100(可自行调整),我个人觉得速度100就基本不会出现遗漏的端口,速度越快越容易遗漏,我自己写了个demo,大佬轻喷:

    # -*- coding: UTF-8 -*-
    import queue
    import nmap
    import datetime
    import threading
    import json
    import os
    import urllib3
    import subprocess
    import sys
    import click
    
    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
    
    lock = threading.Lock()
    final_domains = set()
    insert = set()
    ports = []
    bad_ips = []
    
    
    class PortScan(threading.Thread):
        def __init__(self, queue):
            threading.Thread.__init__(self)
            self._queue = queue
        
        def run(self):
            while not self._queue.empty():
                scan_ip = self._queue.get()
                try:
                    portscan(scan_ip)
                except Exception as e:
                    print('run:', str(e))
                    pass
    
    
    # 调用masscan
    def portscan(scan_ip):
        global count
        temp_ports = []  # 设定一个临时端口列表
        name = scan_ip + '.json'
        command = 'masscan.exe ' + scan_ip +' -p21,22,23,25,53,67,68,80,81,82,83,84,85,86,87,88,89,110,139,143,161,300,' \
            '389,443,445,465,512,513,514,591,593,832,837,873,888,901,981,993,1010,1080,1100,1241,1311,1352,1433,1434,' \
            '1521,1527,1582,1583,1723,1944,2049,2082,2082,2086,2087,2095,2096,2181,2222,2301,2375,2480,3000,3128,3306,' \
            '3333,3389,4000,4001,4002,4100,4125,4243,4443,4444,4567,4711,4712,4848,4849,4993,5000,5104,5108,5432,5555,' \
            '5632,5800,5801,5802,5900,5901,5984,5985,5986,6082,6225,6346,6347,6379,6443,6480,6543,6789,6984,7000,7001,' \
            '7002,7396,7474,7674,7675,7777,7778,8000,8001,8002,8003,8004,8005,8006,8008,8009,8010,8014,8042,8069,8075,' \
            '8080,8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8091,8092,8093,8095,8016,8118,8123,8161,8172,8181,' \
            '8200,8222,8243,8280,8281,8333,8384,8403,8443,8500,8530,8531,8800,8806,8834,8880,8881,8887,8888,8910,8983,' \
            '8989,8990,8991,9000,9043,9060,9080,9090,9091,9200,9294,9295,9300,9443,9444,9800,9981,9988,9990,9999,10000,' \
            '10880,11211,11371,12043,12046,12443,15672,16225,16080,18091,18092,20000,20720,24465,27017,27018,28017,28080,' \
            '30821,43110,50070,61600 -oJ ' + name + ' --rate 100'
        child = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
        child.wait()  # 等待任务完成
        # 提取json文件中的端口
        if os.path.exists(name):
            with open(name, 'r') as f:
                for line in f:
                    if line.startswith('{ '):
                        temp = json.loads(line[:-2])
                        temp1 = temp["ports"][0]
                        temp_ports.append(str(temp1["port"]))
        else:
            print('文件不存在')
            sys.exit()
        if len(temp_ports) > 40:
            count += 1
            print(scan_ip + ' 疑似存在waf')
            bad_ips.append(scan_ip)
            temp_ports.clear()  # 如果端口数量大于40,说明可能存在防火墙,属于误报,清空列表
        else:
            ports.append(temp_ports)  # 小于40则放到总端口列表里
            ips[scan_ip] = temp_ports
            if os.path.exists(name):
                os.remove(name)
                print('file detele')
            if ips.get(scan_ip):
                Scan(scan_ip)
    
    
    # 调用nmap识别服务
    def Scan(scan_ip):
        global count
        open_ports_list = ips[scan_ip]
        open_ports = ",".join(open_ports_list)
        nm = nmap.PortScanner()
        lock.acquire()
        click.secho(f'[*] 开始nmap扫描 ip: {scan_ip} => 端口: {open_ports}', fg='red')
        count += 1
        print('当前是第', count, '个目标')
        lock.release()
        try:
            ret = nm.scan(scan_ip, open_ports, arguments=nmap_arguments)
            try:
                output_item = ret['scan'][scan_ip]['tcp']
            except Exception:
                pass
            else:   # try语句无异常时执行else语句
                for port, port_info in output_item.items():  # 返回可遍历的(键, 值) 元组数组
                    save_item = f"[+] {scan_ip} {port} {port_info['name']} {port_info['product']} {port_info['version']}"
                    insert.add(scan_ip + '\t' + str(port) + '\t' + port_info['name'] + '\t' + port_info['product'] + ' '
                               + port_info['version'] + '\n')
                    lock.acquire()
                    print(save_item)
                    lock.release()
                fw = open('ports3.txt', 'w+', encoding='utf-8')
                fw.writelines(insert)
                fw.close()
        except Exception as e:
            print(str(e))
            pass
    
    
    def main():
        que = queue.Queue()
        try:
            # 要扫描的ip列表,一行一个
            f = open(r'ips.txt', 'r')
            for line in f.readlines():
                final_ip = line.strip()
                que.put(final_ip)
            f.close()
            threads = []
            thread_count = 5
            for i in range(thread_count):
                threads.append(PortScan(que))
            for t in threads:
                t.start()
            for t in threads:
                t.join()
        except Exception as e:
            print('Main:', e)
            pass
        spend_time = (datetime.datetime.now() - start_time).seconds
        print("疑似存在waf的IP:")
        print(bad_ips)
        print('程序共运行了: ' + str(spend_time) + '秒')
    
    
    if __name__ == '__main__':
        ips = {}
        index = 1
        count = 0
        start_time = datetime.datetime.now()
        path = r"D:\Security-Tools\masscan1.0.4\x64"    # masscan所在路径,可自行修改
        os.chdir(path)
        nmap_arguments = "-sV -Pn"
        main()
    

    扫描端口的脚本有了,接下来我们得清楚各种端口的利用方式

    存在未授权风险的端口服务:

    redis、svn、Hadoop、vnc、mongodb、memcached、docker、zookeeper、rsync、ldap、ftp、couchdb

    存在爆破风险的端口服务:

    rdp、vnc、redis、ssh、mongodb、postgresql、mysql、oracle、ms-sql-s、socks5、ldap、smtp、ftp、zebra、snmp、netbios

    那么多风险点记不住咋办?像对我这种没有什么经验的菜鸟来说,可以把以上风险点写入脚本中:

    对于未授权的端口服务,有能力的话最好能复现一遍,然后平时要收集一些利用脚本,下面这个未授权查询脚本是在github上看到的,可以再自行添加

    import socket
    import pymongo
    import requests
    import ftplib
    from tqdm import tqdm
    import sys
    from concurrent.futures import ThreadPoolExecutor
    
    headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1464.0 Safari/537.36'}
    
    def redis(ip):
        try:
            socket.setdefaulttimeout(5)
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect((ip, 6379))
            s.send(bytes("INFO\r\n", 'UTF-8'))
            result = s.recv(1024).decode()
            if "redis_version" in result:
                print(ip + ":6379 redis未授权")
            s.close()
        except Exception as e:
            pass
        finally:
            bar.update(1)
    
    def mongodb(ip):
        try:
            conn = pymongo.MongoClient(ip, 27017, socketTimeoutMS=4000)
            dbname = conn.list_database_names()
            print(ip + ":27017 mongodb未授权")
            conn.close()
        except Exception as e:
            pass
        finally:
            bar.update(1)
    
    def memcached(ip):
        try:
            socket.setdefaulttimeout(5)
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect((ip, 11211))
            s.send(bytes('stats\r\n', 'UTF-8'))
            if 'version' in s.recv(1024).decode():
                print(ip + ":11211 memcached未授权")
            s.close()
        except Exception as e:
            pass
        finally:
            bar.update(1)
    
    def elasticsearch(ip):
        try:
            url = 'http://' + ip + ':9200/_cat'
            r = requests.get(url, headers=headers, timeout=15)
            if '/_cat/master' in r.content.decode():
                print(ip + ":9200 elasticsearch未授权")
        except Exception as e:
            pass
        finally:
            bar.update(1)
    
    def zookeeper(ip):
        try:
            socket.setdefaulttimeout(5)
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect((ip, 2181))
            s.send(bytes('envi', 'UTF-8'))
            data = s.recv(1024).decode()
            s.close()
            if 'Environment' in data:
                print(ip + ":2181 zookeeper未授权")
        except:
            pass
        finally:
            bar.update(1)
    
    def ftp(ip):
        try:
            ftp = ftplib.FTP.connect(ip,21,timeout=15)
            ftp.login('anonymous', 'Aa@12345678')       # 匿名访问,用户名为anonymous,密码为空或任意邮箱
            print(ip + ":21 FTP未授权")                    # 弱口令,username:FTP  password:FTP或空
        except Exception as e:                              # username: USET    password: pass
            pass
        finally:
            bar.update(1)
    
    def CouchDB(ip):
        try:
            url = 'http://' + ip + ':5984'+'/_utils/'
            r = requests.get(url, headers=headers, timeout=15)
            if 'couchdb-logo' in r.content.decode():
                print(ip + ":5984 CouchDB未授权")
        except Exception as e:
            pass
        finally:
            bar.update(1)
    
    def docker(ip):
        try:
            url = 'http://' + ip + ':2375'+'/version'
            r = requests.get(url, headers=headers, timeout=15)
            if 'ApiVersion' in r.content.decode():
                print(ip + ":2375 docker api未授权")
        except Exception as e:
            pass
        finally:
            bar.update(1)
    
    
    def Hadoop(ip):
        try:
            url = 'http://' + ip + ':50070'+'/dfshealth.html'
            r = requests.get(url, headers=headers, timeout=15)
            if 'hadoop.css' in r.content.decode():
                print(ip + ":50070 Hadoop未授权")
        except Exception as e:
            pass
        finally:
            bar.update(1)
    
    
    def Jenkins(ip):
        try:
            url = 'http://' + ip + ':8080' + '/manage'
            r = requests.get(url, headers=headers, timeout=15)
            if 'Jenkins' in r.content.decode():
                print(ip + ":8080 Jenkins api未授权")
        except Exception as e:
            pass
        finally:
            bar.update(1)
    
    
    if __name__ == '__main__':
        if len(sys.argv) == 1:
            print("Usage:python3 unauthorized-check.py url.txt")
        file = sys.argv[1]
        with open(file, "r", encoding='UTF-8') as f:
            line = [i for i in f.readlines()]
        bar = tqdm(total=len(line)*9)
        with ThreadPoolExecutor(max_workers=20) as pool:
            for target in line:
                target=target.strip()
                pool.submit(redis, target)
                pool.submit(Hadoop, target)
                pool.submit(docker, target)
                pool.submit(CouchDB, target)
                pool.submit(ftp, target)
                pool.submit(zookeeper, target)
                pool.submit(elasticsearch, target)
                pool.submit(memcached, target)
                pool.submit(mongodb, target)
                pool.submit(Jenkins, target)
    

    有时候端口扫描会发现一些中间件服务,比如下图:

    针对这种情况,平时可以收集一些中间件漏洞总结的文章,或者在零组漏洞库中查找相应的漏洞

    相关文章

      网友评论

        本文标题:浅谈端口渗透那些事

        本文链接:https://www.haomeiwen.com/subject/fqibkktx.html