
Forgejo 16.0.5 - 높음 - 원격 - IDOR - GET /api/v1/user/keys/{id}가 다른 사용자의 SSH 및 배포 키를 반환함
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · forgejo-keys-idor
분석 문서: https://abraxaslabs.tech/research/forgejo-keys-idor
분류: IDOR 도달 범위: 원격
Forgejo 16.0.5 (8d24b7d) - Forgejo
GET /api/v1/user/keys/{id}는 현재 사용자 그룹(reqToken, 사용자 스코프)에 속해 있습니다. 그런데도 핸들러는 소유자 확인 없이 숫자 ID로 public_key를 로드합니다. 같은 테이블에는 사용자 키, 배포 키, 그리고 principal이 들어 있습니다. 이 버전의 GPG는 올바르게 처리합니다: GetGPGKeyForUserByID(ctx, ctx.Doer().ID, id). 비공개 추가 필드는 제한됩니다. 하지만 공개 키 자료, 제목, 지문은 제한되지 않습니다. ID는 순차적입니다.
read:user 토큰으로 1, 2, 3을 순회하며 다른 사람의 SSH 키와 배포 키를 열람할 수 있습니다.
| ID | 아직 CVE 없음 |
| 분류 | IDOR |
| 도달 범위 | 원격 (인증된 read:user / 세션) |
| CWE | CWE-639 |
| CVSS | 높음: 7.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N |
| 제품 | Forgejo |
| 영향 범위 | v16.0.5 (8d24b7d)까지 |
| 인증 | 인증됨 (read:user 토큰 또는 세션) |
| 라이선스 | GNU Affero GPL v3.0 |
| 실습 환경 | 127.0.0.1 전용 |
아무 계정이나 등록하거나 사용하고, read:user 토큰을 발급받아(또는 세션 쿠키를 사용해) /api/v1/user/keys/{id}를 순회합니다. 그러면 자신이 소유하지 않은 키의 제목, 지문, 공개 키 자료를 얻습니다. 개인 키는 얻지 못합니다. 셸도 얻지 못합니다. 다만 누가 무엇에 접근할 수 있는지 목록을 파악합니다.
| 권한 | 메서드 / 싱크 | 정찰 / 무결성 / 가용성 | 실습 환경 입증 또는 추론 |
|---|---|---|---|
| 다른 사용자의 SSH 공개 키 제목, 지문, 키 자료 읽기 | 다른 소유자로서 GET /api/v1/user/keys/{id} | 정찰 (공개 키 목록의 기밀성) | 실습 환경 입증. id 1의 증인 제목 FORGEJO-KEYS-IDOR-WITNESS; 공격자 목록에는 id 2만 표시됨 |
| 같은 방식으로 배포 키 열람 | 동일 핸들러, public_key의 KeyTypeDeploy 행 (OwnerID 0) | 정찰 | 테이블에서 추론. 실습 환경에는 사용자 SSH 키를 심었고 배포 키는 심지 않음 |
| SSH 인증서 principal 읽기 | 동일 핸들러, KeyTypePrincipal 행. ListPublicKeys는 이 유형을 제외함 | 정찰 | 테이블에서 추론 |
| 제한 사용자 또는 비공개 사용자에 속한 키 보기 | 이 조회에 가시성 확인 없음 | 정찰 | 핸들러에서 추론 |
추가 JSON (user, key_type, read_only) | appendPrivateInformation은 관리자 또는 소유자인 경우에만 실행 | 정찰 | 실습 환경 입증(차단됨): 비소유자 응답에 user 필드가 없음 |
이 경로에서 차단된 것: 개인 키 자료, 셸, GET /users/{username}/keys (사용자명 기준 공개 목록), GPG GET /api/v1/user/gpg_keys/{id} (다른 사용자의 id에 404), DeletePublicKey (소유자/관리자 403). 교차 저장소 GET /repos/{owner}/{repo}/keys/{id}는 RepoID가 일치하지 않으면 404를 반환합니다.
v16.0.5 보안 패치(#14370)는 git-apply RCE와 OpenID CSRF였습니다. 이 조회는 닫지 못했습니다. gitea-user-keys-idor와 같은 부류로, 여기서는 독립적으로 여전히 열려 있습니다.
2026-09 물결 이후 Forgejo v16.0.5를 고정했습니다. Gitea 1.27.3에도 이 조회가 여전히 있었습니다. Forgejo는 분기되었으므로, Gitea 패키지를 복사하는 대신 GPG 옆의 현재 사용자 키 핸들러를 다시 읽었습니다. GPG는 다른 사용자의 id에 404를 반환합니다. SSH는 그렇지 않습니다.
잘못 기록된 오답들: 공격자 자신의 목록을 유출로 취급한 것(그것은 유출이 아니다 - 목록은 범위가 제한되어 있지만, GET-by-id는 그렇지 않다); 설치 프로그램의 DISABLE_REGISTRATION=true를 종결로 취급한 것(기존 계정이 하나라도 있으면 충분하다); 리버스 셸. 극에 불과하다.
python3 forgejo-keys-idor-Abraxas-Labs.py
또는:
cd lab
./run.sh
오직 http://127.0.0.1:19310만 대상으로 합니다. 이미지 codeberg.org/forgejo/forgejo:16.0.5. 두 개의 계정. Witness FORGEJO-KEYS-IDOR-WITNESS.
IOC planted victim-id=1 attacker-id=2
IOC attacker-list status=200 ... title=attacker-own-key
IOC get id=1 status=200 ... FORGEJO-KEYS-IDOR-WITNESS
IOC gpg-neg id=1 status=404
SUCCESS forgejo-keys-idor victim-id=1 get-http=200 list-has-id=no gpg-http=404 FORGEJO-KEYS-IDOR-WITNESS
key.OwnerID == ctx.Doer().ID(또는 사이트 관리자)가 아니면 404를 반환합니다. 이 라우트에서 KeyTypeDeploy / KeyTypePrincipal을 거부합니다. GetGPGKeyForUserByID와 일치시킵니다.
GetPublicKeyGNU Affero GPL v3.0. LICENSE를 참조하세요. 루프백 랩 전용입니다. 보증하지 않습니다.