sonotri
  • Web Hacking_command-injection-1🚩
    2024년 09월 28일 21시 29분 01초에 업로드 된 글입니다.
    작성자: sonootri

    1. 문제 설명

    redacted == 수정됨


    2. 문제 풀이

    시작 페이지, ping 페이지가 있는 간단한 웹 사이트다.

    전 강의와 마찬가지로, Host IP를 입력하면 정상적으로 동작한다.

     

     

    그럼 이제 코드를 살펴보자.

    #!/usr/bin/env python3
    import subprocess
    from flask import Flask, request, render_template, redirect
    from flag import FLAG
    APP = Flask(__name__)
    APP.route('/')
    def index():
        return render_template('index.html')

    render_template를 통해 index.html 페이지를 렌더링한다. 뭐 별건 없다.

    @APP.route('/ping', methods=['GET', 'POST'])
    def ping():
        if request.method == 'POST':
            host = request.form.get('host')
            cmd = f'ping -c 3 "{host}"'
            try:
                output = subprocess.check_output(['/bin/sh', '-c', cmd], timeout=5)
                return render_template('ping_result.html', data=output.decode('utf-8'))
            except subprocess.TimeoutExpired:
                return render_template('ping_result.html', data='Timeout !')
            except subprocess.CalledProcessError:
                return render_template('ping_result.html', data=f'an error occurred while executing the command. -> {cmd}')
    
        return render_template('ping.html')

    -> cmd = f'ping -c 3 "{host}"': 사용자가 입력한 Host 값을 기반으로 Ping 명령어를 생성한다. ping -c 3은, 해당 Host에 대해 Ping을 3번 보내겠다는 의미이다.

    -> output = subprocess.check_output(['/bin/sh', '-c', cmd], timeout=5): 해당 함수는 시스템 명령어를 실해하고, 그 결과를 캡쳐해서 반환한다.

    -> return render_template('ping_result.html', data=output.decode('utf-8')): 해당 함수를 통해 캡쳐한 Ping 명령어 결관 output은 byte 데이터로 반환되기 때문에, 이를 디코딩해 문자열로 반환한다.

    -> 아래의 except는 Timeout = 5, 즉 Ping 명령어 실행이 5초를 초과하면 예외처리 하는 부분이다. CalledProcessError은 Ping 명령어가 실패하거 나 잘못된 명령어를 실행하면 발생한다.

     

     

    이 부분을 살펴보자.

    사용자의 입력을 받는 부분이 이전 강의와 다르게 ""로 감싸져있다.

    cmd = f'ping -c 3 "{host}"'
    //이전 강의에서의 cmd 형식
    cmd = f'ping -c 3 {query}'


    3. 라이트업 참고

    cmd 변수는 사용자로부터 입력받은 Host 값을 포함하고 있다. 하지만 사용자의 입력을 그대로 명령어로 실행하기 때문에, 사용자가 악의적인 공격 코드를 주입할 수 있다.

     

    예를 들어 host의 의도대로 "8.8.8.8"이 들어간다면 ping이 올바르게 실행되겠지만, " 문자를 하나 더 붙여 문자열에서 빠져나오게 된다면...? 그리고 뒤의 "는 #를 통해 주석처리 한다면...? Command Injection 공격을 수행할 수 있게 된다.

     

    아까 위에서 형식이 일치하지 않아, 사용자가 입력한 값이 제출되지 않는 문제가 있었다. 이 문제는 개발자도구를 통해 코드를 살펴봤을 떄 왜 그랬는지 알 수 있다. pattern 속성 설정이 되어있다.

    pattern 속성은, 폼 제출시 <input> 요소의 값을 검사할 때 사용될 정규 표현식을 명시하며, 여기서 표현된 정규 표현식은 A-Za-z 즉 영어 알파벳 전체 + 0-9 숫자 + "." + 글자수는 5에서 20글자까지 이다.

    <input type="text" class="form-control" id="Host" placeholder="8.8.8.8" name="host" pattern="[A-Za-z0-9.]{5,20}" required="">

     

     

    이 필터링은, Server단에서 일어나는 검증이 아닌, 클라이언트 단에서 일어나는 검증이기 때문에 우회가 가능하다.

    개발자 도구를 사용해 pattern 속성을 제거하면 된다.

     

    이제 아래 명령어를 사용해보자 (flag.py가 있는지 확인하기 위해 그냥)

    8.8.8.8"; ls #

     

     

    위의 명령어가 잘 작동 되는것을 확인했으니, 이제 flag를 얻자

    8.8.8.8"; cat flag.py #

    zizizi

    'Dreamhack > 워게임' 카테고리의 다른 글

    webhacking.kr: old-27  (0) 2024.10.01
    Dreamhack: simple_sqli_chatgpt  (1) 2024.10.01
    Lord of Injection: germiln  (0) 2024.10.01
    Web Hacking_simple_spqi🚩  (0) 2024.09.27
    root_me: CSRF-0  (0) 2024.09.25
    댓글