
GitLab CE webhook SSRF के लिए प्रूफ-ऑफ-कॉन्सेप्ट और लैब, जो 0.0.0.0/8 this-network रेंज के माध्यम से एक Maintainer को loopback तक पहुँचने और hook logs से प्रतिक्रियाएँ पढ़ने की सुविधा देता है।
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · gitlab-webhook-0net-ssrf
राइट-अप: https://abraxaslabs.tech/research/gitlab-webhook-0net-ssrf
GitLab CE 19.4.1 - GitLab Inc.
Gitlab::HTTP_V2::UrlBlocker सटीक 0.0.0.0, ::, और 127.0.0.0/8 को ब्लॉक करता है। यह शेष 0.0.0.0/8 को ब्लॉक नहीं करता। Linux उस रेंज को "this network" मानता है और 0.0.0.1 को लोकल स्टैक तक पहुँचा देगा। एक प्रोजेक्ट Maintainer allow_local_requests_from_web_hooks_and_services बंद होने पर भी http://0.0.0.1:<port>/ पर वेबहुक बना सकता है। GitLab हुक लॉग में रिस्पॉन्स के 8 KB संग्रहीत करता है।
अपने ही प्रोजेक्ट का Maintainer GitLab से 0.0.0.1 के माध्यम से लूपबैक पर POST करवा सकता है और हुक लॉग से बॉडी वापस पढ़ सकता है।
| ID | अभी तक कोई CVE नहीं |
| CWE | CWE-918 |
| CVSS | High: 8.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N |
| Product | GitLab CE |
| Affected | 19.4.1-ce.0 (v19.4.1-ee ट्री पर 26212baacadb) |
| Auth | प्रमाणित Maintainer (admin_web_hook) |
| License | GNU Affero GPL v3.0 |
| Lab | केवल 127.0.0.1 |
POST /api/v4/projects/:id/hooks के साथ url=http://0.0.0.1:<port>/। ट्रिगर करें या परीक्षण करें। हुक इवेंट्स API से response_body पढ़ें। all-in-one omnibus पर, Sidekiq Puma, Workhorse, और exporters के साथ कंटेनर netns साझा करता है। अपने प्रोजेक्ट का Maintainer को उन्हें नहीं पढ़ना चाहिए।
http://127.0.0.1/ और http://169.254.169.254/ ब्लॉक रहते हैं। यह लिंक-लोकल के माध्यम से IMDS नहीं है। यह this-network वाला छेद है।
वही उत्पाद, सहोदर अवशेष: Gitea HTTPS import pin drop, Gitaly fetch omits resolved_address।
19.4.1 SSRF फिक्स के बाद मैंने url_blocker.rb पढ़ा। validate_localhost सटीक "::" और "0.0.0.0" तथा Socket.ip_address_list है। validate_loopback ipv4_loopback? (127.0.0.0/8) और ipv6 loopback है। Specs 127.0.0.1 के octal/hex aliases को कवर करते हैं। वे कभी 0.0.0.1 का उल्लेख नहीं करते।
Webhook बॉडी सिंक है: WebHookService POST करता है और 8 KB संग्रहीत करता है। Maintainer के पास admin_web_hook है।
मैंने स्टॉक gitlab/gitlab-ce:19.4.1-ce.0 खड़ा किया। Local-requests बंद। GitLab netns के अंदर 0.0.0.1:18080 पर Catcher। हुक बनाएँ http://127.0.0.1:18080/ और http://169.254.169.254/ : 422 Invalid url given। हुक बनाएँ http://0.0.0.1:18080/ : 201। टेस्ट पुश इवेंट्स : 201। हुक इवेंट्स response_body में GITLAB-WEBHOOK-0NET-SSRF-WITNESS शामिल है।
पहले से दर्ज गलत रास्ते: Accept: application/json के साथ /users/sign_in 404 है; root युक्त सीड पासवर्ड WeakPasswords है; lo में 0.0.0.1 जोड़ने से यह Socket.ip_address_list पर आ जाता है इसलिए validate_localhost "positive" को 422 कर देता है; IP_FREEBIND और ip route add local 0.0.0.1/32 dev lo एड्रेस लिस्ट में शामिल हुए बिना बाइंड करता है; पासवर्ड में compose $ के लिए $$ चाहिए। एक रिवर्स शेल। नाटक। Oracle 0.0.0.1 पर 201 है, 127.0.0.1 पर 422, लॉग में witness।
cd lab
./run.sh
केवल http://127.0.0.1:18420 को लक्षित करें। GitLab CE को कई GB RAM चाहिए। केवल अधिकृत लैब।
negative-a 127.0.0.1 blocked
negative-b link-local blocked
positive-hook id=1
SUCCESS GITLAB-WEBHOOK-0NET-SSRF webhook response_body from 0.0.0.1:18080 hook_id=1 GITLAB-WEBHOOK-0NET-SSRF-WITNESS
def validate_localhost(addrs_info)
local_ips = ["::", "0.0.0.0"]
local_ips.concat(Socket.ip_address_list.map(&:ip_address))
return if (local_ips & addrs_info.map(&:ip_address)).empty?
raise BlockedUrlError, "Requests to localhost are not allowed"
end
def validate_loopback(addrs_info)
return unless addrs_info.any? { |addr| addr.ipv4_loopback? || addr.ipv6_loopback? }
raise BlockedUrlError, "Requests to loopback addresses are not allowed"
end
0.0.0.0/8 (और ::ffff:0.0.0.0/104) को उसी तरह अस्वीकार करें जैसे 127.0.0.0/8 को अस्वीकार किया जाता है।
url_blocker.rb · web_hook_service.rb · project_hooks.rbGNU Affero GPL v3.0. देखें LICENSE। केवल लूपबैक लैब। कोई वारंटी नहीं।