打开题目
输入字符的时候啥也不回显。只有输入数字的时候页面有回显
但是当我们输入union,from,sleep,where,order等,页面回显nonono,很明显过滤了这些关键词
最开始我的思路是打算尝试双写绕过
1;ununionion select 1,2,3
发现依旧被过滤了。
那我们试试堆叠注入
1;show databases;
发现页面有6个数据库
1;show tables;
有一个名为Flag的表
那我们试试能不能直接查看Flag的表结构
1;desc `Flag`;
同样,这里被过滤了flag字段,所以我们不能直接查询到Flag表下的字段
上面的测试我们知道from和order都被过滤了
本来想试试句柄handler命令查询的,结果一试,handler也被过滤了。
那就用不了堆叠注入,也用不了联合查询。
看了大佬的wp后知道
既然输入字符无回显,输入数字才有回显。
他的后端既然能做到数字回显,字母不回显,说明有一个 或 结构,而且不直接回显flag,但作为一道题目,from一定是from flag
所以大佬猜测的后端为:
select $_POST['query'] || flag from Flag
结合我们刚刚上面做的堆叠注入的查询知道,确实有个名为Flag的表
所以上面的猜测成立,不会是from别的地方。
我们对上面的代码简单审计一下,$query
是通过 POST 请求获取的用户输入,所以后端通过获取用户输入的数据,这里的“或”符号(“ | | ”)的意思是,作为逻辑或用于短路逻辑,如果前者的语句为真,则整个语句为真,不理会后面的语句是真还是假直接输出结果。
所以我们这直接利用短路语法
payload:
*,1
这里的原理是
sql=select.post['query']."||flag from Flag";
如果$post['query']的数据为*,1,sql语句就变成了select *,1||flag from Flag,
就是select *,1 from Flag,这样就直接查询出了Flag表中的所有内容
输入 *,1 这里会增加一个临时列,他的列名为1,然后那一列的值都为1。
当我们只关心数据表有多少记录行而不需要知道具体的字段值时,类似“select 1 from table_Name”是一个很不错的SQL语句写法,它通常用于子查询。这样可以减少系统开销,提高运行效率,因为这样子写的SQL语句,数据库引擎就不会去检索数据表里一条条具体的记录和每条记录里一个个具体的字段值并将它们放到内存里,而是根据查询到有多少行存在就输出多少个“1”,每个“1”代表有1行记录,同时选用数字1还因为它所占用的内存空间最小,当然用数字0的效果也一样。在不需要知道具体的记录值是什么的情况下这种写法无疑更加可取。
得到flag
payload:
1;set sql_mode=PIPES_AS_CONCAT;select 1
这里看英文就知道这里把管道符||当做了连接符号
我们原先猜测的后端代码为
select $_POST['query'] || flag from Flag
变成了
select $_POST['query'] and flag from Flag
在 SQL 注入攻击中,concat 是一个用于连接字符串的 SQL 函数。它接受两个或多个字符串作为参数,并返回这些字符串连接在一起的结果。
<1>作为符号命令执行上下文:在一些特殊的上下文中,特别是在 命令执行或 shell 脚本 中, || 可以表示一个截断符号,只有在前一个命令失败(返回非零状态码)时才执行下一个命令。
例如:command1 || command2
如果
command1
失败(返回非零状态码),则执行command2
。这种用法可以用于处理错误情况或依赖于前一个命令的成功执行。
<2>作为逻辑或:|| 表示逻辑或运算符,即只要两边的表达式之一为真,整个条件就为真。
例如:
if condition1 or condition2:
# 如果 condition1 或 condition2 为真,则执行这里的代码只要
condition1
或者condition2
中有一个为真,整个条件就为真,而不需要等待另一个条件的计算结果。
<3>用于短路逻辑:在某些情况下,||
可能被用于实现短路逻辑,这意味着如果第一个表达式为真,就不再计算第二个表达式。如果第一个表达式为假,那么才会计算第二个表达式。这种行为利用了逻辑或的性质,只要有一个条件为真,整个表达式就为真。
例如:var result = expression1 || expression2;
在这里,如果
expression1
为真,expression2
将不会被计算
举例说明:
“||”运算符检查第一个表达式是否返回“true”,如果是“true”则结果必为“true”,不再检查其他内容。“a/0”是个明显的错误!但短路运算“||”先执行“a==b”判断,返回“true”,遂造成短路,也就不进行“a/0”操作了,程序会打出"That's in my control."。这个时候,交换一下“||”左右两边的表达式,程序立即抛出异常“java.lang.ArithmeticException: / by zero”。
class Logic{
public ststic void main(String[] args){
int a=1;
int b=1;
if(a==b || b
参考文章:java中“&&”和“||”短路详解_java中||-CSDN博客
在我自己本地的数据库下有个users表,表的结构如下
我们用select 1 from users;
这个语句在这里的作用就是查询users表下有多少行数据,有多少行就输出多少行的1,而select 1 from就是建立一个临时列,这个列的所有初始值都设为1。而为什么选用数字1呢,因为数字1所占的内存最小。用其他数字效果也是一样的。
而使用select *,1 from users;
也就是本题的payload,效果如下
select *,1 from users;
这个语句显示了users表下的所有列,以及我们的临时列1
sql_mode 是一个MySQL系统变量,用于设置数据库操作的不同方面
文章参考wp为:[SUCTF 2019]EasySQL 1 Writeup(超级详细)-CSDN博客