
Forgejo 16.0.5 - 높음 - 원격 - IDOR - GET /api/v1/user/keys/{id}가 다른 사용자의 SSH 및 배포 키를 반환함
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · forgejo-keys-idor
분류: IDOR 도달 범위: 원격
Forgejo 16.0.5 (8d24b7d) - Forgejo
GET /api/v1/user/keys/{id}는 현재 사용자 그룹(reqToken, user 스코프)에 속해 있다. 그런데도 핸들러는 여전히 숫자 ID로 public_key를 로드하며 소유자 확인이 없다. 같은 테이블에는 사용자 키, deploy 키, 그리고 principal이 들어 있다. 이 버전의 GPG는 제대로 처리한다: GetGPGKeyForUserByID(ctx, ctx.Doer().ID, id). 비공개 추가 필드는 차단되어 있다. 하지만 공개 키 자료, 제목, 지문은 차단되지 않는다. ID는 순차적이다.
read:user 토큰으로 1, 2, 3을 순회하며 다른 사람의 SSH 키와 deploy 키를 수집할 수 있다.
| ID | 아직 CVE 없음 |
| 분류 | IDOR |
| 도달 범위 | 원격 (인증된 read:user / 세션) |
| CWE | CWE-639 |
| CVSS | High: 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에서 witness 제목 FORGEJO-KEYS-IDOR-WITNESS; 공격자 목록에는 id 2만 존재 |
| deploy 키도 같은 방식으로 수집 | 동일 핸들러, public_key의 KeyTypeDeploy 행 (OwnerID 0) | 정찰 | 테이블에서 추정. 랩에는 사용자 SSH 키를 심었고 deploy 키는 아님 |
| 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는 그렇지 않다.
이미 기록된 잘못된 방향: 공격자 자신의 목록을 유출로 취급한 것 (그렇지 않다 - 목록은 범위가 제한되지만, id로 조회하는 GET은 그렇지 않다); 설치 프로그램의 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 참조. 루프백 랩 전용. 보증 없음.