一、前言

​ 做某个项目主要的任务是对资产服务识别,以及弱口令等常规漏洞的检查。由于IP数量巨大,客户自己都不知道有哪些资产服务且有些端口服务开关不定,给工作带来了极大的干扰,导致一些服务上的弱口令及常规未授权访问漏洞在第一轮没有清扫干净,例如海康、ftp、ssh弱口令等。因此在第一轮排查后想写个脚本来监测客户的IP资产,当有新的服务端口开放时用邮件进行通知,再进行排查。根据实际漏洞情况及时间安排进行三轮监控:

​ 第一阶段针对团体名、telnet、海康摄像后台弱口令,redis、Memcached未授权访问漏洞对下面端口服务进行监控:

telnet 23,snmp 161,Redis 6379,Memcached 11211,Rtsp 554。

​ 第二阶段主要是对数据库的一些弱口令及未授权登陆的排查,对下面端口服务进行监测:
MongoDB 27017,Oracle 1521 ,SQLServer 1433,MySQL 3306,Pointbase 9092,DB2 5000,Sybase 4100。

​ 第三阶段是对主机系统可能存在的弱口令进行监测:
ftp 21,ssh 22,RDP 3389

二、脚本编写

1.大体思路:

  • 1.使用python调用nmap对指定资产以及端口服务进行扫描并将扫描结果导出为xml文本。
  • 2.使用python下的xml模块解析上一步导出的xml文本,将开放了指定监测服务端口的IP存入数据库。
  • 3.第一次排查完成后开始后续检测当有新的IP出现监测服务时,将该IP存入数据库,并把IP及开放端口邮件发送至我邮箱。
  • 4.上述完成后程序休眠3小时后开始下一次检测。

2.扫描模块:

调用nmap对资产进行扫描,我所采用的nmap命令如下:

nmap -sS -p ports -Pn -iL filename -oX result.xml

扫描模块代码如下:

def scanner(filename,ports,i):
    strTime = time.strftime("%Y-%m-%d-%H%M%S", time.localtime(time.time()))
    print strTime + '   资产开始第%d次端口扫描\n' % i
    os.system("nmap -sS -p "+ports+" -Pn -iL "+filename+" -oX "+str(i)+".xml")
    print time.strftime("%Y-%m-%d-%H%M%S", time.localtime(time.time())) + "     资产完成第%d次扫描,开始解析" % i
    file='{x}.xml'.format(x=i)
    analysis(file,i)

3.解析模块:

使用python的xml模块来对扫描模块的xml文本进行解析,关于xml模块的教程可参考该网址解析模块如下所示:

def analysis(file,i):
    tree = ET.parse(file)
    root = tree.getroot()
    list=[]
    for temp in root.findall('host'):
        ports = ''
        ip = temp.find('address').get('addr')
        try:
            xml_ports = temp.find('ports').findall('port')
        except:
             print ip + "没有检测出"
             continue
        for temp1 in xml_ports:
            if temp1.find('state').get('state') == 'open':
                port = temp1.get('portid')
                ports = ports + ' ' + port
        cursor.execute('select count(*) from host where ip=?',(ip,))
        result=cursor.fetchall()
        if len(ports)>0 and str(result)=='[(0,)]':
            store(ip,ports)
            list.append((ip+':'+ports))
    cursor.close()
    conn.commit()
    conn.close()
    if len(list)!=0 and i!=1:
        send_email(list)
    elif i!=1 and len(list)==0:
        print "本次没有新地址出现"
    print "本次解析完成!休息一小时候继续工作。\n"

4.存储模块:

该脚本采用的是python自带的sqlite3模块进行数据库的创建,由于SQLite本身是C写的,而且体积很小,实现简单所以,经常被集成到各种应用程序中,甚至在iOS和Android的App中都可以集成。具体教程参见菜鸟教程创建数据、获取游标、执行sql语句:

conn=sqlite3.connect('host.db')
cursor=conn.cursor()
cursor.execute(r"insert into host (ip,ports) values ('{ip}', '{ports}')".format(ip=ip,ports=ports))

5.邮件发送模块:

采用了python下的smtp模块进行了邮件的发送,具体教程参考该网址邮件模块代码如下:

def send_email(list):
    sender="你的163邮箱"
    receiver=[]
    str=""
    for ip in list:
        str=str+ip+"\n"
    text=MIMEText("the new open address and ports:\n"+str,'plain','utf-8')
    message=MIMEMultipart('mixed')
    message['From']='你的163邮箱'
    message['To']=';'.join(receiver)
    message['Subject']='new address!!!!!!'
    message.attach(text)
    smtp=smtplib.SMTP()
    smtp.connect('smtp.163.com')
    smtp.login('你的163邮箱','你的163邮箱密码')
    smtp.sendmail(sender,receiver,message.as_string())
    smtp.quit()
    print "已发现新地址,邮件已发送完成\n"

所有代码

#coding:gbk
import os
import time
import sys
import argparse
import smtplib
import sqlite3
from email.mime.multipart import MIMEMultipart
import xml.etree.ElementTree as ET
from email.mime.text import MIMEText
def scanner(filename,ports,i):
    strTime = time.strftime("%Y-%m-%d-%H%M%S", time.localtime(time.time()))
    print strTime + '   资产开始第%d次端口扫描\n' % i
    os.system("nmap -sS -p "+ports+" -Pn -iL "+filename+" -oX "+str(i)+".xml")
    print time.strftime("%Y-%m-%d-%H%M%S", time.localtime(time.time())) + "     资产完成第%d次扫描,开始解析" % i
    file='{x}.xml'.format(x=i)
    analysis(file,i)
def analysis(file,i):
    tree = ET.parse(file)
    root = tree.getroot()
    list=[]
    for temp in root.findall('host'):
        ports = ''
        ip = temp.find('address').get('addr')
        try:
            xml_ports = temp.find('ports').findall('port')
        except:
             print ip + "没有检测出"
             continue
        for temp1 in xml_ports:
            if temp1.find('state').get('state') == 'open':
                port = temp1.get('portid')
                ports = ports + ' ' + port
        cursor.execute('select count(*) from host where ip=?',(ip,))
        result=cursor.fetchall()
        if len(ports)>0 and str(result)=='[(0,)]':
            store(ip,ports)
            list.append((ip+':'+ports))
    cursor.close()
    conn.commit()
    conn.close()
    if len(list)!=0 and i!=1:
        send_email(list)
    elif i!=1 and len(list)==0:
        print "本次没有新地址出现"
    print "本次解析完成!休息一小时候继续工作。\n"
def store(ip,ports):
    cursor.execute(r"insert into host (ip,ports) values ('{ip}', '{ports}')".format(ip=ip,ports=ports))
    print "success"
def send_email(list):
    sender="你的163邮箱"
    receiver=[]
    str=""
    for ip in list:
        str=str+ip+"\n"
    text=MIMEText("the new open address and ports:\n"+str,'plain','utf-8')
    message=MIMEMultipart('mixed')
    message['From']='你的163邮箱'
    message['To']=';'.join(receiver)
    message['Subject']='new address!!!!!!'
    message.attach(text)
    smtp=smtplib.SMTP()
    smtp.connect('smtp.163.com')
    smtp.login('你的163邮箱','你的163邮箱密码')
    smtp.sendmail(sender,receiver,message.as_string())
    smtp.quit()
    print "已发现新地址,邮件已发送完成\n"
if __name__=='__main__':
    i=1
    prase = argparse.ArgumentParser(usage="python port_scanner.py --file=filename --ports=p1,p2,p3......",description="the script is for large assets monitoring")
    prase.add_argument('--file', type=str, help="IP_assets'filename to be scanned")
    prase.add_argument('--ports', type=str, help="ports which are needed to be scanned")
    if len(sys.argv)<2:
        print prase.usage+'\n input -h for help'
    ports = prase.parse_args().ports
    filename=prase.parse_args().file
    conn=sqlite3.connect('host.db')
    cursor=conn.cursor()
    cursor.execute('create table if not exists host (id INTEGER PRIMARY KEY AUTOINCREMENT,ip VARCHAR(16) UNIQUE NOT NULL,ports TEXT)')
    while 1:
        conn = sqlite3.connect('host.db')
        cursor = conn.cursor()
        scanner(filename,ports,i)
        time.sleep(10800)
        i=i+1

三、实现效果

当探测到开放服务时收到邮件截图:

点击收藏 | 0 关注 | 1
登录 后跟帖