php7cmp4re


  • 인덱스 페이지로 접근하면 입력 폼과 제출 버튼을 확인할 수 있는데요.
  • 제출 버튼을 누르면 입력 폼에 입력한 값이 check.php 경로로 전달됩니다. (POST METHOD)


Analysis

  • 위 이미지의 좌측 입력 폼이 $input_1, 우측 입력 폼이 $input_2 에 해당합니다.
  • check.php 소스 내부를 살펴보면 다음과 같은 로직으로 동작하고 있습니다.
    • CASE 1) 입력 값이 공백인지 확인
    • CASE 2) $input_1 값의 길이가 4보다 작은지 확인
    • CASE 3) $input_1 값이 “8”보다 작고, “7.A”보다 작고, “7.9”보다 큰지 확인
      • 여기서 “8”, “7.A”, “7.9”를 ASCII 코드로 표현하면 아래와 같습니다.
        • “8.0” - 56 46 / “7.A” - 55 46 65 / “7.9” - 55 46 57
  • 따라서, CASE 3)의 부등식은 55 46 57 < $input_1 < 55 46 65 로 정리해 볼 수 있습니다.


  • 55 46 57 < $input_1 < 55 46 65 조건을 만족하기 위해서는 55 46 58~64 사이의 값을 입력하면 됩니다.
    • $input_1 입력 값으로 7.: (55 46 58) 를 입력한 결과 “Good Try” 텍스트가 출력되었습니다.
  • 이제 $input_2 입력 값 검증을 우회해야 합니다.


  • $input_2 입력 값 조건은 다음과 같습니다.
    • $input_2 입력 값의 길이가 3보다 작고, 1보다 커야 한다.
    • $input_2 입력 값은 숫자 74보다 작고, “74” 보다 커야 한다.
  • 주요 우회 포인트는 2번째 조건인데요. (“74” < $input_2 < 74) 를 만족하는 $input_2 값을 찾아야 합니다.
    • “74”는 ASCII 10진수 값으로 표현하면 55 52 가 됩니다.
    • “8X”로 표현하면 56 xx 가 되기 때문에 문자열 간 비교에서는 10의 자리에 55보다 큰 값(8, 9, …)을 입력하면 "74" < $input_2 조건은 통과할 수 있습니다.
    • 문제는 $input_2 < 74 조건인데요. PHP에서는 문자열과 정수를 비교할 때 숫자로 인식될 수 있는 문자열을 숫자로 변환하여 비교합니다. 그러므로, “8X” < 74 에서 X 값으로 숫자가 오게 되면 항상 False 를 반환하게 됩니다. 예를 들어 “80”을 입력하면 숫자 80으로 인식이 되기 때문이죠.
      • 이를 우회하기 위해서는 X 값으로 임의의 문자를 넣어볼 수 있는데요.
      • “8!” 를 입력하면 숫자와 비교할 때, 숫자로 인식될 수 있는 8만 빠져나오기 때문에 8 < 74 로 인식됩니다. 따라서 아래와 같은 검증 로직을 우회할 수 있게 됩니다.


  • $input_1, $input_2 검증 로직 우회 후 플래그 확인


🐛.. 🐛.. 🐛..


REFERENCE

  1. https://dreamhack.io/forum/qna/4950/
  2. https://www.php.net/manual/en/language.operators.comparison.php#language.operators.comparison.types
  3. https://github.com/php/php-src/blob/master/Zend/zend_operators.c