풀이일 : 2023/06/29
문제에 접속해 보도록 하자.
다음과 같이 로그인 페이지가 나온다.
문제 정보에 따르면 해당 페이지는 php로 작성되었고,
알맞은 Nickname과 Password를 입력하면 step2로 넘어갈 수 있다.
step2에서는 system() 함수를 이용하여 플래그를 획득할 수 있고, 친절히 위치까지 알려주었다.
일단 알맞은 Nickname과 Password를 찾아 step2로 넘어가보도록 하자.
문제 파일을 다운받아 소스코드를 확인해 보도록 한다.
문제 파일에는 index.php와 step2.php가 있는데, 아래의 index.php에서는 유용한 정보를 획득하지 못했다.
다음으로 step2.php를 들여다보도록 하자.
소스코드를 훑어보다 보면, 각각 Nickname과 Password에 들어가야 하는 값인 name과 pw의 값이 그대로 노출되어 있는 것을 볼 수 있다.
name이 "dnyang0310", 그리고 pw가 "d4y0r50ng+1+13"과 일치하면 step2로 넘어갈 수 있다.
하지만 사용자로부터 입력받은 값에 필터링이 적용되어 해당 값들을 그대로 입력하면 제대로 로그인을 할 수 없다.
첫번째로 사용자로부터 입력받은 패스워드에 필터링이 적용된다. 입력한 패스워드에 소문자나 대문자가 포함되어 있다면 "alphabet in the pw :("이 화면에 출력된다.
비밀번호가 "d4y0r50ng+1+13"이어야 하는데 사용자가 입력하는 비밀번호에는 알파벳이 포함되면 안되는 것이다.
다음 필터링을 확인해 보자. 문제 이름이 phpreg인 만큼 php 정규표현식을 이용하여 필터링을 하고 있다.
preg_replace() 함수를 사용하여 사용자가 입력한 name에서 "nyang"을 빈 문자열로 필터링한다.
$name = preg_replace("/nyang/i", "", $input_name);
name의 값이 "dnyang0310"이어야 하므로 필터링을 우회하기 위해
"dnynyangang0310"이라는 Nickname을 입력하면 될 것 같다.
다음으로 pw의 필터링을 살펴보자. name보다는 더 복잡한 정규표현식을 이용하여 필터링을 하고 있다. 여기서 중요한 점은 이번에는 사용자의 입력값에서 정규표현식에 해당하는 값이 "d4y0r50ng"라는 비밀번호의 일부로 대체된다는 것이다. 사용자는 비밀번호에 알파벳을 입력할 수 없기 때문에 이를 잘 이용하여 로그인을 해야 한다.
$pw = preg_replace("/\d*\@\d{2,3}(31)+[^0-8]!/", "d4y0r50ng", $input_pw);
정규표현식을 하나하나 해체하여 살펴보자.
\d*
\d는 0에서 9까지의 범위의 한 자리 숫자를 의미한다.
*는 문자 또는 숫자가 0개 이상 나타나는 것을 의미한다.
-> 따라서 0~9 사이의 숫자가 0개 이상 나타나야 한다.
\@
@를 의미한다.
\d{2, 3}(31)
\d는 0에서 9까지의 범위의 한 자리 숫자를 의미한다.
{2, 3}은 앞에 작성한 표현을 2~3회 반복하라는 의미한다.
-> 0~9 사이의 숫자 2~3회 후에 31을 쓰면 된다.
지금까지의 표현을 1회 이상 반복한다.
[^0-8]
0~8 이외의 문자가 있으면 패턴이 매칭된다.
!
!를 의미한다.
위의 모든 요소를 조합하여 123@12319! 라는 문자열을 만들었다.
비밀번호는 "d4y0r50ng+1+13"이 되어야 하므로 뒤에 "+1+13"를 붙여
"123@12319!+1+13"을 비밀번호에 입력해보자.
로그인에 성공했다!!!
사용자의 입력값에 "flag"에 대한 필터링이 적용된다. 이를 유의하여 명령어를 작성해보자.
cat ../dream/f?ag.txt
플래그를 획득했다!
DH{ad866c64dabaf30136e22d3de2980d24c4da617b9d706f81d10a1bc97d0ab6f6}