strcmp 함수는 다들 알다시피 문자열을 비교하여 -1 또는 0 또는 1을 반환하는 함수이다.

  • strcmp('a', 'b') => -1
  • strcmp('b', 'b') => 0
  • strcmp('c', 'b') => 1

 

 

만약 admin인지 아닌지를 검사하는 코드가 있다고 가정하자.

<?php
	$test = $_GET['test'];

	if(!strcmp($test,"admin")){
		echo "yes";
	}
	else{
		echo "no";
	}

?>

 

 

아래와 같은 결과가 출력이 된다.

 

위와 같은 코드로 admin인지 문자열을 비교한 후 결과를 출력하게 된다.

 

만약 비교하는 문자열이 admin이 아니라 다른 값일 경우, 어떻게 strcmp 를 우회 할 수 있을까?

방법은 strcmp 리턴값에 있다. 비교하는 문자열이 어떤 값이든 0으로만 출력하게끔 값을 넣어주면 된다.

아래와 같은 코드를 작성해본 뒤, 접속해보면 이상한 결과가 출력이 된다.

<?php
	$test = Array('asdfasdf');

	if(!strcmp($test,"admin")){
		echo "yes";
	}
	else{
		echo "no";
	}

?>

 

test 라는 배열 변수에 이상한 값을 집어 넣어준 뒤 strcmp 로 admin이라는 값과 비교를 한다.

그런데 php warning 과 함께 yes 라는 값이 출력이 되었다.

 

 

 

실제로 var_dump 를 이용해서 strcmp($test, "admin") 의 리턴값을 보았다.

<?php
	$test = Array('asdfasdf');
    
	var_dump(strcmp($test,"admin"));
	var_dump(!strcmp($test,"admin"));
	var_dump(strcmp($test,"admin") == 0);
?>

 

test의 변수가 배열일때 strcmp로 비교하면 NULL이라는 값이 출력이 되었다.

이유는 strcmp 인자값으로 문자열이 들어오지 않을 경우 NULL을 리턴하게 된다.

2~3번째 줄에서 true가 나오는 이유는 아래와 같다.

아래 표를 참고하면 NULL 과 0을 == 연산하게 되면 True 가 나오는 이상한 상황이 일어나게 된다.

 

 

 

 

실제로 php 버전마다 어떠한 결과를 출력하는지 테스트 해본 결과 아래 사진처럼 출력이 되었다.

php 4.3 ~ 5.2.17 버전에서는 no 라고 뜨지만

php 5.3 ~ 7.34 버전에서는 yes라고 출력하는 것을 볼 수 있다.

 

테스트 사이트는 아래 링크에서 진행했다.

https://3v4l.org/oogMd

 

Online PHP editor | output for oogMd

Enable javascript to submit You have javascript disabled. You will not be able to edit any code. Output for 5.3.0 - 5.6.40, hhvm-3.10.1 - 3.21.3, 7.0.0 - 7.3.4Warning: strcmp() expects parameter 1 to be string, array given in /in/oogMd on line 4 yesOutput

3v4l.org

 


 

 

 

정리하자면, strcmp로 어떤 문자열을 비교하게 된다면 배열 형식으로 데이터를 보내면 우회가 가능하다.

아래 코드는 GET 방식으로 요청을 받을때 취약점이 발생하는 코드이다.

<?php
	$test = $_GET['test'];

	if(!strcmp($test,"admin")){
		echo "yes";
	}
	else{
		echo "no";
	}
?>

?test[]=asdfasdfasdf 와 같은 배열 형태로 값을 보내게 되면 yes라는 문구가 출력되는 것을 확인 할 수 있다.

 

 

마찬가지로 POST 방식으로도 가능하다.

<?php
	$test = $_POST['test'];

	if(!strcmp($test,"admin")){
		echo "yes";
	}
	else{
		echo "no";
	}
?>

 

fiddler로 패킷을 변조해서 보내게 되면 yes라는 문구가 출력이 된다.

 

 

 

따라서 strcmp 보다는 === 연산자를 사용하여 비교하는 것이 안전할 것이다.

아래 표는 === 연산자를 사용하여 == 보다 엄격한 비교를 하는 것을 보여주는 표 이다.