Sqli labs笔记
笔记¶
第七关¶
Text Only | |
---|---|
1 |
|
刚开始这儿一直不行,硬盘上出现不了uuu.txt,原因是自己的mysql设置问题。
在MySQL中,outfile可以用来输出一个文件。但是想要执行这样的操作,就必须要开启文件写入的权限。
我们可以执行:show variables like '%secure%';
来查看:发现secure_file_priv
的 value 值是 NULL,那么这代表此时文件写入的权限是关闭的,那我们需要写入输出文件的保存路径来开启它。
首先,我们来到MySQL的根目录下,会看到一个my.ini的文件。
打开my.ini文件,添加secure_file_priv
以及他所对应的参数:(我写的是secure_file_priv='D://'
)
注意:路径的斜杠需要采用//需要多加一个斜杠来转义字符,其次,因为C盘的权限问题,请不要把路径写到C盘上。【开始我没有注意这一点导致sql语句一直报错,很头疼】
之后我们重启MySQL服务:
最后重复刚才的sql语句show variables like '%secure%';
来查看是否修改成功:发现已经出现路径了。
那这个时候,我们就可以执行outfile
来输出文件到 D盘的任意位置了。
Text Only | |
---|---|
1 |
|
在sql漏洞中可以使用file系列函数
load_file() :读取指定文件 into outfile :将查询的数据写入文件中 into dumpfile:将查询的数据写入文件中(只能写入一行数据)
Text Only 1 2 3secure_file_prive=null //限制mysqld 不允许导入导出 secure_file_priv=/path/ //限制mysqld的导入导出只能发生在默认的/path/目录下 secure_file_priv=’’ //不对mysqld 的导入 导出做限制
outfile函数可以导出多行,而dumpfile只能导出一行数据 outfile函数在将数据写到文件里时有特殊的格式转换,而dumpfile则保持原数据格式
这时候我们可以通过?id=-1')) union select version(),database(),user() into outfile "D:\\uuu.txt" --+
来使得所需信息输出到uuu.txt
也可以弄一些扩展的东西(通过上传一句话木马实现远程任意命令执行)
Text Only | |
---|---|
1 2 3 |
|
Text Only | |
---|---|
1 |
|
第二十三关¶
第二十三关重新回到get请求,会发现输入单引号报错,但是注释符不管用。猜测注释符被过滤,看来源码果然被注释了,所以我们可以用单引号闭合,发现成功。之后可以使用联合注入。不过在判断列数时候不能使用order by 去判断需要用?id=-1' union select 1,2,3,4 or '1'='1通过不停加数字判断最后根据页面显示是三列,且显示位是2号。
Text Only | |
---|---|
1 2 3 4 5 6 7 8 9 10 |
|
第二十五关¶
本关主要为 or and 过滤,如何绕过 or 和 and 过滤。
根据提示是将or和and这两个替换成空,但是只替换一次。大小写绕过没有用。我们可以采用双写绕过。本次关卡使用联合注入就可以了,information里面涉及or可以写成infoorrmation。
一般性提供以下几种思路:
(1)大小写变形 Or,OR,oR
(2)编码,hex,urlencode
(3)添加注释/or/
(4)利用符号 and=&& or=||
第二十五关¶
Q:sqlmap中将and
替换为&&
,需要使用哪一个--tamper 绕过WAF脚本
A:在SQLMap中,可以使用--tamper
选项来使用特定的绕过WAF脚本。如果你想将AND
替换为&&
,你可以使用内置的tamper
脚本charencode
。
这将使用charencode
脚本来编码请求中的字符,包括将AND
替换为&&
。
Q:我不需要编码请求中的字符,只需要包括将AND替换为&&
A:如果你只想简单地将AND
替换为&&
,而不进行其他字符编码或转换,你可以使用自定义的绕过脚本。以下是一个简单的绕过脚本示例,它将替换查询中的AND
为&&
:
Python | |
---|---|
1 2 3 4 |
|
将上述代码保存为and_to_double_amp.py
(或任何你喜欢的名称),然后在SQLMap中使用--tamper
选项指定该脚本的路径:
Text Only | |
---|---|
1 |
|
这将应用自定义的绕过脚本,将AND
替换为&&
。
第二十六关¶
注释符以及空格给过滤了
我们需要使用单引号进行闭合,双写绕过逻辑运算符或者使用&&
和||
替换。空格绕过网上找了些资料,对于绕过空格限制有大把的方式对于空格,有较多的方法:
Text Only | |
---|---|
1 2 3 4 5 6 |
|
我在windows和kali里面都用不了,可能是因为apache解析不了。只能使用()绕过。报错注入空格使用比较少所以我们可以使用报错注入。
疑问¶
第五关的疑问:¶
第五关是布尔盲注,但是布尔盲注的payload肯定符合语法,只是说通过语法内容的正确与否来(是否回显固定内容),来获取信息。但是有时候如果使用错误语法的payload,也有回显。
Text Only | |
---|---|
1 2 |
|
Text Only | |
---|---|
1 2 |
|
第十七关的疑问:¶
这一关用的使增删改部分,建议看看 SQL 注入天书 和后端代码
源码:
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 |
|
==第一个疑问:==
Text Only | |
---|---|
1 |
|
注意上面代码里的“b”,如果删除则会发生错误(Every derived table must have its own alias)(每个派生表都必须有自己的别名)不懂这是为什么。
==解答:(CharGPT)==
Q:为什么错误
A:在你的 SQL 注入语句中,使用子查询时,每个派生表都必须有一个别名。在你的第二个语句中,你去掉了
b
,但是由于缺少别名,导致了错误。Q:请详细解释为什么使用子查询时,每个派生表都必须有一个别名。
A:在 SQL 查询中,派生表是在查询的 FROM 子句中使用的子查询。当你在 SQL 查询中使用子查询时,派生表(即子查询)实际上是一个临时的表,它会在查询执行时生成,并被引用于主查询中。
给派生表一个别名的原因有几个:
引用字段名: 如果你的子查询中包含了一些计算、选择或其他操作,并且你想在主查询中引用这些操作的结果,你需要为子查询创建一个别名,以便在主查询中使用这些字段。否则,数据库引擎可能无法识别字段是从哪个表(或派生表)中得到的。
SQL 1 2SELECT subquery_alias.field_name FROM (SELECT some_operation AS field_name FROM your_table) AS subquery_alias;
支持多个派生表: 如果你的查询中涉及多个派生表,为每个派生表添加别名有助于区分它们。这是因为每个表必须有唯一的名称,即使是临时生成的派生表也不例外。这有助于数据库引擎正确解释查询中每个表的引用。
SQL 1 2 3SELECT * FROM (SELECT column1 FROM table1) AS table1_alias JOIN (SELECT column2 FROM table2) AS table2_alias ON table1_alias.column1 = table2_alias.column2;
清晰可读性: 使用别名可以使 SQL 查询更易读。它提供了对表或派生表的更具描述性的名称,使查询更易于理解和维护。
总的来说,给每个派生表添加别名是一种良好的 SQL 编码实践,有助于提高查询的可读性、维护性,并确保查询执行时引用的表是明确的。在某些情况下,数据库系统要求为每个派生表提供别名,以满足语法规范。
Q:那为什么 ?id=-1') union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+不需要设置别名
A:在你提供的 SQL 注入语句中,是利用了 UNION 操作符,而不是子查询。在 UNION 操作符中,不需要为每个 SELECT 子句设置别名的主要原因是,UNION 的目标是合并多个查询的结果集,而不是创建派生表。在 UNION 中,结果集的列名是由第一个 SELECT 语句定义的,后续的 SELECT 语句的列名必须与第一个 SELECT 语句的列名相匹配。
具体来说,你的注入语句是这样的:
SQL 1
?id=-1') UNION SELECT 1,2,GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name='users'--+
在这里,UNION 合并了两个查询:
SELECT 1,2
: 产生一个两列的结果集,列值分别为1和2。SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name='users'
: 产生一个包含 users 表列名连接结果的结果集。这两个 SELECT 语句的列数和数据类型必须匹配,而不需要为它们设置别名。数据库系统会使用第一个 SELECT 语句的列名作为整个 UNION 结果的列名。
在这种情况下,UNION 操作是将两个查询的结果集纵向合并,而不涉及子查询的概念。所以,不需要为每个 SELECT 子句设置别名。
(这儿其实就是,之前都是先把后端的select语句闭合掉,然后再执行我们的 union select )
Q:解释子查询语句
A:子查询是一个嵌套在主查询中的查询语句。
子查询是在主查询中嵌套的查询语句,可以返回一个结果集,然后主查询可以使用这个结果集进行进一步的过滤、比较或操作。子查询通常出现在
SELECT
、FROM
、WHERE
等子句中。例如,下面是一个使用子查询的示例:
SQL 1 2 3SELECT column1 FROM table1 WHERE column2 = (SELECT some_column FROM table2 WHERE condition);
在这个例子中,
(SELECT some_column FROM table2 WHERE condition)
就是一个子查询,它返回一个值,然后主查询使用这个值进行条件过滤。而
AND
、OR
是逻辑运算符,用于连接多个条件,例如:
SQL 1 2 3SELECT * FROM table WHERE column1 = 'value' AND column2 > 10;
在这个例子中,
AND
连接了两个条件,要求同时满足column1 = 'value'
和column2 > 10
。总的来说,子查询是一个嵌套在主查询中的完整查询语句,而
AND
、OR
等是用于连接多个条件的逻辑运算符。(这儿我感觉和后端代码有关系,后端代码是要修改数据库内容,(先 select 匹配账户,然后 updata 修改密码)然后我们的payload拼接进去后就形成了子查询。)
==第二个疑问:==
Text Only | |
---|---|
1 |
|
这个会报错(You can't specify target table 'users' for update in FROM clause)(不能在 FROM 子句中指定要更新的目标表“users”)
但是这个报错很正常,原因是mysql数据不支持查询和更新是同一张表。所以我们需要加一个中间表。这个关卡需要输入正确账号因为是密码重置页面,所以爆出的是该账户的原始密码。如果查询时不是users表就不会报错。
示例:查用户名:
Text Only | |
---|---|
1 |
|
这个会报错,但是我们可以用其他方法绕过 ,将表名users用(select username from users)a
替换掉
Text Only | |
---|---|
1 |
|
Text Only | |
---|---|
1 |
|
示例:查密码:(仍然报错:Only constant XPATH queries are supported(仅支持常量 XPATH 查询))
Text Only | |
---|---|
1 |
|
但这一关知道用户名就可以随便改密码了呀
(来自https://blog.csdn.net/dreamthe/article/details/123795302)
(来自https://blog.csdn.net/l2872253606/article/details/124411903)
同样,使用sqlmap:python3 sqlmap.py -r "D:\post.txt" -D security -T users --columns --dump
并不能成功跑出数据来,因为这儿我们跑的时候会直接给替换掉,也就是说跑出来的并不是原数据库的密码,而是替换之后的密码(后端代码本来就是先 select
匹配账户,然后 updata
修改密码)。
(你可以边让 sqlmap 跑,边刷新Navicat
,瞅瞅数据库都遭遇了什么折磨……哎……真的是……哎)
复原的方法就是重置一下 sqli-labs 数据库
但这一关知道用户名就可以随便改密码了呀
// txt内容如下:
Text Only | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|