웹해킹을 14년도 이전에 시작한 고인물이라면
PHP 5.4 이전에서 HEAD 메소드로 요청 시 첫번째 echo 에서 스크립트가 중단되는
HEAD method trick 에 대해 들어본적 있을 것입니다.
또한 그렇지 않더라도 에러를 고의적으로 발생시켜서 코드의 뒷부분이 실행 안되도록 하는 유형의 문제, 또는
ignore_user_abort 지시자가 false 일 때 ESC 로 코드를 중단 시킬 수 있는 유형의 문제를
풀어보셨을 수도 있습니다.
그런데 이들 3 가지 트릭은 발생 원인이 같다는 사실 알고 계셨나요?
바로 PHP 의 zend_bailout 이라고 하는 Internal API 때문입니다.
(1) HEAD method trick
PHP 5.4 이전의 버전에서는 다음 코드가 원인이 되어 HEAD 메소드로 요청할 시
첫 번째 echo 까지 실행이 된 후 멈추는 현상이 존재했습니다.
워낙 오래된 트릭이고 패치 된지 오래이기 때문에 자세히 다루지는 않겠습니다.
php-5.3.5\main\SAPI.c line 315:
if (SG(request_info).request_method &&
!strcmp(SG(request_info).request_method, "HEAD")) {
SG(request_info).headers_only = 1;
php-5.3.5\main\output.c:php_ub_body_write line 699
if (SG(request_info).headers_only) {
if(SG(headers_sent)) {
return 0;
}
php_header(TSRMLS_C);
zend_bailout(); // this will stop script
}
(2) ignore_user_abort 지시자
PHP 소스코드 상의 main/main.c 의 2651 line 부터 시작되는 코드를 보게 되면
아래와 같이 ignore_user_abort 옵션에 따라 zend_bailout 의 호출 여부가 달라지는 것을 확인할 수 있습니다.
PHPAPI void php_handle_aborted_connection(void)
{
PG(connection_status) = PHP_CONNECTION_ABORTED;
php_output_set_status(PHP_OUTPUT_DISABLED);
if (!PG(ignore_user_abort)) {
zend_bailout();
}
}
ignore_user_abort 지시자가 false 라면 특정 조건을 만족할 때 bailout 을 유도할 수 있다는 말입니다.
이에 대해서는 wechall.net 의 Stop Us 문제를 풀어보는 것을 추천드립니다.
(3) 에러 발생
main/main.c 의 1387 line 부터 시작되는 코드에는 에러가 발생했을 시 E_DONT_BAIL 이 false 라면
zend_bailout 을 호출하는 사실을 알 수 있습니다.
case E_RECOVERABLE_ERROR:
case E_PARSE:
case E_COMPILE_ERROR:
case E_USER_ERROR:
EG(exit_status) = 255;
if (module_initialized) {
if (!PG(display_errors) &&
!SG(headers_sent) &&
SG(sapi_headers).http_response_code == 200
) {
(생략)
}
/* the parser would return 1 (failure), we can bail out nicely */
if (!(orig_type & E_DONT_BAIL)) {
/* restore memory limit */
zend_set_memory_limit(PG(memory_limit));
efree(buffer);
zend_objects_store_mark_destructed(&EG(objects_store));
zend_bailout();
return;
}
}
break;
}
(4) 결론
그렇다면 zend_bailout 에 대해 아는 것은 어떤 의의가 있을까요?
PHP 에서는 많은 함수들이 내부적으로 zend_bailout 을 사용하고 있습니다.
https://github.com/php/php-src/search?p=3&q=zend_bailout&unscoped_q=zend_bailout
zend_bailout 를 사용하는 함수들이 악용될 여지가 있는지 연구해보는 것은
이 글에 나와있지 않은 또 다른 취약점을 발굴해 낼 수도 있는
좋은 연구 주제가 되리라 생각됩니다.