Learn SQL Injection by Ethically Hacking a Rails App
By: Chris I.
Tags: Programming, Cybersecurity, MySQL, Ruby on Rails, Rails

2. Build a Vulnerable Rails App

We’re going to build an app that we’ll later hack. I’ve tried to be as verbose as possible so you can copy/paste the below into your terminal and web editor to build this quickly.

Set up the app

Navigate to the directory where you want to create the app. Then, generate a new Rails app and install the default gems.

$ rails new hackerapp

$ cd hackerapp

$ sudo bundle install

Hopefully, you won’t have any version problems that pop up, but if you do, post in the comments and I’ll try to help.

Open the code in your favorite editor. I’m using Atom.

$ atom .

Set up the database

Navigate to /config/database.yml (Rails’ database configuration file), delete the existing code, and paste in the below. This specifies PostgreSQL as your database and sets the DB’s name.

Navigate to Gemfile (where we specify libraries to install) and add these two lines near the top.

gem 'pg'

gem 'devise'

Then, run this in the command line to install those gems.

$ sudo bundle install

Now create the DB we set up earlier. You’ll need PostgreSQL installed on your Mac for this to work.

Again, if you have trouble, I’ll try to help in the comments.

$ rake db:create

Start the app

Let’s see if what we’ve set up so far actually works.

$ rails s

Then, navigate to http://localhost:3000/ (or whatever port the server started on).

If you see this, you’re successful:

Add users and authentication (logging in)

We’ll use the go-to auth library for Rails called Devise, which we already added in the above step.

Install Devise.

$ rails generate devise:install

Generate model and migration files. In Rails, a model is a Ruby class that maps to a database table and simplifies making DB transactions via its ORM, Active Record.

$ rails generate devise user

Create views associated with the model.

$ rails generate devise:views users

Add another column to users in addition to what Devise has set up. Generate the empty migration file.

$ rails g migration AddAdminToUsers

It will be the second file down in /db/migrate/ . Paste this in:

Run the migrations. This will add these two columns to the users table in the database.

$ rake db:migrate

Create Post resources

Generate another migration file that creates a Post model. Generate the file and migrate. This also creates all the basic CRUD views for this model in the controller.

$ rails g scaffold Post title:string content:string

$ rake db:migrate

Add root 'posts#index' to the bottom of /config/routes.rb so the app automatically redirects users to the post index page. routes.rb should look like this.

Rails.application.routes.draw do

resources :posts

devise_for :users



root 'posts#index'

end

Navigate to http://localhost:3000/, and you’ll see the view rendered by posts#index .

Cool. Add a few posts yourself just to make sure that it works.

We’ve added authentication with Devise but we can’t even tell if we’re logged in or out. Let’s change that!

Navigate to /app/views/layouts/application.html.erb and update the file so it looks like below. This file actually renders every other view inside it so whatever we put here will be displayed on each page.

Great. Now click “Sign up” in the top-left of the app and create an account. We’ve deactivated email confirmation so after creating an account, you’ll automatically be signed in and you’ll see something like this:

Add one more column to Posts by generating another migration file.

$ rails g migration AddPrivateToPosts

Fill in the newest migration file in db/migrate/ .

class AddPrivateToPosts < ActiveRecord::Migration[5.0]

def change

add_column :posts, :private, :boolean, default: false

end

end

And migrate.

$ rake db:migrate

Generate users and posts

Create a file called seed_data.rake in /lib/tasks/ .

Run the file and these records will be added to the database.

$ rake seed_data

Below are screenshots from my database. You would have to open an SQL editor to see this but it’s not important.

The vulnerable feature

Rails comes with Active Record which is really good at parameterizing inputs but we’re going to go off best practices here to allow injecting SQL.

We’ll create a search field that filters displayed posts. It seems innocent but it’s where we’ll attack later.

Add filtering logic in the view

Add this to the view, app/views/posts/index.html.erb , just below <h1>Posts</h1> .

This creates an input field in the view.

Modify the index action in the controller