티스토리 뷰

- Hack No-Jam

(CTF 서버가 내려가서 비슷하게 구축하긴 했는데 다소 다른 부분이 있습니다.)



Accounts 페이지를 보면 현재 가입된 계정 정보를 알 수 있다.


?p=pages/home

?p=pages/accounts

위 두 그림을 보면 위와 같이 인자 값을 받아서 페이지를 보여주는 것을 알 수 있고 이를 통해서 home.php, accounts.php 파일을 호출해서 보여준다는 것을 추측할 수 있다.

.php 부분이 없기 때문에 이 부분은 소스 코드에서 .php를 붙여서 호출한다는 것도 추측이 가능하다.

즉, LFI 공격이 가능할 수도 있기 때문에 php://filter/convert.base64-encode/resource= 를 이용해서 소스 코드를 알아낼 수 있다.




위와 같은 방법으로 소스 코드를 따라서 다른 파일들도 확인하다보면, 회원가입 후 정보를 수정하는 소스 파일을 볼 수가 있다.


mod/modify.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?php
    include("./db_conn.php");
 
    $input = file_get_contents("php://input");
    $input = json_decode($inputtrue);
    if (strlen($input[2])<6) die("minleng err");
    if (strlen($input[3])<6) die("minleng err");
    sleep(1);
    $input[2= myhash($input[2]);
    $input[3= myhash($input[3]);
    if (update_userpass($input)) {
        die("success");
    } else {
        die("authenticate failed..");
    }
 
    function myhash($v){
        global $salt;
        return md5($salt.$v);
    }
 
    function get_userdata($userid){
        $userid = mysql_real_escape_string($userid);
        $result = mysql_query("select * from users where userid = '{$userid}'");
        $row = mysql_fetch_row($result);
        return $row;
    }
 
    function authenticate($input){
        $userdata = get_userdata($input[1]);
        // Bug #69892    Different arrays compare indentical due to integer key truncation
        // https://bugs.php.net/bug.php?id=69892
        // PHP 5.4.0-5.4.43 | 5.5.0-5.5.26 | 5.6.0-5.6.10
        // var_dump([0 => 0] === [0x100000000 => 0]); // bool(true)
        if ($input===$userdatareturn true;
        return false;
    }
 
    function update_userpass($input){
        $change = $input[3];
        array_pop($input);
        if (!authenticate($input)) return false;
        $input[0= mysql_real_escape_string($input[0]);
        mysql_query("update users set userps='{$change}' where uidx='{$input[0]}'");
        return true;
    }
?>
cs


먼저 admin으로 로그인하기 위해서 현재 내가 로그인한 아이디의 패스워드를 변경할 때, uid 값을 변경해서 관리자의 패스워드가 변경되도록 해야하지만, authenticate() 부분에서 uid, userid 값을 비교하기 때문에 userpw 값을 변경할 수가 없다.


이것을 우회하기 위해서 소스 코드에 주석으로 설명해놓은 것처럼 PHP에서 array 형태의 값을 비교할 때 값은 로그인한 계정의 uid, userid 값을 넣어주고 uid의 인덱스 부분에 0 대신에 0x100000000에 해당하는 4294967296를 넣어준다.



그렇게 되면 PHP에서 array를 비교할 때 인덱스의 데이터 타입은 int(32bit)이기 때문에 범위를 초과하면서 0으로 비교가 되는 버그가 발생한다. 


따라서, $input === $userdata를 통과한 다음,

mysql_query("update users set userps='{$change}' where uidx='{$input[0]}'") 다음 코드에서 uidx 값에 $input[0]을 호출하는 과정에서 에러가 발생하면서 uidx가 0인 admin의 userpw가 내가 설정한 패스워드로 변경이 된다. 


admin으로 로그인하면 flag를 획득할 수 있다.

Flag: qjflftndlTekrh~auclftkdldidnlssjfekfforhdhdh~~


참고: https://sektioneins.de/en/blog/15-08-03-php_challenge_2015_solution.html


풀이 영상: https://www.youtube.com/watch?v=ere9HukUJQU

댓글
«   2024/03   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
링크
공지사항
Total
Today
Yesterday