標籤:shellcode
shellcode學習第一個例子。
以下有一段c語言編寫的命令列程式,檢驗使用者輸入的數字,並判斷是否合法。這裡使用者的輸入被放在了函數的緩衝區裡,但程式沒有對緩衝區長度做檢查,留下了漏洞。這裡可以利用該漏洞繞過數字檢察,使得任意輸入都會被判定為正確。
在 validate_serial 中,do_valid_stuff 的地址溢出到函數的傳回值上,就可實現。
來源程式
#include <stdio.h>#include <stdlib.h>#include <string.h>int valid_serial(char * psz){ size_t len = strlen(psz); unsigned total = 0; size_t i; if (len<10) return 0; for (i = 0; i < len; i++) { if ((psz[i]<‘0‘) || (psz[i]>‘z‘)) return 0; total += psz[i]; } if (total % 853 == 83) return 1; return 0; }int valildate_serial(){ char serial[24]; fscanf(stdin, "%s", serial); if (valid_serial(serial)) return 1; else return 0;}int do_valid_stuff(){ printf("the serial number is valid!\n"); exit(0);}int do_invalid_stuff(){ printf("invalid serial number!\nexiting\n"); exit(1);}int main(int argc, char * argv[]){ if (valildate_serial()) do_valid_stuff(); else do_invalid_stuff(); return 0;}
反組譯碼main
(gdb) disass mainDump of assembler code for function main: 0x0804861a <+0>: push %ebp 0x0804861b <+1>: mov %esp,%ebp 0x0804861d <+3>: call 0x804859f <valildate_serial> 0x08048622 <+8>: test %eax,%eax 0x08048624 <+10>: je 0x804862d <main+19> 0x08048626 <+12>: call 0x80485de <do_valid_stuff> 0x0804862b <+17>: jmp 0x8048632 <main+24> 0x0804862d <+19>: call 0x80485fc <do_invalid_stuff> 0x08048632 <+24>: mov $0x0,%eax 0x08048637 <+29>: pop %ebp 0x08048638 <+30>: retEnd of assembler dump.
可得到 do_valid_stuff 的地址為 0x08048626。validate_serial 的返回地址為 0x08048622。下面就通過溢出修改返回地址。
緩衝區溢位
源碼中,緩衝區長度為24,理論上只要覆蓋24+2處的資料就可以了。我們需要檢驗一下,在fscanf處打斷點,觀察堆棧內容。
Breakpoint 1, valildate_serial () at serial.c:3131 fscanf(stdin, "%s", serial);(gdb) x/20x $esp0xbffff6bc: 0x0804869b 0x00000001 0xbffff794 0xbffff79c0xbffff6cc: 0xbffff6e8 0xb7e987f5 0xb7ff0590 0x0804865b0xbffff6dc: 0xb7fc7ff4 0xbffff6e8 0x08048622 0xbffff7680xbffff6ec: 0xb7e7fe46 0x00000001 0xbffff794 0xbffff79c0xbffff6fc: 0xb7fe0860 0xb7ff6821 0xffffffff 0xb7ffeff4(gdb)cAAAAAAAAAABBBBBBBBBBCCCCCCCC1234Breakpoint 2, valildate_serial () at serial.c:3333 if (valid_serial(serial))(gdb) x/20x $esp0xbffff6bc: 0xb7fc8440 0x080486d0 0xbffff6c8 0x414141410xbffff6cc: 0x41414141 0x42424141 0x42424242 0x424242420xbffff6dc: 0x43434343 0x43434343 0x34333231 0xbffff7000xbffff6ec: 0xb7e7fe46 0x00000001 0xbffff794 0xbffff79c0xbffff6fc: 0xb7fe0860 0xb7ff6821 0xffffffff 0xb7ffeff4(gdb)
可以看到“1234”對應的ascii碼“0x34333231”已經被寫入了傳回值”0x08048622”原來所在的地方。
接下來把“1234”換成我們需要的返回地址。
我們回到shell中實驗一下
[email protected]:~/Desktop/shellcode/validate_serial$ printf "AAAAAAAAAABBBBBBBBBBCCCCCCCC\x26\x86\x04\x08" | ./serialthe serial number is valid!
成功繞過了程式的檢驗機制。
[shellcode學習] 繞過條件判斷