CentOS의 Contorl Web Panel (CWP)에서 file inclusion vulnerability이 보고되었다.
직접 취약점을 상세히 분석하고 재현해보진 않았지만 접근 과정이 흥미있어 공개된 내용을 참고하여 정리 해본다. Control Web Panel의 ‘/user/loader.php’와 ‘/user/index.php’는 인증 과정 없이 접근이 가능한 페이지로 아래와 같은 include 구문을 포함한다.
<?php if(!empty($_GET["api"])) { … if (!empty($_GET["scripts"])) { $_GET["scripts"] = GETSecurity($_GET["scripts"]); include "../../resources/admin/scripts/" . $_GET["scripts"] . ".php"; } …
PHP의 include()와 require() 함수는 로컬 또는 원격의 파일을 읽어 PHP 스크립트로 실행하는 함수로서 공격자의 악의적인 코드를 포함한 파일이 읽혀지도록 함수에 전달하는 방식으로 오래전부터 공격의 포인트로 활용되었다. CWP는 Include 공격을 방어하기 위하여 아래의 코드가 사용되었다.
function GETSecurity($variable) { if (stristr($variable, ".." ) { exit("hacking attempt"); } }
공개된 보안 권고문에는 해당 방어 코드를 공략하기 위하여 아래와 같은 전략을 제시한다.
- Trick PHP to treat other characters as dot (.)
- Find unique characters the language C processes as a dot (.) when lower cased.
- Trick PHP into thinking there are no consecutive dots (..)
모두 stristr 함수에서 공격자가 입력을 원하는 ‘..’을 필터링 하지 못하기 위한 방법이다. 여기에는 한가지 더 중요한 사항이 필요한데 단순히 필터링을 우회하는것이 아닌 이후의 include 구문에서 원하는 행동을 처리할 수 있어야만 한다. 여기에서 원하는 행동은 공격자가 원하는 임의의 파일을 include 하는 것이다.
취약점 발견자는 3가지 전략을 검증하였고 이 중 3번에서 유효한 방식을 찾아내었다. 그 방법은 상당히 고전적으로 NULL 값인 “%00″을 문자열 중간에 포함시키는 것이다. 코드를 정확하게 확인하지 않았지만 문자열 검증 함수와 PHP의 include 구문에 주입된 경로 값의 불일치로 인하여 검증을 우회하고 include 구문에서는 ‘../’의 역할을 수행하게 된다.
공개된 보안 권고문은 아래와 같은 요청을 전송하여 허가받지 않은 사용자가 원하는 API 권한을 등록하는 것을 보인다.
/user/loader.php?api=1&scripts= .%00./.%00./api/account_new_create&acc=guadaapi&ip=192.168.1.1&keyapi=OCTAGON
보다 상세한 내용은 발표된 보안 권고문을 참고하길 바란다.
내용 추가) 취약점을 해결하기 위한 패치가 발표되었지만 여전히 새로운 문제점이 나타나는 것을 Reddit의 댓글에서 지적하고 있다. 그리고 이후 아래의 문제 패치는 또다시 수정되었다고 한다.
function GETSecurity($variable) { if (stristr($variable, "..") || stristr($variable, ".%00./.%00.")) { exit("hacking attempt"); } $variable = trim($variable); $variable = str_replace("\0", "", $variable); return htmlspecialchars(strip_tags($variable)); }
기존의 공격 구문에서 조금만 변형을 하면 NULL 값 필터링에 포함되지 않도록 할 수 있다. 필터링 이후에 등장하는 태그 삭제 구문으로 인하여 태그 값을 경로 사이에 주입하여 필터링을 우회하는 것이 가능하다. 마치 필터링 우회 예제를 위하여 만들어진 것 같은 참신한 실제 취약점이다.
블랙 리스트에 의한 필터링 방식은 언제든지 우회될 수 있다. 가급적이면 화이트 리스트 방식으로의 전환이 필요하다.
Reference
CVE-2021-45467: CWP CentOS Web Panel – preauth RCE
잡담
아래는 그냥 주절 주절 개인적인 잡담이다.
문자열의 종료로 사용되는 널(NULL) 값은 오동작을 일으키게 하는 대표적인 값 중 하나다. 문자열을 다루는 비교적 복잡한 작업 중 하나인데 대소문자 구분, 문자열의 종료 방식, 구분자 등이 일관성 있고 정확하게 구현되어야 한다. 여기에 멀티바이트/유니코드까지 고려하면 가히 혼돈의 카오스라고 할 수 있다. 윈도우즈 개발에서 보안을 새롭게 등장한 문자열 처리 함수를 보면 짐작할 수 있다. 개선된 함수들을 사용할 수 있지만 용도에 맞게 정확하게 사용하는 것은 오로지 개발자의 몫이다.
이런 유형은 파일 경로를 처리하는 과정에서도 단골로 발생된다. Unix 계열과 Windows 파일 경로 처리와 과거로는 Windows와 DOS 파일 처리에서 문제점을 찾아볼 수 있다.
때문에 개발자 본인의 시스템에서의 검증 과정에서 취약점이 없다고 생각되는 솔루션이더라도 운영 환경에 따라 얼마든지 취약점이 발생될 소지가 있다. 훌륭한 솔루션이라고 하면 이러한 경우에도 대비책이 마련되어야 하겠지만 솔루션을 사용하는 기관/업체마다 운영환경이 천차만별이기 때문에 모든 경우를 대비한다라는건 사실상 불가능하다.
이것이 시스템에 설치된 솔루션만을 기계적으로 점검하는 것이 아닌 모의해킹을 직접 수행해야 하는 이유이다. 단순히 필터링 코드가 있다고 해서 당연히 안되겠거니 하고 건너뛰면 안되는 이유이다. 경력이 많은 사람들은 결과를 미리부터 지레 짐작하고서 불필요하다고 생각하는 작업은 거르게 되는데 그러다보면 간단하게 찾을 수 있는 취약점조차 놓치게 된다. 때문에 나는 고경력자 이외에 무식하게 맨땅에 헤딩할 수 있는 초짜 신입이 함께 작업하는것을 권유한다.
과거에는 이러한 꼼수들이 대단한 것처럼 인식되고 꽁꽁 감추어져 왔다. 인터넷 시기가 들어서며 정보의 교류가 활발해지다보니 마치 사부가 제자에게 비전을 전수하는 것과 같은 상황은 없어졌지만 그럼에도 실제 써먹을 만한 꼼수들은 잘 드러나지 않는 점은 똑같다. 나는 이러한 기술들이 단순한 팁과 같은 것이라 생각해왔지만 결국은 이러한 팁도 무수한 삽질을 해온 사람들이 발굴하는 거라고 생각한다. 정보의 홍수 시대에 와서 무엇이든 쉽게 얻을 수 있을거 같지만 막상 가치있는 정보들을 구하는건 여전히 어려운 일인것 같다.