정보 · 테크
PHP 의 실행 중단 트릭의 원인: zend_bailout

웹해킹을 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 를 사용하는 함수들이 악용될 여지가 있는지 연구해보는 것은
이 글에 나와있지 않은 또 다른 취약점을 발굴해 낼 수도 있는
좋은 연구 주제가 되리라 생각됩니다.

#zend_bailout #head_method_trick #ignore_user_abort #triggering_error
작성자 정보
avatar
posix
대표 업적 없음
4년 전
팬이예요