12558网页游戏私服论坛

 找回密码
 立即注册
游戏开服表 申请开服
游戏名称 游戏描述 开服状态 游戏福利 运营商 游戏链接
攻城掠地-仿官 全新玩法,觉醒武将,觉醒技能 每周新区 经典复古版本,长久稳定 进入游戏
巅峰新版攻 攻城掠地公益服 攻城掠地SF 新兵种、新武将(兵种) 进入游戏
攻城掠地公 散人玩家的天堂 新开 进入游戏
改版攻城掠 上线即可国战PK 稳定新区 全新改版,功能强大 进入游戏
少年江山 高福利高爆率 刚开一秒 江湖水落潜蛟龙 进入游戏
太古封魔录 开服送10亿钻石 福利多多 不用充钱也可升级 进入游戏
神魔之道 签到送元宝 稳定开新区 送豪华签到奖励 进入游戏
神奇三国 统帅三军,招揽名将 免费玩新区 激情国战,征战四方 进入游戏
龙符 三日豪礼领到爽 天天开新区 助你征战无双 进入游戏
王者之师 免费领豪华奖励 免费玩新区 6元送6888元宝 进入游戏
查看: 415|回复: 0

CVE-2014-9707-漏洞形成分析

[复制链接]
发表于 2019-8-20 11:04:11 | 显示全部楼层 |阅读模式
CVE-2014-9707-漏洞形成分析
前言
    实验主机: Linux 4.0.0-kali1-686-pae #1 SMP Debian 4.0.4-1+kali2 (2015-06-03) i686 GNU/Linux(关闭ASLR、NX)
    工具: GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1(带peda插件)
    漏洞程序版本: Version: 3.1.3-0
    Embedthis Software GoAhead 3.0.0版本至3.4.1版本中存在安全漏洞,该漏洞源于程序没有正确处理以.字符开始的路径部分。远程攻击者可借助构造URI利用该漏洞实施目录遍历攻击,造成拒绝服务(基于堆的缓冲区溢出和崩溃),也可能执行任意代码。
漏洞分析
    先把我们的漏洞程序GoAhead运行起来,然后打开另一个命令行终端,输入ps -ef查看当前GoAhead的PID,便于我们gdb附加
[Asm] 纯文本查看 复制代码root@Hacker-Deceive:/Overflow/goahead-3.1.3-0# make rungoahead: 2: Configuration for Embedthis GoAheadgoahead: 2: ---------------------------------------------goahead: 2: Version:            3.1.3-0goahead: 2: BuildType:          Debuggoahead: 2: CPU:                x86goahead: 2: OS:                 linuxgoahead: 2: Host:               127.0.1.1goahead: 2: Directory:          /Overflow/goahead-3.1.3-0/srcgoahead: 2: Documents:          webgoahead: 2: Configure:          bit -d -q -platform linux-x86-default -configure . -gen makegoahead: 2: ---------------------------------------------goahead: 2: Started http://*:80goahead: 2: Started https://*:443     
    可以看到GoAhead程序的PID为8742,然后我们使用Gdb附加GoAhead程序gdb attech 8742
[Asm] 纯文本查看 复制代码root      8724  3875  0 17:01 pts/1    00:00:00 make runroot      8734  8724  0 17:01 pts/1    00:00:00 make --no-print-directory -f projects/groot      8741  8734  0 17:01 pts/1    00:00:00 /bin/sh -c cd src; goahead -v ; cd ..root      8742  8741  0 17:01 pts/1    00:00:00 goahead -vroot      8746  4688  0 17:02 pts/2    00:00:00 ps -ef
    附加成功,程序断了下来,然后我们输入命令C 让程序继续运行.
[Asm] 纯文本查看 复制代码[------------------------------------------------------------------------------]Legend: code, data, rodata, value0xb7fdebe0 in __kernel_vsyscall ()gdb-peda$ cContinuing.
    运行我们的Poc程序,可见GoAheadService触发了一个SIGABRT,
    触发SIGABRT的原因:
     1.Free没有初始化的地址或者错误的地址,
     2.堆越界,
     3.assert

    bt 栈回溯,看调用流程,因为是堆溢出,所以栈上的数据是完整的gdb-peda$ bt
[Asm] 纯文本查看 复制代码#0  0xb7fdebe0 in __kernel_vsyscall ()#1  0xb7d73307 in __GI_raise (sig=sig@entry=0x6)    at ../nptl/sysdeps/unix/sysv/linux/raise.c:56#2  0xb7d749c3 in __GI_abort () at abort.c:89#3  0xb7db16f8 in __libc_message (do_abort=do_abort@entry=0x1,     fmt=fmt@entry=0xb7ea765c "*** Error in `%s': %s: 0x%s ***\n")    at ../sysdeps/posix/libc_fatal.c:175#4  0xb7db776a in malloc_printerr (action=,     str=0xb7ea77b4 "free(): corrupted unsorted chunks", ptr=0x805b938) at malloc.c:4996#5  0xb7db83bd in _int_free (av=0xb7eeb420 , p=, have_lock=0x0)    at malloc.c:3840#6  0xb7dbb0c3 in __GI___libc_free (mem=) at malloc.c:2946#7  0xb7fb65ad in websNormalizeUriPath (    pathArg=0x805b8a0 "/1234567/./89abcdef", 'x' , "/.gh")    at src/http.c:3226#8  0xb7fb8a74 in parseFirstLine (wp=) at src/http.c:954#9  parseIncoming (wp=) at src/http.c:870#10 websPump (wp=0x804f550) at src/http.c:824#11 0xb7fb900d in readEvent (wp=0x804f550) at src/http.c:797#12 socketEvent (sid=0x2, mask=0x2, wptr=0x804f550) at src/http.c:735#13 0xb7fc6312 in socketDoEvent (sp=0x804f4a0) at src/socket.c:649#14 socketProcess () at src/socket.c:623#15 0xb7fb3585 in websServiceEvents (finished=0x804ab44 ) at src/http.c:1290#16 0x08048c31 in main (argc=0x2, argv=0xbffff304, envp=0xbffff310) at src/goahead.c:146#17 0xb7d5ea63 in __libc_start_main (main=0x8048a70 , argc=0x2, argv=0xbffff304,     init=0x80491e0 , fini=0x8049250 ,     rtld_fini=0xb7fedc90 , stack_end=0xbffff2fc) at libc-start.c:287#18 0x08048f67 in _start ()gdb-peda$
    src/目录下的是GoAhead程序源代码中的函数,可以看见程序在WebNormalizeUriPath函数中调用系统函数Free时发生了异常,并且调用WebNormalizeUriPath函数时传递的参数中有我们的畸形字符串函数
    调用链是这样的:MAIN(goahead, int argc, char **argv, char **envp)---> websServiceEvents(&finished) ---> socketProcess() ---> socketDoEvent(WebsSocket *sp) ---> socketEvent(int sid, int mask, void *wptr) ---> readEvent(Webs *wp) ---> websPump(Webs *wp) ---> parseIncoming(Webs *wp) ---> parseFirstLine(Webs *wp) ---> websNormalizeUriPath(char *pathArg) ---> wfree(dupPath)[释放dupPath堆块的时候发生异常,说明dupPath指向的堆块被破坏]
    因为这是开源软件所以我们可以对照着源代码追溯漏洞发生的原因.根据分析调用链发现#14处的函数调用并没有参数传递所以从这个函数往上的调用都可以直接排除,并且可以看出从readEvent函数开始连续传递wp参数,说明wp参数蛮可疑的,在源代码中看看Webs到底是什么类型.
[Asm] 纯文本查看 复制代码//src/goahead.h源文件代码/**    GoAhead request structure. This is a per-socket connection structure.    @defgroup Webs Webs*/typedef struct Webs {    WebsBuf         rxbuf;              /**< Raw receive buffer */    WebsBuf         input;              /**< Receive buffer after de-chunking */    WebsBuf         output;             /**< Transmit buffer after chunking */    WebsBuf         chunkbuf;           /**< Pre-chunking data buffer */    WebsBuf         *txbuf;    WebsTime        since;              /**< Parsed if-modified-since time */    WebsHash        vars;               /**< CGI standard variables */    WebsTime        timestamp;          /**< Last transaction with browser */    int             timeout;            /**< Timeout handle */    char            ipaddr[64];         /**< Connecting ipaddress */    char            ifaddr[64];         /**< Local interface ipaddress */    int             rxChunkState;       /**< Rx chunk encoding state */    ssize           rxChunkSize;        /**< Rx chunk size */    char            *rxEndp;            /**< Pointer to end of raw data in input beyond endp */    省略一些代码............
    Webs是一个结构体,存放着我们的畸形Get数据包。我们看到WebNormalizeUriPath函数参数是我们的畸形字串,所以可以到它的上层函数parseFirstLine函数中看一下调用WebNormalizeUriPath函数时的具体流程
[Asm] 纯文本查看 复制代码     //src/http.c源文件代码     省略一些代码............     /*        Parse the URL and store all the various URL components. websUrlParse returns an allocated buffer in buf which we        must free. We support both proxied and non-proxied requests. Proxied requests will have http://host/ at the        start of the URL. Non-proxied will just be local path names.     */    host = path = port = query = ext = NULL;    if (websUrlParse(url, &buf, NULL, &host, &port, &path, &ext, NULL, &query) < 0) {        error(&quot;Cannot parse URL: %s&quot;, url);        websError(wp, HTTP_CODE_BAD_REQUEST | WEBS_CLOSE | WEBS_NOLOG, &quot;Bad URL&quot;);        return;    }    if ((wp->path = websNormalizeUriPath(path)) == 0) {        error(&quot;Cannot normalize URL: %s&quot;, url);        websError(wp, HTTP_CODE_BAD_REQUEST | WEBS_CLOSE | WEBS_NOLOG, &quot;Bad URL&quot;);        wfree(buf);        return;    }    省略一些代码............
    在此函数中调用websNormalizeUriPath函数时给函数传递了一个变量path,此变量中存放的也就是我们的畸形字符串,那么变量path中的值又是如何来的?分析函数我们找到path是一个局部变量,被初始化为Null,然后调用websUrlParse函数把path的地址当做参数传递进去,调用完此函数后调用的就是websNormalizeUriPath函数,所以我们推测path中的畸形字符串应该是被websUrlParse函数写入进去的,为了准确我们可以动态调试一下
    重启GoAhead,ps -ef查看PID,gdb attech PID附加程序,因为我们有源代码,所以在gdb中直接用websUrlParse函数名进行下断,若我们没有源代码的话可以用IDA反汇编,在函数地址处进行下断,这里直接用函数名下断点b websUrlParse
[Asm] 纯文本查看 复制代码gdb-peda$ b websUrlParsereakpoint 1 at 0xb7fb5f60: file src/http.c, line 3018.gdb-peda$
    断点设置成功,输入C命令让程序继续运行,运行POC给GoAheadWebServer发送畸形Get数据包,gdb马上就断了下来
[Asm] 纯文本查看 复制代码[------------------------------------------------------------------------------]Legend: code, data, rodata, valueBreakpoint 1, websUrlParse (url=0x805d89c &quot;/1234567/./89abcdef&quot;, 'x' , &quot;/.gh&quot;,     pbuf=0xbffff110, pprotocol=0x0, phost=0xbffff0fc, pport=0xbffff108, ppath=0xbffff104,     pext=0xbffff10c, preference=0x0, pquery=0xbffff100) at src/http.c:30183018        {gdb-peda$
    此时websUrlParse函数的参数如上图所示,path变量对应着ppath,因为此函数传入的是path变量的地址是一个指针,所以我们看到的是ppath,我们看一下此时path变量中的值是什么,
[Asm] 纯文本查看 复制代码gdb-peda$ x/100x 0xbffff1040xbffff104:        0x00000000        0x00000000        0x00000000        0xbffff170
    此时path中的值为0x00000000,然后反编译websUrlParse函数gdb-peda$ Disas websUrlParse,查找ret指令的地址,并且在函数末尾处下一个断点
    b *0xb7fb614e   
[Asm] 纯文本查看 复制代码 0xb7fb6408 :    pop    ebx   0xb7fb6409 :    pop    esi   0xb7fb640a :    pop    edi   0xb7fb640b :    pop    ebp   0xb7fb640c :    ret   0xb7fb640d :    lea    esi,[esi+0x0]   gdb-peda$ b *0xb7fb614e   Breakpoint 2 at 0xb7fb614e: file src/http.c, line 3150.
    然后执行C命令直接运行到函数末尾
[Asm] 纯文本查看 复制代码Breakpoint 2, 0xb7fb614e in websUrlParse (    url=0x805d89c &quot;/1234567/./89abcdef&quot;, 'x' , &quot;/.gh&quot;, pbuf=0xbffff110,     pprotocol=0x0, phost=0xbffff0fc, pport=0xbffff108, ppath=0xbffff104, pext=0xbffff10c,     preference=0x0, pquery=0xbffff100) at src/http.c:31503150        }
    此时我们再看看path中的值,可以看到path确实是被websUrlParse函数设置为了指向我们的畸形字符串.gdb-peda$ x/100x *0xbffff104
[Asm] 纯文本查看 复制代码0x805b8a0:        0x3332312f        0x37363534        0x382f2e2f        0x636261390x805b8b0:        0x78666564        0x78787878        0x78787878        0x787878780x805b8c0:        0x78787878        0x78787878        0x78787878        0x787878780x805b8d0:        0x78787878        0x78787878        0x78787878        0x672e2f780x805b8e0:        0x00000068        0x00000000        0x00000000        0x00000000
    注意:这里为什么需要解引用?答:因为0xbffff104中存放的是path的值,而path本身就是一个指针,我们需要取这个指针中的内容所以需要解引用.//src/http.c源文件代码
[Asm] 纯文本查看 复制代码static void parseFirstLine(Webs *wp){    char    *op, *protoVer, *url, *host, *query, *path, *port, *ext, *buf;     int     testPort;    省略一些代码............
    websNormalizeUriPath传入的参数是我们的畸形字符串,再来分析websNormalizeUriPath函数
    此函数中分配堆空间的地方有3处,strcpy函数使用有2处   
    第一处:逻辑比较简单,应该没什么问题   
[Asm] 纯文本查看 复制代码    len = (int) slen(pathArg);                  //计算传入的payload长度,赋值给len    if ((dupPath = walloc(len + 2)) == 0) {     //dupPath指向 申请len+2大小的堆空间        return NULL;    }    strcpy(dupPath, pathArg);                   //把传入的payload拷贝到新开辟的堆空间中//申请len+1大小的堆空间    if ((segments = walloc(sizeof(char*) * (len + 1))) == 0) {        return NULL;
    第二处:这一块的逻辑比第一处的逻辑稍微复杂一点,问题可能会出在这里
[Asm] 纯文本查看 复制代码//下面为分配堆空间,拷贝数据    nseg = j;                                   //nseg == j    assert(nseg >= 0);                          //断言nseg大于等于零//分配了(len + nseg + 1)大小的堆空间,path指向if ((path = walloc(len + nseg + 1)) != 0) {//dp也指向新申请的空间,循环次数nseg        for (i = 0, dp = path; i < nseg; ) {    //这里有一个拷贝函数,循环运行记录每次拷贝的大小,总和是否会大于(len + nseg + 1)            strcpy(dp, segments);            len = (int) slen(segments);            dp += len;            if (++i < nseg || (nseg == 1 && *segments[0] == '\0' && firstc == '/')) {                *dp++ = '/';            }        }        *dp = '\0';    }    wfree(dupPath);                         //释放dupPath(再次发生异常)    wfree(segments);
    先调试获取分配给dp的内存到底有多大(len + nseg + 1),在websNormalizeUriPath处下断点,C继续运行,断点断在websNormalizeUriPath函数处.
[Asm] 纯文本查看 复制代码gdb-peda$ b websNormalizeUriPathBreakpoint 3 at 0xb7fb63e0: file src/http.c, line 3158
[Asm] 纯文本查看 复制代码[------------------------------------------------------------------------------]Legend: code, data, rodata, valueBreakpoint 3, websNormalizeUriPath (    pathArg=0x805b8a0 &quot;/1234567/./89abcdef&quot;, 'x' , &quot;/.gh&quot;) at src/http.c:31583158        {gdb-peda$
    gdb-peda$ disas websNormalizeUriPath      //反汇编websNormalizeUriPath函数
[Asm] 纯文本查看 复制代码0xb7fb6524 :   jg     0xb7fb6500    0xb7fb6526 :   lea    esi,[esi+0x0]   0xb7fb6529 :   lea    edi,[edi+eiz*1+0x0]   0xb7fb6530 :   sub    esp,0xc   0xb7fb6533 :   mov    eax,DWORD PTR [esp+0x18]   0xb7fb6537 :   lea    eax,[esi+eax*1+0x1]                                     //eax = (len+nseg+1)   0xb7fb653b :   push   eax   0xb7fb653c :   call   0xb7fad990                                  //walloc()   0xb7fb6541 :   mov    DWORD PTR [esp+0x28],eax                                //path = walloc()函数的返回值   0xb7fb6545 :   add    esp,0x10   0xb7fb6548 :   test   eax,eax                                                 //检测堆空间是否申请超过那个   0xb7fb654a :   je     0xb7fb65a1                    //若返回值等于0则跳转   0xb7fb654c :   test   esi,esi   0xb7fb654e :   je     0xb7fb6642    0xb7fb6554 :   mov    DWORD PTR [esp+0x10],esi   0xb7fb6558 :   xor    edi,edi   0xb7fb655a :   mov    esi,ebp   0xb7fb655c :   mov    ebp,eax   0xb7fb655e :   jmp    0xb7fb6566    0xb7fb6560 :   lea    ebp,[eax+0x1]   0xb7fb6563 :   mov    BYTE PTR [eax],0x2f   0xb7fb6566 :   mov    ecx,DWORD PTR [esi+edi*4]   0xb7fb6569 :   sub    esp,0x8   0xb7fb656c :   add    edi,0x1   0xb7fb656f :   push   ecx   0xb7fb6570 :   mov    DWORD PTR [esp+0x18],ecx   0xb7fb6574 :   push   ebp   0xb7fb6575 :   call   0xb7fad8a0                               //strcpy(dp, segments);   0xb7fb657a :   mov    ecx,DWORD PTR [esp+0x1c]   0xb7fb657e :   mov    DWORD PTR [esp],ecx   0xb7fb6581 :   call   0xb7fad690                                 //len = (int) slen(segments);   0xb7fb6586 :   add    esp,0x10   0xb7fb6589 :   add    eax,ebp   0xb7fb658b :   cmp    edi,DWORD PTR [esp+0x10]   0xb7fb658f :   jl     0xb7fb6560    0xb7fb6591 :   cmp    DWORD PTR [esp+0x10],0x1   0xb7fb6596 :   je     0xb7fb664b    0xb7fb659c :   mov    ebp,esi   0xb7fb659e :   mov    BYTE PTR [eax],0x0   0xb7fb65a1 :   sub    esp,0xc   0xb7fb65a4 :   push   DWORD PTR [esp+0x20]   0xb7fb65a8 :   call   0xb7fad370                                 //wfree(dupPath);   0xb7fb65ad :   mov    DWORD PTR [esp],ebp   0xb7fb65b0 :   call   0xb7fad370                                 //wfree(segments);
    根据查找几个关键函数可以定位到0xb7fb653c处对应的大概就是walloc(len + nseg + 1)),传入参数存放在eax处,在0xb7fb653c处下断,C命令继续执行,中断于0xb7fb653c
[Asm] 纯文本查看 复制代码[------------------------------------------------------------------------------]Legend: code, data, rodata, valueBreakpoint 4, 0xb7fb653c in websNormalizeUriPath (    pathArg=0x805b8a0 &quot;/1234567/./89abcdef&quot;, 'x' , &quot;/.gh&quot;) at src/http.c:32153215            if ((path = walloc(len + nseg + 1)) != 0) {gdb-peda$
    查看当前eax的值eax == 0x42,也就是说程序分配了0x42(66)个字节大小的空间,并让path指向其首地址
[Asm] 纯文本查看 复制代码gdb-peda$ print /x $eax$1 = 0x42
    再调试运行到拷贝segments元素到dp内存的循环内,循环调试看最后到底拷贝了多少字节的数据到dp中,我们在这条指令len = (int) slen(segments)对应的汇编位置下一条处下断,看slen函数返回值b *0xb7fb6586  
[Asm] 纯文本查看 复制代码   gdb-peda$ b *0xb7fb6586   Breakpoint 5 at 0xb7fb6586: file src/http.c, line 3220.   0xb7fb6575 :   call   0xb7fad8a0                               //strcpy(dp, segments);   0xb7fb657a :   mov    ecx,DWORD PTR [esp+0x1c]   0xb7fb657e :   mov    DWORD PTR [esp],ecx   0xb7fb6581 :   call   0xb7fad690                                 //len = (int) slen(segments);   0xb7fb6586 :   add    esp,0x10
    我们还应该在这个for循环结束的时候下一个断点,这样我们循环结束以后程序就不至于跑飞,我们在wfree(dupPath)对应的汇编位置下断b *0xb7fb65a8
[Asm] 纯文本查看 复制代码0xb7fb65a8 :   call   0xb7fad370                                 //wfree()释放内存[Asm] 纯文本查看 复制代码gdb-peda$ b *0xb7fb65a8Breakpoint 6 at 0xb7fb65a8: file src/http.c, line 3226
    关键断点设置完毕以后我们就开始循环执行,观察每次循环执行slen函数的返回值
[Asm] 纯文本查看 复制代码[----------------------------------registers-----------------------------------]EAX: 0x0 EBX: 0xb7fd851c --> 0x303c4 ECX: 0xf7fa4708 EDX: 0x8
[Asm] 纯文本查看 复制代码[----------------------------------registers-----------------------------------]EAX: 0x7 EBX: 0xb7fd851c --> 0x303c4 ECX: 0xf7fa4709 EDX: 0x0
[Asm] 纯文本查看 复制代码[----------------------------------registers-----------------------------------]EAX: 0x32 ('2')EBX: 0xb7fd851c --> 0x303c4 ECX: 0x3 EDX: 0x5
[Asm] 纯文本查看 复制代码[----------------------------------registers-----------------------------------]EAX: 0x32 ('2')EBX: 0xb7fd851c --> 0x303c4 ECX: 0x3 EDX: 0x5
[Asm] 纯文本查看 复制代码[------------------------------------------------------------------------------]Legend: code, data, rodata, valueBreakpoint 6, 0xb7fb65a8 in websNormalizeUriPath (    pathArg=0x805b8a0 &quot;/1234567/./89abcdef&quot;, 'x' , &quot;/.gh&quot;) at src/http.c:32263226            wfree(dupPath);gdb-peda$
循环结束,程序命中了我们设置在释放函数处的断点,然后我们来计算一下拷贝的总长度,看是否大于dp指向的堆空间的大小(0x42(66))
    拷贝总数:0x0 + 0x7 + 0x32 + 0x32 = 0x6B因为0x6B>0x42
    所以此次的拷贝存在堆溢出,我们单步运行程序,程序在释放dupPath指向的堆空间的时候出发了异常,
[Asm] 纯文本查看 复制代码[------------------------------------------------------------------------------]Legend: code, data, rodata, valueStopped reason: SIGABRT0xb7fdebe0 in __kernel_vsyscall ()gdb-peda$
    单步前dupPath中的值
[Asm] 纯文本查看 复制代码gdb-peda$ x/10x dupPath0x805b938:        0x33323100        0x37363534        0x38002e00        0x636261390x805b948:        0x78666564        0x78787878        0x78787878        0x787878780x805b958:        0x78787878        0x78787878
    异常触发原因应该就是之前的堆溢出覆盖了dupPath指向的堆空间,导致堆空间被破坏,Free堆的时候触发unlink操作,会把当前要释放的堆块进行脱链,脱链的过程取决于堆块的前向指针与后向指针,但是因为前向指针与后向指针被覆盖为了无效指针,所以发生异常.
    找到了溢出现场,那是什么原因造成的拷贝数据过多呢?
    分析一下程序解析url的代码
        len + nseg + 1
           len     //畸形字符串的有效字符总数
           nseg    //segments数组的元素个数,此个数用来后期填充为'/'的个数
           1       //用于填充结尾'\0'字符
    因为程序员在写程序时考虑不全,没把.x这类字符串考虑进去,所以若畸形字符串中包含.x的时候程序不对其进行任何处理直接i++,j++,这样segments数组中所对应的指针也就没有进行处理,

    第一次for循环去除'/',没毛病
        segments[0] ==
        segments[1] == 1234567
        segments[2] == .
        segments[3] == 89abcdef
        segments[4] == .gh
[Asm] 纯文本查看 复制代码//遍历dupPath指向的字符串的每一个字符,以'/'为分隔符并且把每个'/'替换为'\0'便于把分割出来的每段字符串首地址放到segments数组中    for (mark = sp = dupPath; *sp; sp++) {      //初始化变量 mark,sp,dupPath全指向畸形字符串,循环次数为畸形字符串的字符个数        if (*sp == '/') {                       //当遇到’/’则进入            *sp = '\0';                         //把当前sp指向的’/’赋值为’\0’            while (sp[1] == '/') {              //若sp指向的元素的下一个元素也等于’/’则进入                sp++;                           //sp++ 指向下一个元素,直到sp指向的元素的下一个元素不等于’/’时退出循环            }            segments[nseg++] = mark;            //把mark赋值给segments数组的第nseg个元素,然后nseg++,mark指向畸形字符串首地址            len += (int) (sp - mark);           //计算sp - mark的差,len最后等于所有有效字符的个数,            mark = sp + 1;                      //mark指向sp + 1  ,加1是因为当前sp=’\0’所以需要加1指向下一个有效字符        }    }    //因为sp要领先几步,所以循环完毕以后还需在做一次与循环同样的处理    segments[nseg++] = mark;                    //segmaents的第nseg个元素等于mark,nseg++,末尾添加一个'\0'用以结尾    len += (int) (sp - mark);                   //len += 计算sp - mark的差,//这轮循环过后,len == 畸形字符串去除所有'/'的字符总数.

    第二次for循环去除'.'
          [======]segments[0] ==
          [======]segments[1] == 1234567
          [======]segments[2] == 89abcdef
          [======]segments[3] == 89abcdef
[Asm] 纯文本查看 复制代码for (j = i = 0; i < nseg; i++, j++) {          //j,i=0,循环次数nseg-1        sp = segments;                       //把segments的第i个元素赋值给sp,sp分别指向每一个被分割出来的字符串        if (sp[0] == '.') {                     //如果sp[0]等于’.’,则进入            if (sp[1] == '\0')  {               //如果sp[1]等于’\0’,则进入 检测当前sp指向的字符是否为’.’                if ((i+1) == nseg) {            //判断当前i的值是否已经到了最大值,也就是segments数组的最后一个元素                    segments[j] = &quot;&quot;;           //如果已经到达最后一个元素,则把segments的第j个元素赋值为空                } else {                        //否则j--,与for循环中的条件表达式的j++相互抵消,                    j--;                        //如果sp指向’.’但是又没有又没有到达数组的最后一个元素,那么j不变                }            } else if (sp[1] == '.' && sp[2] == '\0')  {//检测当前sp指向的是否为&quot;..&quot;                if (i == 1 && *segments[0] == '\0') {   //若i==1并且segments[0] == ’\0’                    j = 0;                              //j赋值为0                } else if ((i+1) == nseg) {     //判断当前i的值是否已经到了最大值,也就是segments数组的最后一个元素                    if (--j >= 0) {             //若j自减之后还 >= 0,则说明j小都为1                        segments[j] = &quot;&quot;;       //segments的第j个元素赋值为空                    }                } else {                    j = max(j - 2, -1);         //比较j-2与-1,把最大的值赋值给j                }            }        } else {            segments[j] = segments;         //把第i个元素直接赋值给第j个元素        }    }
    循环时第[0]个字符串指针和第[1]个字符串指针没什么问题都没包含'.'直接赋值,
    处理第[2]个字符串指针时因为字符串指针指向的是'.'所以跳过本次的赋值,
    处理第[3]个字符指针时,因为不包含'.'所以赋值到数组第[2]个位置上,
    理第[4]个字符串指针时因为指向的是'.gh',程序没有对其进行处理,所以值还是原来的值,这样就导致多出了一个字符串指针,[2][3]指向的是同一段字符串,拷贝的时候拷贝了两次,这样的话就会导致最开始申请的缓冲区存放不了多出的字符
    构造出类似这样的畸形字符串/1234567/./89abcdef/.gh;并且③号处的字符必须比④号处的字符长度要大许多,不然为④号字符串分配的缓冲区会填补上第二次拷贝③号字符串时所需的缓冲区。
        
    对CVE-2014-9707漏洞成因的分析,记录了详细的操作过程,写的不好或理解不对的地方希望可以指出,谢谢!
    附件链接:http://pan.baidu.com/s/1pLRnLtp 密码:z2k8


来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
楼主热帖
回复

使用道具 举报

*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|12558网页游戏私服论坛 |网站地图

GMT+8, 2024-5-5 22:52 , Processed in 0.093750 second(s), 31 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表