发现P神办了个小密圈两周年的活动,并且放了一些题目。学习记录一下
easy-function
这道题代码很短,就几行,但是学到了新知识
1 |
|
不难看出,需要通过传入action
作为函数名,传入arg
作为该函数的变量。初步的想法是构造成eval
函数然后任意执行代码。这里犯了个错,eval
是一种语言结构而不是函数,所以不能通过这种动态调用函数的方式调用,所以改用assert
。
但是发现action
是有两个参数的,所以assert
和system
不行。试试,create_fuction(),为了本地测试方便,先将正则部分注释掉了。
再看正则部分,action
要出现除了字母数字以及下划线以外的字符。回想一下所有的函数名,似乎都是字母构成的,例如system
,assert
如果引入一个非字母的字符,必然导致函数无法执行。
这边从大佬们的题解里学到了php默认的命名空间是 \
php里默认命名空间是\,所有原生函数和类都在这个命名空间中。普通调用一个函数,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路径;而如果写\function_name() 这样调用函数,则其实是写了一个绝对路径。
如果你在其他namespace里调用系统类,就必须写绝对路径这种写法。
就是
\
在php中表示默认的命名空间,比如写一些类的时候会在开头写
1
2
3 > namespace think\db;
> use think\Exception;
>
也就是说,调用php自带的原生函数时
可以在前面加一个\
,这样的写法就是调用默认命名空间中的某个函数。
这样就满足了正则,就可以注入任意代码了。
这边应该是禁用了system
函数,所以不能直接调用系统命令。因此payload如下
1 | http://51.158.75.42:8087/?action=\create_function&arg=}print_r(scandir(%27../%27));// |
1 | http://51.158.75.42:8087/?action=\create_function&arg=}print_r(file_get_contents(%27../flag_h0w2execute_arb1trary_c0de%27));// |
easy_prcewaf
1 |
|
是一个模拟文件上传的过程。并且会讲上传的文件内容读取出来,判断里面是否写入了php代码
这样可能是为了防止文件包含漏洞
吧.文件上传之后会被保存在一个以用户ip用md5加密后
的路径下,并且用一个随机数字重命名该文件。
问题的关键点在于如何绕过is_php
这个正则。只要绕过这里,就可以上传任意的php
文件并且执行。最先想到的是之前做过类似死亡退出
的那题。将这些字符利用编码的方式变成满足正则的字符串。然后再通过某种方式解码,还原成正常的php
代码,就可以执行了。
可控的输入点只有文件的内容。也就意味着,没办法利用伪协议进行编码解码的操作。
解决办法:正则匹配 回溯超过最大次数(100万次)则正则匹配失败,导致的绕过
http://www.kingkk.com/2018/11/Code-Breaking-Puzzles-%E9%A2%98%E8%A7%A3-%E5%AD%A6%E4%B9%A0%E7%AF%87/
https://www.leavesongs.com/PENETRATION/use-pcre-backtrack-limit-to-bypass-restrict.html
原理在以上两篇文章写的很清楚了。只记录下具体做法。
因此payload
如下
1 | #我是写了一个上传文件的表单 |
1 | #python生成一个文件 |
上传这个文件就能拿到flag
。当绕过了正则,其实php
的代码内容就可以发挥各自的想象
比如利用include
1 | with open("shell.txt", "w+") as f: |
先上传一个文件内容用base64
加密好的文件,再上传这个shell.txt
就可以getshell
;