# encoding: utf-8
Regex In Ruby – Capture Groups
Lecky Lao(@leckylao)
RORO 09-06-2015
Mongo BSON Injection: Ruby Regexps Strike Again
Jun 4, 2015 • Egor Homakov (@homakov)
Mongoid is an ODM(Object Document Mapper) Framework
for MongoDB written in Ruby
Mongoid uses more low-level adapter Moped which uses BSON-ruby
the vulnerability is in legal? method of BSON::ObjectId
# /\nhi\n/ =~ /hi$/
# /\nhi\n/ =~ /hi\Z/
# /\nhi\n/ =~ /hi\z/
# Vulnerable
def legal?(string)
# March 31 2013 to Apr 7 2013
/\A\h{24}\Z/ === string.to_s
# currently it thinks Mongo is down and pings it 39 more times with intervals.
# In other words it keeps the worker busy for 5 seconds and makes x40 requests to Mongo DB
# One way or another, it is Denial of Service.
# Apr 7 2013 till now
string.to_s =~ /^[0-9a-f]{24}$/i ? true : false
# he attacker can send any data to the socket with something like
# _id=Any binary data\naaaaaaaaaaaaaaaaaaaaaaaa\nAny binary data
end
# Patch
def ((defined?(Moped::BSON) ? Moped::BSON : BSON)::ObjectId).legal?(s)
/\A\h{24}\z/ === s.to_s
end
—-Capturing Groups—-
# What's the difference?
/sat (in)/.match("The cat sat in the hat")
"The cat sat in the hat" =~ /sat (in)/
The difference is
The operator =~ returns the index
of the first match (nil if no match)
and stores the MatchData
in the global variable $~
The method match returns
the MatchData itself (again, nil if no match)
Grouping with reference
# What's the difference?
/\$(?\d+)\.(?\d+)/.match("$3.67")
"$3.67" =~ /\$(?\d+)\.(?\d+)/
/\$(?\d+)\.(?\d+)/ =~ "$3.67"
The difference is
When named capture groups are used with a literal regexp
on the left-hand side of an expression and the =~ operator,
the captured text is also assigned to local variables
with corresponding names.
—-Backreferences—-
# Is this correct?
"The cat sat in the hat".gsub(/(.*)cat(.*)/, "#{$1}black dog#{$2}")
"The cat sat in the hat".gsub(/(.*)cat(.*)/, "\1black dog\2")
"The cat sat in the hat".gsub(/(.*)cat(.*)/, '\1black dog\2')
"The cat sat in the hat".gsub(/(?<prefix>.*)cat(.*)/, '\k<prefix>black dog\2')
"The cat sat in the hat".gsub(/(?<prefix>.*)cat(?<suffix>.*)/, '\k<prefix>black dog\k<suffix>')
$1 and $2 only store after the execution, therefore
DO NOT USE $1 AND $2 IN GSUB,
and use \\1 and \\2 instead
use '' instead of "" when using regex
A regexp can't use named backreferences
and numbered backreferences simultaneously.
That's all, thanks!
slide: https://github.com/leckylao/tkn – examples/regex_in_ruby.rb
slides made using tkn(https://github.com/fxn/tkn)"