安全漏洞本質扯談之決戰彙編程式碼

wyzsk發表於2020-08-19
作者: alert7 · 2015/02/28 18:42

0x00 前言


當前比較流行也比較有效率的挖掘的漏洞的方法是Fuzzing,當然這也需要花點時間去寫Fuzzing程式。然而不是每個東西都有必要去寫Fuzzing程式,也不是每個東西都可以去Fuzzing的,所以也還是要繼續修煉我們的二進位制安全流派內功—“肉眼挖洞神功”。

安全漏洞在原始碼層面和彙編程式碼層面會有不同的表現,想要進階升級的話,必須清晰的瞭解每種安全漏洞型別在原始碼層面和彙編程式碼層面都是張什麼樣的。有些安全漏洞在原始碼層面容易發現它,有些安全漏洞則在彙編程式碼層面比較容易發現它。不管是原始碼層面還是彙編程式碼層面,普通人看程式碼的時候即使看到有安全漏洞的那些程式碼的時候,往往是“只見程式碼,不見漏洞”。修煉“肉眼挖洞神功”的目標是看到那些疑似有問題的程式碼時候能夠警覺,能夠識別,並快速判定是否可形成安全漏洞。

早些時候給我們翰海源的小夥伴們講過《深入安全漏洞-Root Cause of Vulnerabilities》和《決戰彙編程式碼》,希望小夥伴們能夠掌握安全漏洞的本質原因以及練就“肉眼挖洞神功”。今天把裡面的部分例子跟大夥一起分享下。

0x01 原始碼層面


1. Link Attack


*unix 下的 link attack,有意識到嗎?

#!c
if(access("file",W_OK)!=0){
    exit(1);
}
fd = open("file",O_WRONLY);

write(fd,buffer,sizeof(buffer));

2. Integer Overflow Example in OpenSSH 3.1


發生在真實的 openssh 3.1 ,有漏洞嗎?

#!c
u_int nresp;
...
nresp = packet_get_int();
if(nresp){
    response = xmalloc(nresp * sizeof(char*));
    for(i=0; i<nresp; i++)
        response[i] = packet_get_string(NULL);
}
packet_check_eom();

3. Signed Integer Vulnerability Example


注意整形符號,能被繞過嗎?

#!c
int read_user_data(int sockfd) 
{
   int length, sockfd, n;
   char buffer[1024];

   length = get_user_length(sockfd);

   if(length > 1024){
       error("illegal input, not enough room in buffer\n"); 
       return 1;
   }

   if(read(sockfd, buffer, length) < 0){ error("read: %m");
       return 1;
   }

   return 0; 
}

4. Truncation Vulnerability Example in NFS


整形截斷問題?

#!c
void assume_privs(unsigned short uid) {
   seteuid(uid);
   setuid(uid);
}

int become_user(int uid) 
{
   if (uid == 0)
       die("root isnt allowed");
   assume_privs(uid); 
}

5. 蘋果SSL/TLS 重大安全漏洞的細節


(CVE-2014-1266)多個goto fail造成重大安全隱患。

#!c
static OSStatus
SSLVerifySignedServerKeyExchange(SSLContext *ctx, bool isRsa, SSLBuffer signedParams,
                                 uint8_t *signature, UInt16 signatureLen)
{
    ...

    if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0)
        goto fail;
    if ((err = SSLHashSHA1.update(&hashCtx, &clientRandom)) != 0)
        goto fail;
    if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
        goto fail;
    if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
        goto fail;
        goto fail;  <---- *** DANGER ***
    if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
        goto fail;

        err = sslRawVerify(ctx,
                       ctx->peerPubKey,
                       dataToSign,                              /* plaintext */
                       dataToSignLen,                   /* plaintext length */
                       signature,
                       signatureLen);
    ...
fail:
    SSLFreeBuffer(&signedHashes);
    SSLFreeBuffer(&hashCtx);
    return err;

}

6. MS-RPC DCOM Buffer Overflow
(衝擊波)


衝擊波蠕蟲只因為一個緩衝區溢位。

#!c
HRESULT GetMachineName (WCHAR * pwszPath) {
     The WCHAR wszMachineName [N + 1]); 
     ...
     LPWSTR pwszServerName = wszMachineName;
     while (* pwszPath! = L '\\')
         * PwszServerName + + = * pwszPath + +;   
     ...
 }

7. 有漏洞嗎?


#!c
unsigned short read_length(int sockfd) 
{
    unsigned short len;

    if(full_read(sockfd, (void *)&len, 2) != 2)
        die("could not read length!\n");
    return ntohs(len);
}

int read_packet(int sockfd) 
{
   struct header hdr;
   short length;
   char *buffer;

   length = read_length(sockfd);

   if(length > 1024){
       error("read_packet: length too large: %d\n", length); 
       return 1;
   }

   buffer = (char *)malloc(length+1);

   if((n = read(sockfd, buffer, length) < 0){
       error("read: %m");
       free(buffer);
       return 1;
   }
   buffer[n] = '\0';
   return 0; 
}

8. 有漏洞嗎?


提示: 5rOo5oSPc216ZW9m

#!c
char *read_username(int sockfd) 
{
    char *buffer, *style, userstring[1024]; 
    int i;

    buffer = (char *)malloc(1024);

    if(!buffer){
        error("buffer allocation failed: %m"); 
        return NULL;
    }

    if(read(sockfd, userstring, sizeof(userstring)-1) <= 0){ 
       free(buffer);
       error("read failure: %m");
       return NULL;
    }

    userstring[sizeof(userstring)-1] = '\0';

    style = strchr(userstring, ':'); 
    if(style)
       *style++ = '\0';

    sprintf(buffer, "username=%.32s", userstring);

    if(style)
        snprintf(buffer, sizeof(buffer)-strlen(buffer)-1,
                 ", style=%s\n", style);
    return buffer;
}

9. 有漏洞嗎?


提示:

enter image description here

#!c
/* special thing for ldap.
* The parts are separated by question marks. 
* From RFC 2255:
* ldapurl = scheme "://" [hostport] ["/"
*           [dn ["?" [attributes] ["?" [scope] 
*           ["?" [filter] ["?" extensions]]]]]]
*/

if (!strncasecmp(uri, "ldap", 4)) 
{
    char *token[5];
    int c = 0;

    token[0] = cp = ap_pstrdup(p, cp); 
    while (*cp && c < 5) {
        if (*cp == '?') {
            token[++c] = cp + 1;
            *cp = '\0';
        }
        ++cp; 
    }

10. 有漏洞嗎?(Antisniff v1.1 Vulnerability)


tips

#!c
char *indx;
int count;
char nameStr[MAX_LEN]; //256
...
memset(nameStr, '\0', sizeof(nameStr));
...
indx = (char *)(pkt + rr_offset); 
count = (char)*indx;

while (count){
    if (strlen(nameStr) + count < ( MAX_LEN - 1) ){
       (char *)indx++;
       strncat(nameStr, (char *)indx, count); 
       indx += count;
       count = (char)*indx;
       strncat(nameStr, ".",
               sizeof(nameStr) strlen(nameStr));
    } else {
       fprintf(stderr, "Alert! Someone is attempting "
                       "to send LONG DNS packets\n");
       count = 0; }
}
nameStr[strlen(nameStr)-1] = '\0';

11. 還有漏洞嗎?(Antisniff v1.1.1 Vulnerability)


#!c
char *indx;
int count;
char nameStr[MAX_LEN]; //256
...
memset(nameStr, '\0', sizeof(nameStr));
...
indx = (char *)(pkt + rr_offset); 
count = (char)*indx;

while (count){
/* typecast the strlen so we aren't dependent on 
  the call to be properly setting to unsigned. */

  if ((unsigned int)strlen(nameStr) + 
    (unsigned int)count < ( MAX_LEN - 1) ){
    (char *)indx++;
    strncat(nameStr, (char *)indx, count); 
    indx += count;
    count = (char)*indx;
    strncat(nameStr, ".",
            sizeof(nameStr) strlen(nameStr)); 
  } else {
    fprintf(stderr, "Alert! Someone is attempting " 
                    "to send LONG DNS packets\n");
    count = 0; 
  }
}
nameStr[strlen(nameStr)-1] = '\0';

12. 還有漏洞嗎?(Antisniff v1.1.2 Vulnerability)


#!c
unsigned char *indx;
unsigned int count;
unsigned char nameStr[MAX_LEN]; //256
...
memset(nameStr, '\0', sizeof(nameStr));
...
indx = (char *)(pkt + rr_offset); 
count = (char)*indx;

while (count){
    if (strlen(nameStr) + count < ( MAX_LEN - 1) ){ 
       indx++;
       strncat(nameStr, indx, count);
       indx += count;
       count = *indx;
       strncat(nameStr, ".",
               sizeof(nameStr) strlen(nameStr));
     } else {
       fprintf(stderr, "Alert! Someone is attempting "
                       "to send LONG DNS packets\n");
       count = 0; 
     }
}
nameStr[strlen(nameStr)-1] = '\0';

0x02 彙編程式碼層面


接下要在彙編程式碼堆裡磨練下,下面的彙編程式碼有安全問題嗎?都是些什麼問題?

1. Safe or vulnerability?


#!bash
text:0040106B sub_40106B      proc near               ; CODE XREF: _main+58p
.text:0040106B
.text:0040106B var_10004       = byte ptr -10004h
.text:0040106B var_4           = dword ptr -4
.text:0040106B arg_0           = word ptr  8
.text:0040106B
.text:0040106B                 push    ebp
.text:0040106C                 mov     ebp, esp
.text:0040106E                 mov     eax, 10004h
.text:00401073                 call    __alloca_probe
.text:00401078                 mov     eax, dword_404020
.text:0040107D                 xor     eax, ebp
.text:0040107F                 mov     [ebp+var_4], eax
.text:00401082                 movsx   eax, [ebp+arg_0]
.text:00401086                 movsx   eax, [ebp+eax+var_10004]
.text:0040108E                 push    eax
.text:0040108F                 push    offset Format   ; "t %x"
.text:00401094                 call    ds:printf
.text:0040109A                 pop     ecx
.text:0040109B                 pop     ecx
.text:0040109C                 mov     ecx, [ebp+var_4]
.text:0040109F                 xor     ecx, ebp
.text:004010A1                 xor     eax, eax
.text:004010A3                 call    sub_401BD2
.text:004010A8                 leave

2. Safe or vulnerability?


#!bash
text:004010AA sub_4010AA      proc near               ; CODE XREF: _main+60p
.text:004010AA
.text:004010AA var_190         = dword ptr -190h
.text:004010AA arg_0           = dword ptr  8
.text:004010AA
.text:004010AA                 push    ebp
.text:004010AB                 mov     ebp, esp
.text:004010AD                 mov     eax, [ebp+arg_0]
.text:004010B0                 sub     esp, 190h
.text:004010B6                 cmp     eax, 64h
.text:004010B9                 jle     short loc_4010BE
.text:004010BB                 push    64h
.text:004010BD                 pop     eax
.text:004010BE
.text:004010BE loc_4010BE:                             ; CODE XREF: sub_4010AA+Fj
.text:004010BE                 push    [ebp+eax*4+var_190]
.text:004010C5                 push    offset Format   ; "t %x"
.text:004010CA                 call    ds:printf
.text:004010D0                 pop     ecx

3. Safe or vulnerability?


#!bash
.text:00401000 sub_401000      proc near               ; CODE XREF: _main+48p
.text:00401000
.text:00401000 var_190         = dword ptr -190h
.text:00401000 arg_0           = dword ptr  8
.text:00401000
.text:00401000                 push    ebp
.text:00401001                 mov     ebp, esp
.text:00401003                 mov     eax, [ebp+arg_0]
.text:00401006                 sub     esp, 190h
.text:0040100C                 cmp     eax, 64h
.text:0040100F                 jbe     short loc_401014
.text:00401011                 push    64h
.text:00401013                 pop     eax
.text:00401014
.text:00401014 loc_401014:                             ; CODE XREF: sub_401000+Fj
.text:00401014                 push    [ebp+eax*4+var_190]
.text:0040101B                 push    offset Format   ; "t %x"
.text:00401020                 call    ds:printf
.text:00401026                 pop     ecx
.text:00401027                 pop     ecx

4. Safe or vulnerability?


#!bash
.text:004010D6 sub_4010D6      proc near               ; CODE XREF: _main+68p
.text:004010D6
.text:004010D6 arg_0           = dword ptr  4
.text:004010D6
.text:004010D6                 push    esi
.text:004010D7                 push    64h             ; Size
.text:004010D9                 call    ds:malloc
.text:004010DF                 mov     esi, eax
.text:004010E1                 mov     eax, [esp+8+arg_0]
.text:004010E5                 cmp     eax, 64h
.text:004010E8                 pop     ecx
.text:004010E9                 jle     short loc_4010EE
.text:004010EB                 push    64h
.text:004010ED                 pop     eax
.text:004010EE
.text:004010EE loc_4010EE:                             ; CODE XREF: sub_4010D6+13j
.text:004010EE                 movsx   eax, byte ptr [eax+esi]
.text:004010F2                 push    eax
.text:004010F3                 push    offset Format   ; "t %x"
.text:004010F8                 call    ds:printf
.text:004010FE                 push    esi             ; Memory
.text:004010FF                 call    ds:free

5. Safe or vulnerability?


#!bash
. text:0040110C sub_40110C      proc near               ; CODE XREF: _main+70p
.text:0040110C
.text:0040110C var_19A0        = byte ptr -19A0h
.text:0040110C var_4           = dword ptr -4
.text:0040110C arg_0           = word ptr  8
.text:0040110C
.text:0040110C                 push    ebp
.text:0040110D                 mov     ebp, esp
.text:0040110F                 mov     eax, 19A0h
.text:00401114                 call    __alloca_probe
.text:00401119                 mov     eax, dword_404020
.text:0040111E                 xor     eax, ebp
.text:00401120                 mov     [ebp+var_4], eax
.text:00401123                 movsx   eax, [ebp+arg_0]
.text:00401127                 movsx   eax, [ebp+eax+var_19A0]
.text:0040112F                 push    eax
.text:00401130                 push    offset Format   ; "t %x"
.text:00401135                 call    ds:printf
.text:0040113B                 pop     ecx
.text:0040113C                 pop     ecx
.text:0040113D                 mov     ecx, [ebp+var_4]
.text:00401140                 xor     ecx, ebp

6. Safe or vulnerability?


#!bash
.text:0040102C sub_40102C      proc near               ; CODE XREF: _main+50p
.text:0040102C
.text:0040102C var_10004       = byte ptr -10004h
.text:0040102C var_4           = dword ptr -4
.text:0040102C arg_0           = word ptr  8
.text:0040102C
.text:0040102C                 push    ebp
.text:0040102D                 mov     ebp, esp
.text:0040102F                 mov     eax, 10004h
.text:00401034                 call    __alloca_probe
.text:00401039                 mov     eax, dword_404020
.text:0040103E                 xor     eax, ebp
.text:00401040                 mov     [ebp+var_4], eax
.text:00401043                 movzx   eax, [ebp+arg_0]
.text:00401047                 movsx   eax, [ebp+eax+var_10004]
.text:0040104F                 push    eax
.text:00401050                 push    offset Format   ; "t %x"
.text:00401055                 call    ds:printf
.text:0040105B                 pop     ecx

7. Safe or vulnerability?


#!bash
. .text:0040118A ; int __cdecl sub_40118A(LPCSTR lpMultiByteStr)
.text:0040118A sub_40118A      proc near               ; CODE XREF: _main+91p
.text:0040118A
.text:0040118A WideCharStr     = word ptr -44h
.text:0040118A var_4           = dword ptr -4
.text:0040118A lpMultiByteStr  = dword ptr  8
.text:0040118A
.text:0040118A                 push    ebp
.text:0040118B                 mov     ebp, esp
.text:0040118D                 sub     esp, 44h
.text:00401190                 mov     eax, dword_404020
.text:00401195                 xor     eax, ebp
.text:00401197                 mov     [ebp+var_4], eax
.text:0040119A                 mov     ecx, [ebp+lpMultiByteStr]
.text:0040119D                 mov     eax, ecx
.text:0040119F                 push    esi
.text:004011A0                 lea     esi, [eax+1]
.text:004011A3
.text:004011A3 loc_4011A3:                             ; CODE XREF: sub_40118A+1Ej
.text:004011A3                 mov     dl, [eax]
.text:004011A5                 inc     eax
.text:004011A6                 test    dl, dl
.text:004011A8                 jnz     short loc_4011A3
.text:004011AA                 push    40h             ; cchWideChar
.text:004011AC                 lea     edx, [ebp+WideCharStr]
.text:004011AF                 push    edx             ; lpWideCharStr
.text:004011B0                 sub     eax, esi
.text:004011B2                 push    eax             ; cbMultiByte
.text:004011B3                 push    ecx             ; lpMultiByteStr
.text:004011B4                 push    0               ; dwFlags
.text:004011B6                 push    0               ; CodePage
.text:004011B8                 call    ds:MultiByteToWideChar

8. Safe or vulnerability?


#!bash
text:00401738 Size            = dword ptr  4
.text:00401738 Src             = dword ptr  8
.text:00401738
.text:00401738                 push    esi
.text:00401739                 push    edi
.text:0040173A                 mov     edi, [esp+8+Size]
.text:0040173E                 lea     eax, [edi+1]
.text:00401741                 push    eax             ; Size
.text:00401742                 call    ds:__imp__malloc
.text:00401748                 mov     esi, eax
.text:0040174A                 test    esi, esi
.text:0040174C                 pop     ecx
.text:0040174D                 jz      short loc_401774
.text:0040174F                 push    edi             ; Size
.text:00401750                 push    [esp+0Ch+Src]   ; Src
.text:00401754                 push    esi             ; Dst
.text:00401755                 call    _memcpy
.text:0040175A                 push    esi
.text:0040175B                 push    offset aS       ; "%s\n"
.text:00401760                 mov     byte ptr [esi+edi], 0
.text:00401764                 call    ds:__imp__printf

0x04 最後


彙編程式碼層面的例子需要想想它們的原始碼都是怎麼寫的才能編譯出來這些有安全漏洞的程式碼。做到原始碼層面和彙編程式碼層面通吃。更要做到從宏觀上了解程式世界功能和規則,從微觀上了解其實現細節。

上面的例子都不到一百行的彙編程式碼,都找出問題了嗎?決戰彙編程式碼就是需要我們在真實程式世界的上千萬行彙編程式碼中找出那些隱藏的安全漏洞,這個難度會高很多。其中有對抗有程式設計者的防禦措施,需要思考如何打敗它,是和程式世界的締造者們的一次跨時間和空間無聲的較量。

以上這些其實是一個引子,需要小夥伴繼續深入研究推演和鍛鍊。推薦學習Mark Down & JohnMcDonald兩位大牛的書《The Art of Software Security Assessment-- Identifying andavoiding software vulnerabilities》(某些例子來自該書),希望對小夥伴們有所幫助。

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章