[root-me]PHP register globals

우선, register_globals이 뭔지부터 알아보자.

register globals는 internal PHP setting이다.

서버에 액세스하는 방법을 제어하며,

ON상태와 OFF상태가 있다. 디폴트 값은 OFF이다(보안 문제 때문).

ON상태 - Global배열( GET[], POST[], REQUEST[] 등) 없이 양식 속성에 액세스 가능

OFF상태 - Global배열을 통해서만 모든 속성에 액세스 가능

OFF 상태인 경우, Global배열을 이용해서 파라미터를 받으면 액세스가 가능하다.

아무래도 보안에 취약한 점을 이용해서 문제를 냈을테니까,

register globals가 ON상태임을 예상할 수 있다.

먼저, 힌트에서 준 백업 파일을 찾아보자.

패스워드가 어떤 방식으로 인증을 거치는지 알아야 되니까, 소스코드가 필요하다.

url에 index.php.bak를 넣어서 백업파일을 다운로드받은 후에, 에디터를 이용해 파일을 열어주면 페이지 소스 코드를 얻을 수 있다.


<?php


function auth($password, $hidden_password){
    $res=0;
    if (isset($password) && $password!=""){
        if ( $password == $hidden_password ){
            $res=1;
        }
    }
    $_SESSION["logged"]=$res;
    return $res;
}



function display($res){
    $aff= '
  <html>
  <head>
  </head>
  <body>
    <h1>Authentication v 0.05</h1>
    <form action="" method="POST">
      Password&nbsp;<br/>
      <input type="password" name="password" /><br/><br/>
      <br/><br/>
      <input type="submit" value="connect" /><br/><br/>
    </form>
    <h3>'.htmlentities($res).'</h3>
  </body>
  </html>';
    return $aff;
}



session_start();
if ( ! isset($_SESSION["logged"]) )
    $_SESSION["logged"]=0;

$aff="";
include("config.inc.php");

if (isset($_POST["password"]))
    $password = $_POST["password"];

if (!ini_get('register_globals')) {
    $superglobals = array($_SERVER, $_ENV,$_FILES, $_COOKIE, $_POST, $_GET);
    if (isset($_SESSION)) {
        array_unshift($superglobals, $_SESSION);
    }
    foreach ($superglobals as $superglobal) {
        extract($superglobal, 0 );
    }
}

if (( isset ($password) && $password!="" && auth($password,$hidden_password)==1) || (is_array($_SESSION) && $_SESSION["logged"]==1 ) ){
    $aff=display("well done, you can validate with the password : $hidden_password");
} else {
    $aff=display("try again");
}

echo $aff;

?>

[첫 번째 풀이]

맨 아래 부분에 $aff값을 echo하기 전에 hidden_password를 불러온다.

따라서 저 부분을 포함하는 if문의 조건(이 방법에서는 OR연산의 두 번째 조건)이 True가 되게 만들어야 한다.

간단하게 $_SESSION["logged"]의 값이 1이면 될 것 같다.

url에는
ch17/?_SESSION[logged]=1 로 넣어주면 flag를 얻을 수 있다.

*URL을 작성하고 아래 버튼(connect)을 누르면 안된다. URL창에서 엔터 키를 눌러서 값을 전달해줘야 한다.


[두 번째 풀이]

마지막 if문의 첫 번째 조건에 주목한다.

1. isset(&password)이므로 무언가 값이 들어가서 True를 만들어 줘야 한다.
2. $password != "" - 마찬가지로 password에는 값이 들어가야 한다.
3. auth($password,$hidden_password)==1 - 위의 auth 함수에서 두 인자를 비교해서 같은지를 확인한다.

그래서 나는 url에 password=1&hidden_password=1을 넘겨주었다.
?password=1&hidden_password=1 로 넘겨주면,
You can validate with the password : 1
이라는 문구가 출력된다. 당연히 1은 답이 아닌데,
여기서 중요한 것은 서버에서 내가 hidden_password를 알고 있다고 인식했다는 것이다.
따라서 이 상태에서 url을 원래 상태(ch17까지만 있는 상태, url에 파라미터 없음)로 되돌려서 새로고침해주면 원래의 hidden_password가 호출된다.

댓글