登陆验证后端逻辑
一般而言,登录验证逻辑语句为:
select * from 表名 where name(用户名)='$输入' and pass(密码)='$输入'
当数据表中同时存在输入的name和pass字段时,页面将回显登录成功。
未知用户名注入攻击原理
若后端逻辑为:select * from users where name='xx' and password='xx'
手工注入
在用户名中输入qiu' or '1=1 ,密码中同样输入qiu' or '1=1
xx被输入的内容替换,查询语句变为:
select * from users where name='qiu' or '1=1' and password='qiu' or '1=1'
等同于
SELECT * FROM users WHERE (name='qiu' or '1'='1') AND (password='qiu' OR '1'='1')
1
括号内的 OR 表达式由于包含了一个恒成立的表达式 ‘1’=‘1’,所以不论用户名与密码是否正确,它始终返回真。
查询条件变为真and真,因此,sql语句注入成功。
基于#注释符的sql注入
在 SQL 语句中,# 号被用作单行注释符号。如果在一条 SQL 语句中以 # 开头,则后面的所有文字都将被解释器忽略掉,不会被执行。
当password不能为空时,用户名输入qiu' or 1=1 #,密码满足不为空即可
注入语句等同于:
select * from users where name='qiu' or 1=1 # and password='xxx'
1
即select * from users where name='qiu' or 1=1
故sql语句注入成功
当password为可为空时,用户名输入qiu' or 1=1 #
注入语句等同于:
select * from user where name='qiu' or 1=1 #' and pass=''
1
即:
select * from user where name='qiu' or 1=1
故sql语句注入成功
基于错误消息的sql注入
当应用程序遇到异常或错误时,会返回相关的错误消息给客户端,这些消息可能包含有关SQL查询语句、数据库表结构和内容等敏感信息。
攻击者可以通过构造sql攻击语句,让应用程序触发错误或异常,并从中获取有利消息。举例如下:
SELECT * FROM users WHERE id=1 AND 1=(SELECT COUNT(*) FROM users GROUP BY CONCAT_WS(':', username, password));
1
该语句使用GROUP BY子句将用户名和密码进行连接,并通过CONCAT_WS函数指定分隔符。由于一个用户只能有一个密码,所以每个组别只有一条记录。COUNT() 函数用于返回匹配指定条件的行数,所以当我们使用COUNT函数统计结果时就可以将结果与数字1进行比较。
如果我们输入任意的用户名及密码,在数据库中查询不到该字段。导致数字1与查询结果不匹配,即1=0,该查询语句会触发一个错误消息,而错误消息可能包含有关SQL语句、数据库和表结构等敏感信息。
报错注入
报错注入是一种常见的 SQL 注入攻击方式,通过向输入参数中插入恶意 SQL 代码,从而导致数据库执行异常 SQL 语句并返回错误信息。攻击者可以通过分析错误信息来获取敏感信息或执行恶意操作。
简要分析利用字符集转换错误
攻击者在输入参数中插入特定的字符集转换函数,例如 CONVERT() 或 CAST(),从而导致数据库执行异常 SQL 语句。当数据库返回错误信息时,这些信息通常会包含一些关键信息,比如数据库名称、表名、字段名等。攻击者可以利用这些信息,进一步构造有效的注入攻击。
假设应用程序中有一个搜索功能,可以根据用户名查询用户信息。当用户输入用户名并提交查询请求时,应用程序会构造以下 SQL 查询语句:
SELECT * FROM users WHERE name='输入的用户名';
1
如果攻击者在输入框中输入以下查询条件:
' CONVERT(int, (SELECT TOP 1 password_hash FROM users)) --
1
则应用程序构造的 SQL 查询语句将变为:
SELECT * FROM users WHERE name='' CONVERT(int, (SELECT TOP 1 password_hash FROM users)) -- ';
1
这条 SQL 语句会触发数据库的异常错误,因为将一个字符串类型的参数转换为整数类型是不合法的。数据库返回的错误消息可能会包含一些关键信息,比如密码哈希值等。
报错注入与基于错误消息的sql注入区别
基于错误信息的 SQL 注入和报错注入其实是同一种攻击方式。它们都是利用了数据库执行异常 SQL 语句时返回错误信息的特性,从而获取敏感信息或执行恶意操作。
区别在于:
基于错误消息的 SQL 注入更侧重于利用错误消息中包含的关键信息,进一步构造有效的注入攻击。而报错注入则更侧重于向数据库中插入一些恶意代码或数据,从而触发数据库的异常错误。
已知用户名注入攻击原理
若已知用户名为qiu
基于- -注释符的sql注入
SQL 使用双短横线注释符号来注释掉整行的内容,并从双短横线开始一直到行末都不会被解释为有效的 SQL 语句。因此,攻击者可以在用户名或密码中添加 --,来注释掉后面的字符串,从而绕过过滤器的检测。例如用户名输入qiu'--,密码输入xx
注入语句等同于:
SELECT * FROM users WHERE username = 'qiu'--' AND password = 'xx'
1
即SELECT * FROM users WHERE username = 'qiu'
这条 SQL 语句将只查询 users 表中用户名为qiu的记录。
基于/* */注释符的sql注入
SQL 使用斜线星号注释符号来注释掉多行的内容,从/* 开始,到*/结束的区域都会被注释掉。攻击者可以在用户名或密码中添加 /*,来注释掉后面的字符串。例如用户名输入qiu’/* ,密码输入xx
注入语句等同于:
SELECT * FROM users WHERE username = 'qiu'/* AND password = 'xx'
1
即SELECT * FROM users WHERE username = 'qiu'
这条 SQL 语句将只查询 users 表中用户名为qiu的记录。
注意:如果/*注释符号没有被正确地闭合掉,那么在执行 SQL 语句时就会出现语法错误,导致查询失败。为了避免这种情况的发生,一些 SQL 解析器会自动将后续的所有内容视为注释,直到遇到 */ 注释符号为止。
已知用户名与未知用户名攻击区别
对于未知用户名的注入攻击,注入成功后登录的是大概率是普通用户,而一般来说,获取管理员权限是黑客的主要目的。所以在知道管理员用户名时,可使用已知用户名攻击方式获取管理员权限,从而进行访问和窃取敏感数据、破坏和修改系统设置等恶意活动。同时,如果仅仅想登录系统获取相关信息,以上两种攻击方式均可选择。
sql注入绕过
一般来说,登录后端对用户名及密码有验证限制,例如:用户名、密码不能出现特殊字符等。此时常规的 SQL 注入攻击方式可能会被限制或无法成功实施。但这并不意味着 SQL 注入完全无法发生,攻击者仍然有可能利用其它漏洞点进行注入。
利用数字型注入
在数字型注入攻击中,攻击者通常会使用数字类型的变量或参数来注入恶意代码。攻击者将注入的恶意代码嵌入到数字型变量或参数中,并检查应用程序的响应结果以确定是否成功执行该注入。攻击者还可以利用数字运算符、格式字符串和其他SQL语法结构来进行数字型注入攻击。
基于布尔型运算的盲注攻击
盲注攻击是指攻击者无法直接获取查询结果,而只能通过不断猜测和推测来获得信息的一种注入攻击方式。
对于位置参数的SQL语句,攻击者可以通过修改参数值,并在其中嵌入布尔型运算符,从而利用盲注技术进行攻击。通常情况下,布尔型运算符的返回值只有真或假两种情况。
若后端语句如下:
SELECT * FROM users WHERE id = ?
其中id为位置参数,攻击者可以通过修改该参数值来构造恶意的查询语句,例如:
SELECT * FROM users WHERE id = 1 AND (SELECT COUNT(*) FROM users) > 0
1
在这个查询语句中,我们使用布尔型运算符 > 来判断user表中是否存在记录。如果该表中存在数据,那么COUNT函数返回的结果就大于0,故sql语句注入成功。通过不断尝试和推测,攻击者就可以逐步了解目标数据库的内容和结构等敏感信息。
基于联合查询的注入攻击
举例如下:
SELECT * FROM users WHERE id=1; DROP TABLE users;
这个可变参数值可以使SQL语句执行两个操作:首先查询 id 为 1 的用户信息,然后删除 users 表。因此,攻击者可以利用该漏洞非法地访问和操作数据库。
需要注意的是,由于大多数数字类型的数据都不允许附加特定的字符或语法结构。因此,攻击者需要结合使用其它方法,如二进制编码、脚本编码等,来成功地进行数字型注入攻击。
基于数字型操作符的注入攻击
攻击者还可以利用其他数字型操作符来构造注入,例如 AND、UNION、IN 等等。以 IN 操作符为例:
在 SQL 中,IN 操作符用于指定一个值集合,从而在查询时选择与该集合中任意一个值匹配的行。
例如,以下查询语句将检索 id 字段的值等于 1、2 或 3 的用户信息:
SELECT * FROM users WHERE id IN (1, 2, 3);
在数字型注入攻击中,攻击者可以利用这个操作符来向查询语句中注入恶意代码。例如:
SELECT * FROM users WHERE id IN (1, 2, 3) AND 1=1
由于布尔表达式 AND 1=1 恒成立,查询语句中前面的选择条件被忽略,而只保留了恒成立的后面的条件,从而使查询没有了限制条件。这就导致所有的用户记录都被返回。
利用模糊匹配注入
如果应用程序使用模糊匹配或通配符查询,攻击者可以在查询字符串中注入模糊匹配或通配符来扩展查询范围,检索到应用程序不打算公开的数据。
假设某个应用程序提供了一个搜索功能,可以根据关键字查询用户信息。该应用程序使用以下 SQL 查询语句来实现搜索功能:
SELECT * FROM users WHERE username LIKE '输入';
该功能使用了 LIKE 操作符。该操作符允许使用 % 和 _ 这两个通配符来代替查询字符串中的字符。
比如,abc%表示以 abc 开头的字符串,%abc表示以 abc 结尾的字符串。
例如,攻击者可输入如下语句:
xx OR 1=1--
语句变为:
SELECT * FROM users WHERE username LIKE ' xx OR 1=1-- ';
其中--可注释掉后面的语句,由于1=1恒成立,OR前的xx被省略,数据库会返回所有用户信息。
sql注入攻击思路
判断是否存在 Sql 注入漏洞
单引号判断法是一种简单的判断 SQL 注入漏洞的方法。该方法的基本原理是,在输入框中输入一个带有单引号的字符串,如果应用程序对输入参数没有进行正确的过滤和转义,则会发生语法错误,进而证明存在 SQL 注入漏洞。
具体步骤如下:
1.在输入框中输入一个带有单引号的字符串,例如 qiu'
2.观察是否发生了语法错误或异常提示
3.如果出现了语法错误或异常提示,那么说明该应用程序可能存在 SQL 注入漏洞
需要注意的是,单引号判断法只是一种初步的检测方法,不能保证能够检测所有的 SQL 注入漏洞。有些应用程序可能会对输入参数进行合理的过滤和转义,从而避免了单引号判断法的检测。
判断sql注入的类型
数字型注入的判断
假定后端逻辑为select * from <表名> where id = x
当输入x and 1=1时,sql语句变为:
select * from <表名> where id = x and 1=1
语法正确且逻辑判断为真,所以返回正常。
当输入x and 1=2时,sql语句变为:
select * from <表名> where id = x and 1=2
语法正确但是逻辑判断为假,所以返回错误。
若存在以上回显,即可判断该漏洞类型为数字型注入漏洞
字符型注入与数字型注入的区分
假定后端逻辑为select * from <表名> where id ='x'
当输入x and 1=1时,sql语句变为:
select * from <表名> where id ='x and 1=1'
当输入x' and '1'='2时,sql语句变为:
select * from <表名> where id = 'x and 1=2'
查询语句将 and 语句全部转换为了字符串,并没有进行 and 的逻辑判断,所以不会出现数字型注入中返回正常或返回错误的结果。
通过以上,即可判断:如果存在回显,则该漏洞类型不是字符型注入漏洞
字符型注入的判断:
假定后端逻辑为:select * from <表名> where id = 'x'
当输入x' and '1'='1时,sql 语句变为:
select * from <表名> where id = 'x' and '1'='1'
语法正确,逻辑判断正确,所以返回正确
当输入x' and '1'='2时,sql语句变为:
select * from <表名> where id = 'x' and '1'='2'
语法正确,但逻辑判断错误,所以返回错误
若存在以上回显,即可判断该漏洞类型为字符型注入漏洞
布尔型注入
基于布尔盲注的SQL注入攻击是一种利用目标Web应用程序对SQL查询条件正确/错误响应的不同表现来推测查询语句的正确性,从而获取数据库中敏感信息的攻击方式。
1)例如,攻击者可以构造如下SQL语句,用于判断某个字段是否存在:
SELECT CASE WHEN (username = 'admin') THEN 1 ELSE 0 END FROM users
1
这个查询语句选取了users表中的一个字段username,并通过CASE WHEN语句来判断该字段的值是否等于’admin’。如果字段的值等于’admin’,则返回1,说明该字段存在;否则,返回0,说明该字段不存在。
CASE WHEN语句是一个条件表达式,其基本形式如下:
CASE WHEN condition THEN expr1 [ELSE expr2] END
其中,condition是一个逻辑表达式,如果为真,则返回expr1;否则,返回expr2。
该类注入,是需要攻击者知道表名、列名及字段的。这里介绍一种使用ASCII码二分法逐一猜解表名、列名、字段的方法。
先确定要猜解的表名admin,再构造 SQL 查询语句,比如:
SELECT COUNT(*) FROM admin WHERE ascii(mid(table_name,N,1)) > X;
1
其中,N 表示正在猜解的字符在表名中从左到右的位置,X 表示当前猜测的 ASCII 码值。COUNT(*) 函数用于满足条件 ascii(mid(table_name,N,1)) > X 的行数。
若查询结果大于 0,则说明 实际ASCII码值大于当前猜测值,应将x取大;
反之,如果查询结果为 0,则说明实际ASCII 码值小于或等于当前猜测值,应将x取小。重复该步骤,直到找到当前字符的正确 ASCII 码值。
例如,表名第一个字符为a,a的ascii码是97。攻击者在不知道表名的情况下给x赋值,x取64,a>64,回显大于0;x取大,取96,回显大于0,再猜>100,回显小于0;x取小,取98,再猜>98,回显小于0,这样就知道ascii码是97了,即为a。
2)再者,攻击者可以通过修改查询语句中的条件表达式,来判断不同的字段是否存在或符合条件。如下语句可判断某个字段是否为数字类型:
SELECT CASE WHEN ISNUMERIC(column_name) = 1 THEN 1 ELSE 0 END FROM table_name
在这个语句中,ISNUMERIC函数用于判断column_name字段的值是否为数字。如果是数字类型,则返回1;否则,返回0。
时间盲注
基于时间盲注的SQL注入是一种利用Web应用程序对SQL语句的响应时间来推测查询语句正确性的攻击方式。攻击者不停地尝试不同的SQL语句,观察程序的响应时间,从而判断SQL语句是否正确,进而获取数据库中的敏感信息。
例如,攻击者可以构造如下查询语句:
SELECT * FROM users WHERE username = 'admin' AND password = 'password' AND sleep(5) #'
#起作用后,语句变为:
SELECT * FROM users WHERE username = 'admin' AND password = 'password' AND sleep(5)
1
其中,sleep函数用于让数据库暂停执行5秒钟的时间,以便观察Web应用程序的响应时间。如果程序响应时间增长,则说明该漏洞存在时间盲注。
联合注入
基于联合查询的SQL注入是一种数据库查询语句中包含联合查询的攻击方式。攻击者将原始查询结果与构造的SQL查询语句的结果联合到一起,从而获取敏感信息或执行恶意操作。
举例如下:
SELECT * FROM users WHERE username='admin' UNION SELECT NULL,NULL,NULL FROM information_schema.tables --
1
首先,查询 users 表中 username 值为 ‘admin’ 的记录,这是一个正常的 SQL 查询语句。
然后,使用UNION将查询结果与另一个 SELECT 语句的结果合并。第二个SELECT语句中插入了三个NULL 值,来匹配前面查询的 users 表中的字段数目。
最后,利用 – 来注释掉原本的 SQL 查询语句,从而执行恶意代码。攻击者可查询到 information_schema.tables 中的所有表名信息。
实例如下:
SELECT * FROM users WHERE username='admin' UNION SELECT credit_card_number, expiration_date FROM credit_cards
攻击者将从 credit_cards 表中获取到信用卡号和过期日期等敏感信息
若回显成功,则说明该漏洞存在联合注入。
总结
以上为SQL注入常见原理及攻击方法简析。由于SQL语言的复杂性、灵活性及作者水平有限,本文仅供参考;具体姿势及其它注入原理、方法读者可自行探索。
后续会分享DVWA应用程序及SQLLABS测试平台相关注入知识、攻击姿势。
我是秋说,我们下次见。