※ 추가적인 취약점이 있다면, 알려주시면 감사하겠습니다.
▶ 취약점 1. eval
eval 함수는 인자로 입력된 문자열을 어플리케이션 코드로 실행하는 함수이다. php 뿐만이 아니라, python javascript 등 다른 언어에서도 똑같이 발생하는 취약점이다. 예를 들어, <?php eval("1+1"); ?> 를 입력하면 2를 반환한다. 진정한 문제는 eval이 원하는 프로그램 코드를 실행할 수 있다는데에 있다. 아래에 설명할 시스템함수를 입력해도 이를 php코드마냥 실행시켜버린다.
▶ 취약점 2. OS Command Function
많은 언어가 OS Command를 실행할 수 있도록 지원한다. 편의를 추구하려면 어쩔 수 없는 부분인 것 같다. 하지만, Command Injection에 대한 위협에 노출될 수 있다는 문제점이 존재한다. PHP의 경우, 많은 시스템 함수를 지원한다. 대표적인 예로, 외부 프로그램을 실행 결과를 text로 반환하는 system함수가 있으며, 아래와 같이 외부 프로그램 실행결과를 binary 형태와 함께 출력하는 passthru함수도 있다. passthru함수는 브라우저에게 직접 반환해야 하는 Unix의 binary data의 command가 필요한 경우 exec와 system을 대신해서 사용하는 함수이다. 나는 Linux를 사용해서 그런지 두 개의 출력에는 큰 차이가 없는 모습이다(binary 데이터가 알아서 변환된건지는 모르겠다. 아시는 분은 알려주시면 감사하겠습니다.).
exec함수 역시 system과 같이 외부 프로그램을 실행하는 함수이다. 다만, 다음과 같이 출력 중에서 마지막 한줄만 반환하는 모습을 확인할 수 있다.
이 외에도 php의 OS Command Function에는 shell_exec, backtick operator(ex.`ls`), popen, proc_open 등이 존재함을 확인할 수 있다.
▶ 취약점 3. File system Function
파일에 관련된 편의를 제공하기 위해서 File system Function 도 php는 지원한다. 어플리케이션에서 파일 시스템에 접근할 수 있는 함수들의 인자가 사용자의 입력 데이터 또는 변조될 가능성이 있는 변수들을 사용할 경우 서버의 파일 시스템을 공격하거나, 다른 취약점으로 악용될 수 있다.
파일 시스템을 공격하여 발생할 수 있는 대표적인 서버의 피해는,
- File Read : 어플리케이션 코드, 설정 파일 정보 등의 노출
- File Write : WebShell 생성을 통한 원격 코드 실행 공격, 기존 설정 파일을 덮는 공격을 통해 운영체제 또는 어플리케이션 설정 변경
- Etc : 파일 복사를 통해 File Write 와 유사한 상황 발생, 설정 파일을 삭제하여 운영체제 또는 어플리케이션 서비스 무력화
php 에서 지원하는 Filesystem 함수로는 대표적으로
file_get_contents, fopen, readfile, show_source, highlight_file 가 있다. file_get_contents의 경우 전체파일을 문자열로 읽어들이는 php함수이고, fopen은 파일을 불러오고 읽거나 수정할 수 있는(ex. fopen("hello.txt","w")) 함수이고, readfile은 파일을 출력하는 함수이며(많은 경우, 파일 다운로드를 구현하기 위해서 사용함. 브라우저에서 지원하는 형식이 아니면 다운로드, 지원하는 형식이면 출력한다.), show_source는 highlight_file과 같은 기능을 하는 함수로써 색깔로 해당페이지의 소스코드를 노출한다. 워게임을 많이해본 사람들은 익숙할 것이다.
▶ 취약점 4. Serialize /Deserialize (직렬화 / 역직렬화)
Python 취약점 문제를 풀면서 학습했었던 내용같은데, php와 javascript(NodeJS)에도 똑같은 문제를 가지고 있다고 한다.
php의 deserialize 공격에서는 Object의 특수한 상황에서 실행되어지는 "Magic Methods"를 이용한다. 주로 사용하는 Magic Methods는, 소멸자의 개념으로 오브젝트 소멸 시에 호출되는 __destruct() 와 역직렬화 시에 호출되는 __wakeup()이 있다. Magic Methods의 예시는 아래와 같다.
<?php class Test{ function __wakeup(){ echo "Call __wakeup.\n"; } function __destruct(){ echo "Call __destruct.\n"; } function __construct(){ echo "Call __construct.\n"; } } echo "New Class.\n"; $obj = new Test(); echo "unserialize Class.\n"; $serialize_Data = 'O:4:"Test":0:{}'; $obj = unserialize($serialize_Data); |
Unserialize에 호출되는 Magic Methods 로직의 취약점이 존재하거나, 클래스의 데이터를 조작하여 공격을 연계해야 한다.
<?php class Test{ var $func_name = "var_dump"; var $argv = "test"; function __destruct(){ call_user_func($this->func_name, $this->argv); } } $obj = new Test(); $serialize_Data = 'O:4:"Test":2:{s:9:"func_name";s:6:"system";s:4:"argv";s:2:"id";}'; $obj = unserialize($serialize_Data); |
▶ 취약점 5. LFI / RFI (local file inclusion / Remote file Inclusion)
해당 링크를 참고하자. 파일 취약점 공격에서 이미 한 번 다뤘기 때문에, 자세한 설명은 생략하도록 하겠다.
include, include_once, require, require_once 와 같은 함수들에 의해서 파일을 로드하면서 발생하는 문제이다.
▶ 취약점 6. Wrapper
해당 링크를 참고하자. 이미 PHP 취약점으로 언급했으므로, 여기서도 자세한 설명은 생략하도록 하겠다.
▶ 취약점 7. Extract
PHP의 extract 함수는 배열에서 변수를 가지고 온다고 한다. extract 함수는 기존에 사용되고 있는 변수의 데이터를 덮을 수 있다는 특징이 있다. 따라서 extract 함수에 사용자의 입력($_GET, $_POST, $_FILE)와 같은 신뢰할 수 없는 데이터가 사용되면 다른 변수를 변조하여 공격에 사용될 수 있다고 한다. 이를 이용하는 문제가 webhacking.kr의 24번 문제이다.

해당 소스코드를 보면 extract로 $_SERVER를 불러온 후, $_COOKIE로 쿠키를 불러온다. $_SERVER를 불러오면 다음과 같은 데이터들이 배열의 형태로 불려오게 된다.
$_SERVER['DOCUMENT_ROOT'] = 현재 사이트가 위치한 서버상의 위치 = webappinclude $_SERVER['HTTP_ACCEPT_ENCODING'] = 인코딩 방식 = gzip, deflate $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 언어 = ko $_SERVER['HTTP_USER_AGENT'] = 사이트 접속한 사용자 환경 = Mozilla4.0(compatible; MSIE 6.0; Windows NT 5.1; Q312461; .NET CLR 1.0.3705 $_SERVER['REMOTE_ADDR'] = 사이트 접속한 사용자 IP = xxx.xxx.xxx.xxx $_SERVER['SCRIPT_FILENAME'] = 실행되고 있는 위치와 파일명 = webappincludeindex.php $_SERVER['SERVER_NAME'] = 사이트 도메인 = WWW.X2CHI.COM $_SERVER['SERVER_PORT'] = 사이트가 사용하는 포트 = 80 $_SERVER['SERVER_SOFTWARE'] = 서버의 소프트웨어 환경 = Apache1.3.23 (Unix) PHP4.1.2 mod_fastcgi2.2.10 mod_throttle3.1.2 mod_ssl2.8.6 OpenSSL0.9.6c $_SERVER['GATEWAY_INTERFACE'] = cGI 정보 = CGI1.1 $_SERVER['SERVER_PROTOCOL'] = 사용된 서버 프로토콜 = HTTP1.1 $_SERVER['REQUEST_URI'] = 현재페이지의 주소에서 도메인 제외 = index.phpuser=&name= $_SERVER['PHP_SELF'] = 현재페이지의 주소에서 도메인과 넘겨지는 값 제외 = index.php $_SERVER['APPL_PHYSICAL_PATH'] = 현재페이지의 실제 파일 주소 = Dwebapp |
※출처 : https://unabated.tistory.com/entry/PHP-SERVER-%ED%95%A8%EC%88%98
Cookie값에 REMOTE_ADDR을 extract로 뒤집어씌울 수 있으니깐, 필터링된 이후의 cookie 값 설정을 REMOTE_ADDR=127.0.0.1 과 같이 설정하면 클리어할 수 있다. 따라서, 112277...00...00...1 와 같이 설정하게 console창에 document.cookie = "REMOTE_ADDR = 112277...00...00...1" 을 입력하면, 손쉽게 클리어할 수 있다. 필터링과 extract함수에 대한 기초적인 지식만 있어도 클리어할 수 있었던 문제.

▶ 취약점 8. Type Juggling
PHP의 서로 다른 타입인 변수를 비교 또는 연산 시 자동으로 형변환이 발생하며 의도치 않은 결과가 발생할 수 있다. Mysql에서 이러한 형변환으로 filtering bypass 하는 경우가 많았던 것 같다. 다음과 같이 연산이 이상하게 되는 경우도 있다.
<?php $a = "a"; // String $b = "2"; // String echo $a * 2; // 0 echo $b * 2; // 4 /* String과 integer 비교 또는 연산 시 앞 문자열이 숫자로 시작할 경우 해당 숫자를 사용하여 연산합니다. 아닌 경우에는 0으로 처리됩니다. */ $a = "a"; $b = ""; var_dump($a == True); // bool(true) var_dump($b == True); // bool(false) /* String과 Boolean 타입 비교 또는 연산 시 문자열의 내용이 존재하면 True, 빈 문자열인 경우 False로 처리됩니다. */ |
▶ 취약점 9. Comparison
취약점 8. Type juggling에 의해서, 서로 다른 타입이 비교 연산자에서 사용될 경우 의도치 않은 결과가 발생할 수도 있다. 따라서 비교 연산자를 사용할 때 비교하는 두 변수의 타입이 다르면 형변환이 일어날 수도 있으니, 동일한 타입인지도 비교하는 엄격한 비교연산자(===, !==)를 써야한다. 이로 인해 발생하는 PHP의 허점 중 유명한 예시가 strcmp 함수이다. 인자를 비교하고 같으면 0, 앞쪽이 작으면 음수를, 뒤쪽이 작으면 양수를 반환한다. string이 아닌 array를 인자로 전달하게 되면 NULL을 반환하게 되는데, NULL과 0을 느슨한 비교(==)로 수행하면 Null을 0으로 형 변환 시켜서 비교할 변수를 array혀식으로 전달하면, var_dump(strcmp("a", array()) == 0); 값이 True로 반환되는 쇼킹한 결과를 초래할 수 있다.
이걸 wargame으로 구현한 wargame.kr 문제 중에 'strcmp'라는 문제가 있다.

POST 형식으로 받은 password 파라미터를 문제에서 생산한 password값과 비교하는 형식이다. strcmp값을 null로 만들어주면 clear될 듯 싶다. 따라서 password 파라미터를 array형식으로 만들어주면 되고, 이는 password[] = @@ 와 같은 payload로 구성이 된다. 이를 전송하면, 다음과 같이 flag를 출력한다.

▶ 취약점 10. Session
PHP의 세션 로직은 다음과 같다. HTTP Request에서 쿠키를 가져와 PHPSESSID의 값을 가져온 뒤, PHPSESSID값이 존재하지 않으면 랜덤한 값의 PHPSESSID를 생성하고 세션 변수에 ($_SESSION) 빈 array를 할당한다. PHPSESSID값이 있다면 해당 PHPSESSID에 해당하는 값을 세션 변수에 ($_SESSION) 로드한다.
세션에 사용자의 입력 데이터가 들어가게 될 경우, 다른 공격과 연계하여 사용될 수 있다. 만약, include 함수의 인자를 조작가능하고 인자에 대한 검증이 없는 페이지에서 세션 파일을 include 인자로 넘겨 원하는 PHP코드를 실행할 수 있다.
session.php <?php session_start(); $_SESSION['name'] = $_GET['name']; // 사용자 입력 데이터를 세션에 저장. |
위와 같은 코드가 있을 때, /session.php?name=<?php system('id');?>와 같이 입력하면, php 코드를 세션에 삽입할 수 있다(log에 삽입해서 include하는 경우와 비슷한 것 같다. ). cat sess_{세션번호} 를 입력하게 되면 id <?php system('id');?>가 삽입된 것을 확인해볼 수 있다.
이후에 해당 LFI취약점이 있는 페이지가 다음과 같은 코드로 구성되어 있다고 가정하자.
index.php <?php include $_GET['page']; // 사용자의 입력 데이터를 기반으로 include 실행. |
해당 페이지에서 /index.php?page=/var/lib/php/sessions/sess_{세션번호} 와 같이 세션 파일을 include하여 세션 파일의 php 코드를 실행하는 공격이 가능하다.
▶ 취약점 11. Upload Logic
PHP 홈페이지를 만들어봤다면 공감할 내용인데, PHP 파일 저장은 tmp 디렉토리에 잠깐동안 내가 업로드할 파일을 업로드하고 옮기는 과정으로 이루어진다. 참고로 임시로 생성되는 php파일의 양식 은 "php[a-zA-Z0-9]{6}"과 같다. 여기서 생기는 문제는 다음과 같다.
[1] php 코드상에서 업로드 기능을 구현하지 않아도 사용자가 서버의 임시 디렉토리에 업로드 가능.
[2] Unhandled exception(php엔진에 문제 발생 segmentation fault)에서 php 로직이 정상적으로 종료도지 않아 임시 디렉토리에 업로드한 파일을 삭제하지 못함.
[3] 예측 가능한 임시 파일 생성 규칙: php[a-zA-Z0-9]{6} , Unhandled exception으로 임시 디렉토리 내에 임시 파일이 삭제되지 않도록하고, 같은 파일 데이터를 가진 파일을 무한히 업로드하면 무작위 대입공격을 통해 충분히 예측가능한 범위까지 줄일 수 있다.
파일 업로드 내부 로직에서 발생할 수 있는 문제점이 include 또는 파일 시스템에서 발생하는 취약점과 연계된다면 서버의 명령어를 실행시키는 등의 공격으로 연계될 수도 있다.
'정보보안(웹해킹) > 기타' 카테고리의 다른 글
인증/인가 취약점 (0) | 2022.12.30 |
---|---|
CRLF injection (0) | 2022.12.22 |
CSS Injection (0) | 2022.12.19 |
[PHP취약점] php wrapper (0) | 2022.11.26 |
댓글