一、Sql注入简介
Sql 注入攻击是通过将恶意的 Sql 查询或添加语句插入到应用的输入参数中,再在后台 Sql 服务器上解析执行进行的攻击,它目前黑客对数据库进行攻击的最常用手段之一。
二、Web 程序三层架构
三层架构(3-tier architecture) 通常意义上就是将整个业务应用划分为:
- 界面层(User Interface layer)
业务逻辑层(Business Logic Layer)
数据访问层(Data access layer)。
区分层次的目的即为了“高内聚低耦合”的思想。在软件体系架构设计中,分层式结构是最常见,也是最重要的一种结构被应用于众多类型的软件开发。
由数据库驱动的Web应用程序依从三层架构的思想也分为了三层:
表示层。
业务逻辑层(又称领域层)
数据访问层(又称存储层)
拓扑结构如下图所示:
发现
找到有效SQL注入的第一部分是发现漏洞。而其中最重要的部分是知道在你的输入会在哪一SQL语境中结束。这里有一些基本的例子:
· SELECT user_input FROM tournament ORDER BY region;
· INSERT INTO tbl_name (col1,col2) VALUES (15,user_input);
· DELETE FROM somelog WHERE texts ='user_input'
现在我们可以看到我们的user_input在不同语境中结束:在()之间,在’之间或者没有任何分隔符。这些命令的共同之处是,一旦’作为输入进行注入,它们就会失效。如果使用了不存在的系统变量,前两个即使没有分隔符也会给出一个错误。像:@@versionz'(取代@@version)。
一旦你能够让这个服务返回错误(主要是HTTP 500),你需要确认是SQL命令引起这个错误而不是一些类似数据解析器的东西。要做到这一点,你可以使用一系列技巧:
| 如果一个’导致错误,试着查看’能否成功(因为反斜杠在MySQL中取消了单引号)
l 你也可以尝试注释掉’就会返回成功消息,就像:%23’或者--’。这是因为你告诉MYSQL忽略注释之后的所有东西,包括额外的’。
l 如果’是不允许,你可以在有效和无效的系统变量之间比较,类似@@versionzvs @@version',或在无效函数和有效函数之间的比较:SLEP(5) vsSLEEP(5)。
l 有些时候你的输入会在()之间结束,以确保你可以测试input)%23,也会查看你是否可以突破这些,例如利用UnionSQL注入( input)order by 5%23)。
l 如果正常的输入只是一个整数,你可以尝试减去一些量,然后查看减法是否有效( id=460-5)。
l 试着看偶数的引号是否会返回成功(例如460''或460-'')并且奇数的引号会导致错误(460'或460-''')。
利用
在你找到SQL注入之后,你总是要尝试证明输出或者输出中的敏感数据有差异。不幸的是这并不总是直截了当的,特别是防火墙和黑名单会妨碍你。这部分是帮助你绕过那些问题。
防火墙
当你处理防火墙时,你要做的第一件事是看你是否可以在一个设置中找到错误配置。对于大多数防火墙和CDN,你可以通过访问真实IP并用真实域名作为主机值访问不受保护的网站(防火墙在IP前面)。这里第一步应该是找到网站的原始IP,使用追踪某个网站所使用的IP服务通常不会太难。通常用在防护墙ip前的那一个是他们仍在使用的那一个(基本上就是后面所说的cloudflare 或 akamai)。在寻找真实IP时Shodan 也非常有用。
在你找到真实IP地址之后,尝试访问带有真实主机HTTP头信息的网站。在cURL中这部分会这样工作的(添加头文件也适用于sqlmap):
$ curl --header 'Host: www.example.com' 'https://54.165.170.2/' -v -k
很不幸我的目标被禁止了。所以我必须具有创造力。在这我发现通过给主机域名后面添加一个点(http://www.example.com.)不会受限制而且仍然允许我浏览这个直接IP。在你的/etc/hosts文件中添加:
54.165.170.2 http:www.example.com
就会允许你在浏览器中浏览http://www.example.com,并且在这之间没有任何防火墙。从这开始,所有的限制都应该消失,而且SQL注入的利用应该相当容易
绕过黑名单
有时, 您无法绕过防火墙, 这将要求您绕过已就位的 (可能) 黑名单。这里我最大的提示是, 谷歌是你的朋友。找到具有强大功能的利基功能, 要求您以某种方式提取数据。但是这里有一些常见的提示:
1. 在查询中使用注释作为空格以破坏防火墙中的正则表达式或词组。例如:2/dhab bc/OR/dahdshka/2/sd/LIKE/da/"2"/**/%23就是:2 OR 2=2%23。
2. 如上例所示,用 LIKE 代替 =,用 2 代替 1,用 ” 代替 ’ 。很多人都很懒,防火墙也是如此,走小路会让许多防火墙措手不及。
3. 正如我上面说的用Google找niche函数。例如,我发现MID()和SUBSTRING()的工作方式一样,然而,后一个是被禁止的,第一个不是。变量也是一样的CURRENT_USER()是被禁止的,而CURRENT_USER不是。
把它们放在一起
从SQL注入发现,这很可能是我最喜欢的。因为利用真的非常难。所以我将详细地描述它,并且希望你们可以从中学到一些东西。
我偶然发现这个URL:
https://www.example.com/php/analyticsExcel.php?action=res_unique_analytics&resid=2100935&start_date=2016-07-11 00:00:00&end_date=2017-08-11 23:59:59&action=res_unique_analytics&entity_type=restaurant
这里我有2100935的合法访问权,而且请求2100935将会导致未经验证的错误。奇怪的是,在2100935后面添加一个引号,就会导致错误500,添加两个引号就会使URL再次起作用。在这里,为了让利用更容易,我用www.example.com.绕过。在那里,我试图在输入中找到一个地方在输入中注入我自己的SQL命令,然而我没有设法在字符串中插入注释,因此我断定这个查询是非常复杂的。考虑到这一点我决定把侧重点烦躁一个更简单的OR语句上,这个语句几乎可以在任何地方注入。在这我注意到' OR 1='1会返回状态码200,' OR 1='2,' AND1='1,' AND 1='2也都是一样的。而且最终似乎没有哪个sleep()命令有效果。
非常奇怪的是,我可以确定我注入的语法是正确的,但是没有任何技巧可以提取数据。在这我尝试' OR@@version=5,它会导致状态码200,以及' OR@@versionz=5,它会导致错误500。这至少证实我正在使用MySQL并表明注入确实在这里。这里指向MySQL的IF函数。我的想法是如果我可以根据if语句是真是假来返回一个无效函数,我就可以证明数据提取。由于MySQL似乎在验证IF语句之前验证了命令,但是进展并没有如想象般顺利。但是IF语句最终成为解决方案的一部分。在一个具有正整数的IF语句中输入一个有效的SLEEP命令将会导致服务器超时,而从IF语句中返回一个简单的整数时,将会迅速返回一个状态码200。从这里我利用了下面的POC:
TRUE: if @@version starts with a 5:
2100935' OR IF(MID(@@version,1,1)='5',sleep(1),1)='2
Response:
HTTP/1.1 500 Internal Server Error
False: if @@version starts with a 4:
2100935' OR IF(MID(@@version,1,1)='4',sleep(1),1)='2
Response:
HTTP/1.1 200 OK
总结
如果注入一个单引号会在响应中导致不同的输出,请尝试使用这篇博客中列出的其他的技术,以查看你是否在处理SQL注入。在确定了你正在使用的SQL上下文之后,利用一个POC,它可以显示敏感信息(基于error或union),或者根据问题是真是假(基于布尔和时间)来显示输出中的差异。