Hack&Dev/Web

PHP - STRCMP [DREAMHCK] wargame.kr strcmp

스우스우03 2025. 3. 15. 21:55

1. PHP strcmp() 함수의 취약점 분석 (배열 이용)

PHP 7이하의 버전에서 취약함

1.1 개요

  • PHP의 strcmp() 함수는 문자열을 비교하는 함수로, 두 개의 문자열이 동일하면 0을 반환하고, 다르면 음수 또는 양수를 반환한다.
  • 하지만, 예상치 못한 데이터 타입(예: 배열)이 들어갈 경우 strcmp()의 동작이 비정상적으로 수행되며, 보안 취약점이 발생할 수 있다.

 

 

1.2 strcmp()의 기본 동작

  • PHP에서 strcmp()는 다음과 같이 동작한다.
  • <?php var_dump(strcmp("hello", "hello")); // int(0) var_dump(strcmp("hello", "world")); // int(-15) var_dump(strcmp("world", "hello")); // int(15) ?>
  • 위 코드에서 strcmp("hello", "hello")의 결과가 0이므로, 이를 if 조건문에서 사용하면 FALSE로 평가된다.
  • <?php if (strcmp("hello", "hello")) { echo "다름"; } else { echo "같음"; // 출력됨 } ?>

 

 

1.3 배열을 넣을 경우 발생하는 문제

  • PHP의 strcmp()는 두 개의 문자열을 비교해야 하지만, 배열을 넣으면 경고가 발생하며 NULL을 반환한다.
    • 그러나, 이 반환값 NULL은 if 문에서 TRUE로 평가될 수 있어 논리적 오류 및 보안 취약점으로 이어진다.
1.3.1 취약한 코드 예시
<?php
$password = "admin123";
$user_input = $_GET['password']; // 사용자가 입력한 값

if (!strcmp($password, $user_input)) {
    echo "로그인 성공!";
} else {
    echo "로그인 실패!";
}
?>
  • 위 코드에서 $_GET['password']에 배열을 전달하면??

 

1.3.2 공격 예제
curl "<http://example.com/login.php?password[]=hacked>"
  • PHP 내부에서 실행되는 strcmp() 함수:
strcmp("admin123", array());
  • 이 경우 PHP는 Warning: strcmp() expects parameter 2 to be string, array given이라는 경고를 발생시키고, 반환값으로 NULL을 반환한다. 중요한 점은 NULL이 if 문에서 TRUE로 평가된다는 점이다.
  • 즉, !NULL은 TRUE로 평가되므로 공격자는 로그인에 성공할 수 있다.

 

 

1.4 취약점이 발생하는 원인

  1. strcmp()는 두 개의 문자열만 비교해야 하지만, 타입 체크가 엄격하지 않아 배열이 들어가도 오류 없이 동작한다.
  2. strcmp()가 배열을 비교할 수 없을 때 NULL을 반환하며, NULL이 if 문에서 TRUE로 평가되는 논리적 문제를 초래한다.
  3. 이를 악용하면, 인증 우회 및 보안 우회 공격이 가능해진다.

 

 

1.5 해결 방법

  • 제일 안전한것은 PHP 8.0 이상으로 업그레이드 하는 것이다.

 

1.5.1 is_string()을 사용하여 입력값 검증
  • 입력값이 문자열인지 확인한 후 비교해야 한다.
<?php
$password = "admin123";
$user_input = $_GET['password'];

if (is_string($user_input) && strcmp($password, $user_input) === 0) {
    echo "로그인 성공!";
} else {
    echo "로그인 실패!";
}
?>

변경된 코드의 핵심

  • is_string($user_input)을 통해 배열이 입력될 경우 FALSE를 반환하여 strcmp()를 실행하지 않도록 방지.

 

1.5.2 === 연산자를 사용한 직접 비교
  • 문자열 비교에는 strcmp() 대신 === 연산자를 사용하는 것이 더욱 안전하다.
<?php
$password = "admin123";
$user_input = $_GET['password'];

if ($password === $user_input) {
    echo "로그인 성공!";
} else {
    echo "로그인 실패!";
}
?>

이 방법의 장점

  • === 연산자는 타입까지 정확히 비교하기 때문에, 배열 입력 시 자동으로 FALSE가 되어 보안 취약점을 예방할 수 있다.