[{"content":"Cobalt Strike 4.8 Client Docker 部署指南 为解决java环境不兼容问题，将 Cobalt Strike 4.8 汉化版客户端（Java Swing GUI）完整容器化，通过浏览器远程桌面访问。 Github项目链接\n📋 前置要求 Docker Desktop: 20.10+（含 Compose v2） 内存: 至少 4GB 可用（容器限制 2GB） CPU: 建议 2 核以上 🏗️ 技术架构 ┌─────────────────────────────────────────────┐ │ Docker Container (Ubuntu 20.04) │ │ │ │ entrypoint.sh (PID 1 入口) │ │ ├─ [启动前] start_vnc.sh 清理残留 │ │ │ (锁文件/socket/孤儿进程/shm) │ │ └─ exec supervisord │ │ ├─ [vncserver] Xvnc :99 │ │ │ └─ 内联再清一次锁后启动 (:5900) │ │ ├─ [noVNC] websockify (:6080) │ │ │ └─ 浏览器 WebSocket→VNC │ │ └─ [csclient] start.sh → CS GUI │ │ (DISPLAY=:99) │ └─────────────────────────────────────────────┘ ↑ port 6080 / 5900 浏览器 http://localhost:6080 关键设计点：\n单一 X server：Xvnc :99 同时充当显示服务器和 VNC 服务，CS GUI 与 VNC 画面天然同步（不再用 Xvfb，避免双 display 不同步问题）。 每次启动自动清理：entrypoint.sh 在拉起 supervisord 前执行 start_vnc.sh，删除上次异常退出残留的 /tmp/.X99-lock、陈旧 socket、孤儿 Xvnc/java 进程和共享内存段；supervisord 的 [program:vncserver] 又内联清一次锁——彻底杜绝重启后 Server is already active for display 99。 免密访问：-SecurityTypes None，连接无需密码。 supervisord 作 PID 1：统一管理所有子进程，任一崩溃可自动重启。 中文字体：预装 fonts-wqy-zenhei + fonts-noto-cjk，汉化界面正常显示。 📁 目录结构 CobaltStrike-Docker-Client/ ├── Dockerfile # 镜像定义 (Java 11 + TigerVNC + noVNC) ├── docker-compose.yml # 容器编排 (端口/资源/volume) ├── entrypoint.sh # 容器入口: 清理 → supervisord ├── start_vnc.sh # 启动前自动清理残留锁/socket/进程 ├── supervisord.conf # 进程管理配置 (Xvnc/noVNC/CS) ├── start.sh # CS 客户端启动脚本 ├── .dockerignore # 构建忽略规则 ├── README.md # 本文件 ├── prepare.bat # (可选) 从原始目录整理文件 ├── deploy.bat # Windows 一键 build/up/down/logs └── cobaltstrike-client/ # ⚠️ volume 挂载源目录 ├── cobaltstrike-client.jar # 主客户端包 ├── cobaltstrike.jar # 核心库 ├── uHook.jar # Hook 库 ├── cobaltstrike.auth # ⚠️ 授权文件（必需！） └── plugin/ # 插件目录 (Erebus/Ladon/TaoWu/XieGongZi...) 🚀 快速开始 项目已包含全部客户端文件，直接构建即可：\ncd C:\\Users\\17856\\Desktop\\CTF\\CobaltStrike-Docker-Client # 构建镜像（首次约 3-5 分钟，需下载依赖） docker-compose build --no-cache # 启动容器 docker-compose up -d # 查看日志确认各服务就绪 docker-compose logs -f 访问界面 打开浏览器访问 👉 http://localhost:6080 （无需密码）\n或用任意 VNC 客户端连接 localhost:5900（无密码）。\n🔧 常用命令 docker ps # 查看容器状态 docker-compose logs -f # 实时日志 docker-compose down # 停止并清理 docker-compose restart # 重启 docker exec -it cobaltstrike-4.8-client bash # 进入容器调试 docker-compose up -d --build # 改文件后重建 ⚙️ 自定义配置 修改资源限制（编辑 docker-compose.yml） mem_limit: 4g # 最大内存 cpus: 4.0 # CPU 核心数 shm_size: \u0026#39;2g\u0026#39; # 共享内存 修改 noVNC 端口 ports: - \u0026#34;8080:6080\u0026#34; # 宿主机端口:容器端口 局域网其他机器访问 把端口映射改为 \u0026quot;0.0.0.0:6080:6080\u0026quot;，再从其他机器访问 http://\u0026lt;你的IP\u0026gt;:6080。\n⚠️ 生产环境务最好加 nginx + WebSocket SSL，并改用带密码的 VNC，切勿裸暴露公网。\n📝 注意事项 合法用途：仅用于获得授权的渗透测试 / CTF / 研究。 首次启动慢：Java GUI 预热需时间，耐心等 10-20 秒。 数据持久化：Java 配置经 volume (cs-java-config) 保存。 更新流程：改客户端文件 → restart；改构建配置 → build --no-cache \u0026amp;\u0026amp; up -d。 ","permalink":"https://lewis1766.github.io/posts/20260918/","summary":"\u003ch1 id=\"cobalt-strike-48-client-docker-部署指南\"\u003eCobalt Strike 4.8 Client Docker 部署指南\u003c/h1\u003e\n\u003cp\u003e为解决java环境不兼容问题，将 \u003cstrong\u003eCobalt Strike 4.8 汉化版客户端\u003c/strong\u003e（Java Swing GUI）完整容器化，通过浏览器远程桌面访问。\n\u003ca href=\"https://github.com/Lewis1766/CobaltStrike-docker-vnc\"\u003eGithub项目链接\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"-前置要求\"\u003e📋 前置要求\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eDocker Desktop\u003c/strong\u003e: 20.10+（含 Compose v2）\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e内存\u003c/strong\u003e: 至少 4GB 可用（容器限制 2GB）\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eCPU\u003c/strong\u003e: 建议 2 核以上\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"-技术架构\"\u003e🏗️ 技术架构\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e┌─────────────────────────────────────────────┐\n│           Docker Container (Ubuntu 20.04)    │\n│                                              │\n│   entrypoint.sh (PID 1 入口)                  │\n│     ├─ [启动前] start_vnc.sh 清理残留          │\n│     │          (锁文件/socket/孤儿进程/shm)    │\n│     └─ exec supervisord                       │\n│          ├─ [vncserver] Xvnc :99              │\n│          │   └─ 内联再清一次锁后启动 (:5900)   │\n│          ├─ [noVNC]     websockify (:6080)    │\n│          │   └─ 浏览器 WebSocket→VNC          │\n│          └─ [csclient]  start.sh → CS GUI     │\n│                         (DISPLAY=:99)         │\n└─────────────────────────────────────────────┘\n        ↑ port 6080 / 5900\n   浏览器 http://localhost:6080\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e关键设计点\u003c/strong\u003e：\u003c/p\u003e","title":"CobaltStrike的容器化实现"},{"content":"前言 最近对渗透测试特别感兴趣，越来越想找一个真实的环境练手，最后瞄准了校园网。我想如果被发现入侵，好歹是自己学校，应该不会过于为难我。\n搞笑的是，我真的被导员联系了，说是上网有关问题，当时我心中一悸，心想是不是渗透的太过火了，结果竟然是因为fq问题，并且我被告知不能再fq，我写了检讨书。。。我现在连github都不敢打开，那么这几天的学习就暂时停一阵吧。\n我把校园网攻击了反而没人问。。。\nSpring Boot 信息泄露 我最近在学校的专利成果转化中心勤工俭学，不得不说学校的岗位就是清闲不少。我没事干的时候就扫了一下\n这里的wifi密码他们告诉了我。连接后发现网段是192.168.5.x/24，是我们校园网里的一个配网。扫描发现 192.168.5.15 开放 Spring Boot Actuator 端点：\n| /heapdump | 严重 - 可下载堆转储文件 |\n| /env | 严重 - 泄露环境变量配置 |\n直接访问断点，得到heapdump文件和env配置，使用jdumpspider分析一下，这个工具用来springboot内存取证简单好用，本质就是一个提取关键字的脚本。比较初步的分析就不必惊动EclipseMemoryAnalyzer了。我整理了一下所有泄露的信息。 华为AX3PRO路由器 (192.168.5.1) 发现弱密码：和wifi密码相同，为门牌号输三次 成功登入管理界面 看配置 这里的手动设置显示的是路由器的身份，说明了他们是如何接入校园网的 10.4.175.87试了一下，403，这个网关底下应该有好几个重要资产 dns服务器防线也很深\n还有一个有意思的点，之前的那个专利申请系统不止192.168.5.15，还有很多ip，但是有时候我扫描不到。我想了好久。因为一个专利申请服务器怎么会时断时续的开着，并且在办公室里并没有发现物理服务器。 今天在路由器的连接设备界面看到了192.168.5.15，恍然大悟，这是一台个人电脑，服务器是在他们电脑自己上，估计是他们用的这个专利申请软件有大问题，为什么会在内网暴露heapdump和env，这个问题之后再研究 看到华为智慧互联开启，看来是使用这个手段实现各办公室网络无缝衔接的 并且暴露了组网密码，我想可不可以利用这个密码欺骗其他路由器，自己搞一个假的路由器，这样华为的互联策略会以为他是“自己人”。待我抽时间研究一下这个华为智慧互联吧\n","permalink":"https://lewis1766.github.io/posts/20260601/","summary":"\u003ch2 id=\"前言\"\u003e前言\u003c/h2\u003e\n\u003cp\u003e最近对渗透测试特别感兴趣，越来越想找一个真实的环境练手，最后瞄准了校园网。我想如果被发现入侵，好歹是自己学校，应该不会过于为难我。\u003c/p\u003e\n\u003cp\u003e搞笑的是，我真的被导员联系了，说是上网有关问题，当时我心中一悸，心想是不是渗透的太过火了，结果竟然是因为fq问题，并且我被告知不能再fq，我写了检讨书。。。我现在连github都不敢打开，那么这几天的学习就暂时停一阵吧。\u003c/p\u003e\n\u003cp\u003e我把校园网攻击了反而没人问。。。\u003c/p\u003e\n\u003ch2 id=\"spring-boot-信息泄露\"\u003eSpring Boot 信息泄露\u003c/h2\u003e\n\u003cp\u003e我最近在学校的专利成果转化中心勤工俭学，不得不说学校的岗位就是清闲不少。我没事干的时候就扫了一下\u003c/p\u003e\n\u003cp\u003e这里的wifi密码他们告诉了我。连接后发现网段是192.168.5.x/24，是我们校园网里的一个配网。扫描发现 \u003ccode\u003e192.168.5.15\u003c/code\u003e 开放 Spring Boot Actuator 端点：\u003c/p\u003e\n\u003cp\u003e| \u003ccode\u003e/heapdump\u003c/code\u003e | 严重 - 可下载堆转储文件 |\u003c/p\u003e\n\u003cp\u003e| \u003ccode\u003e/env\u003c/code\u003e | 严重 - 泄露环境变量配置 |\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"heapdump\" loading=\"lazy\" src=\"/images/heapdump.png\"\u003e\u003c/p\u003e\n\u003cp\u003e直接访问断点，得到heapdump文件和env配置，使用jdumpspider分析一下，这个工具用来springboot内存取证简单好用，本质就是一个提取关键字的脚本。比较初步的分析就不必惊动EclipseMemoryAnalyzer了。我整理了一下所有泄露的信息。\n\u003cimg alt=\"page\" loading=\"lazy\" src=\"/images/page.png\"\u003e\n\u003cimg alt=\"jdumpspider\" loading=\"lazy\" src=\"/images/jdumpspider.png\"\u003e\n\u003cimg alt=\"cmd\" loading=\"lazy\" src=\"/images/cmd.png\"\u003e\n\u003cimg alt=\"发现专利局帐密\" loading=\"lazy\" src=\"/images/%E5%8F%91%E7%8E%B0%E4%B8%93%E5%88%A9%E5%B1%80%E5%B8%90%E5%AF%86.png\"\u003e\u003c/p\u003e\n\u003ch2 id=\"华为ax3pro路由器\"\u003e华为AX3PRO路由器\u003c/h2\u003e\n\u003cp\u003e(192.168.5.1)\n\u003cimg alt=\"router\" loading=\"lazy\" src=\"/images/router.png\"\u003e\n发现弱密码：和wifi密码相同，为门牌号输三次\n成功登入管理界面\n\u003cimg alt=\"admin\" loading=\"lazy\" src=\"/images/admin.png\"\u003e\n看配置\n\u003cimg alt=\"config\" loading=\"lazy\" src=\"/images/config.png\"\u003e\n这里的手动设置显示的是路由器的身份，说明了他们是如何接入校园网的\n10.4.175.87试了一下，403，这个网关底下应该有好几个重要资产\ndns服务器防线也很深\u003c/p\u003e\n\u003cp\u003e还有一个有意思的点，之前的那个专利申请系统不止192.168.5.15，还有很多ip，但是有时候我扫描不到。我想了好久。因为一个专利申请服务器怎么会时断时续的开着，并且在办公室里并没有发现物理服务器。\n今天在路由器的连接设备界面看到了192.168.5.15，恍然大悟，这是一台个人电脑，服务器是在他们电脑自己上，估计是他们用的这个专利申请软件有大问题，为什么会在内网暴露heapdump和env，这个问题之后再研究\n\u003cimg alt=\"devices\" loading=\"lazy\" src=\"/images/devices.png\"\u003e\u003c/p\u003e\n\u003cp\u003e看到华为智慧互联开启，看来是使用这个手段实现各办公室网络无缝衔接的\n\u003cimg alt=\"zhilian\" loading=\"lazy\" src=\"/images/zhilian.png\"\u003e\n并且暴露了组网密码，我想可不可以利用这个密码欺骗其他路由器，自己搞一个假的路由器，这样华为的互联策略会以为他是“自己人”。待我抽时间研究一下这个华为智慧互联吧\u003c/p\u003e","title":"一次对学校内网的渗透"},{"content":"前言 最近在 GitHub 学生包里发现了一个好东西——GitHub Copilot CLI\u0026hellip;\nCopilot CLI 听说这个产品是 Claude Code 的竞品，刚看新闻说微软让员工从Claude Code转用它\n正好对比体验一下\n大一 C 语言实践作业 翻到之前大一的 C 语言作业——学生管理系统\u0026hellip;\n当时懵懂无知，完全不懂什么是 agent\u0026hellip;\n用 DeepSeek 改了又改，虽然（but still）仍然不会古法编程\u0026hellip;\n现在用 Copilot CLI，几分钟就能写好，完全不用手。\n搭一个网页版吧 核心代码 from flask import Flask, g, render_template, request, redirect, url_for import sqlite3 import os BASE_DIR = os.path.dirname(__file__) DB_PATH = os.path.join(BASE_DIR, \u0026#39;student.db\u0026#39;) app = Flask(__name__, instance_path=BASE_DIR) def get_db(): db = getattr(g, \u0026#39;_database\u0026#39;, None) if db is None: db = g._database = sqlite3.connect(DB_PATH) db.row_factory = sqlite3.Row return db def init_db(): db = get_db() cur = db.cursor() cur.execute(\u0026#39;\u0026#39;\u0026#39; CREATE TABLE IF NOT EXISTS students ( id TEXT PRIMARY KEY, name TEXT, gender TEXT, birth TEXT, address TEXT, phone TEXT, email TEXT ) \u0026#39;\u0026#39;\u0026#39;) cur.execute(\u0026#39;\u0026#39;\u0026#39; CREATE TABLE IF NOT EXISTS courses ( id INTEGER PRIMARY KEY AUTOINCREMENT, sid TEXT, cid TEXT, name TEXT, credit REAL ) \u0026#39;\u0026#39;\u0026#39;) cur.execute(\u0026#39;\u0026#39;\u0026#39; CREATE TABLE IF NOT EXISTS scores ( id INTEGER PRIMARY KEY AUTOINCREMENT, ssid TEXT, sname TEXT, scid TEXT, cname TEXT, score REAL ) \u0026#39;\u0026#39;\u0026#39;) db.commit() @app.teardown_appcontext def close_connection(exception): db = getattr(g, \u0026#39;_database\u0026#39;, None) if db is not None: db.close() with app.app_context(): init_db() @app.route(\u0026#39;/\u0026#39;) def index(): return render_template(\u0026#39;index.html\u0026#39;) # Students @app.route(\u0026#39;/students\u0026#39;) def students(): db = get_db() cur = db.execute(\u0026#39;SELECT * FROM students ORDER BY id\u0026#39;) rows = cur.fetchall() return render_template(\u0026#39;students.html\u0026#39;, students=rows) @app.route(\u0026#39;/students/add\u0026#39;, methods=[\u0026#39;GET\u0026#39;, \u0026#39;POST\u0026#39;]) def add_student(): if request.method == \u0026#39;POST\u0026#39;: form = request.form db = get_db() try: db.execute(\u0026#39;INSERT INTO students(id,name,gender,birth,address,phone,email) VALUES (?,?,?,?,?,?,?)\u0026#39;, (form[\u0026#39;id\u0026#39;], form[\u0026#39;name\u0026#39;], form.get(\u0026#39;gender\u0026#39;,\u0026#39;\u0026#39;), form.get(\u0026#39;birth\u0026#39;,\u0026#39;\u0026#39;), form.get(\u0026#39;address\u0026#39;,\u0026#39;\u0026#39;), form.get(\u0026#39;phone\u0026#39;,\u0026#39;\u0026#39;), form.get(\u0026#39;email\u0026#39;,\u0026#39;\u0026#39;))) db.commit() except sqlite3.IntegrityError: return \u0026#39;学号已存在\u0026#39;, 400 return redirect(url_for(\u0026#39;students\u0026#39;)) return render_template(\u0026#39;student_form.html\u0026#39;, student=None) @app.route(\u0026#39;/students/edit/\u0026lt;sid\u0026gt;\u0026#39;, methods=[\u0026#39;GET\u0026#39;,\u0026#39;POST\u0026#39;]) def edit_student(sid): db = get_db() if request.method == \u0026#39;POST\u0026#39;: form = request.form db.execute(\u0026#39;UPDATE students SET id=?,name=?,gender=?,birth=?,address=?,phone=?,email=? WHERE id=?\u0026#39;, (form[\u0026#39;id\u0026#39;], form[\u0026#39;name\u0026#39;], form.get(\u0026#39;gender\u0026#39;,\u0026#39;\u0026#39;), form.get(\u0026#39;birth\u0026#39;,\u0026#39;\u0026#39;), form.get(\u0026#39;address\u0026#39;,\u0026#39;\u0026#39;), form.get(\u0026#39;phone\u0026#39;,\u0026#39;\u0026#39;), form.get(\u0026#39;email\u0026#39;,\u0026#39;\u0026#39;), sid)) db.commit() return redirect(url_for(\u0026#39;students\u0026#39;)) cur = db.execute(\u0026#39;SELECT * FROM students WHERE id=?\u0026#39;, (sid,)) student = cur.fetchone() return render_template(\u0026#39;student_form.html\u0026#39;, student=student) @app.route(\u0026#39;/students/delete/\u0026lt;sid\u0026gt;\u0026#39;, methods=[\u0026#39;POST\u0026#39;]) def delete_student(sid): db = get_db() db.execute(\u0026#39;DELETE FROM students WHERE id=?\u0026#39;, (sid,)) db.execute(\u0026#39;DELETE FROM courses WHERE sid=?\u0026#39;, (sid,)) db.execute(\u0026#39;DELETE FROM scores WHERE ssid=?\u0026#39;, (sid,)) db.commit() return redirect(url_for(\u0026#39;students\u0026#39;)) # Courses @app.route(\u0026#39;/courses\u0026#39;) def courses(): db = get_db() cur = db.execute(\u0026#39;SELECT * FROM courses ORDER BY sid, cid\u0026#39;) rows = cur.fetchall() return render_template(\u0026#39;courses.html\u0026#39;, courses=rows) @app.route(\u0026#39;/courses/add\u0026#39;, methods=[\u0026#39;GET\u0026#39;,\u0026#39;POST\u0026#39;]) def add_course(): if request.method == \u0026#39;POST\u0026#39;: f = request.form db = get_db() db.execute(\u0026#39;INSERT INTO courses(sid,cid,name,credit) VALUES (?,?,?,?)\u0026#39;, (f[\u0026#39;sid\u0026#39;], f[\u0026#39;cid\u0026#39;], f[\u0026#39;name\u0026#39;], float(f.get(\u0026#39;credit\u0026#39;,0)))) db.commit() return redirect(url_for(\u0026#39;courses\u0026#39;)) return render_template(\u0026#39;course_form.html\u0026#39;, course=None) @app.route(\u0026#39;/courses/delete/\u0026lt;int:id\u0026gt;\u0026#39;, methods=[\u0026#39;POST\u0026#39;]) def delete_course(id): db = get_db() # delete related scores cur = db.execute(\u0026#39;SELECT sid,cid,name FROM courses WHERE id=?\u0026#39;, (id,)) row = cur.fetchone() if row: db.execute(\u0026#39;DELETE FROM scores WHERE scid=? AND ssid=?\u0026#39;, (row[\u0026#39;cid\u0026#39;], row[\u0026#39;sid\u0026#39;])) db.execute(\u0026#39;DELETE FROM courses WHERE id=?\u0026#39;, (id,)) db.commit() return redirect(url_for(\u0026#39;courses\u0026#39;)) # Scores @app.route(\u0026#39;/scores\u0026#39;) def scores(): db = get_db() cur = db.execute(\u0026#39;SELECT * FROM scores ORDER BY ssid\u0026#39;) rows = cur.fetchall() return render_template(\u0026#39;scores.html\u0026#39;, scores=rows) @app.route(\u0026#39;/scores/add\u0026#39;, methods=[\u0026#39;GET\u0026#39;,\u0026#39;POST\u0026#39;]) def add_score(): if request.method == \u0026#39;POST\u0026#39;: f = request.form db = get_db() db.execute(\u0026#39;INSERT INTO scores(ssid,sname,scid,cname,score) VALUES (?,?,?,?,?)\u0026#39;, (f[\u0026#39;ssid\u0026#39;], f[\u0026#39;sname\u0026#39;], f[\u0026#39;scid\u0026#39;], f[\u0026#39;cname\u0026#39;], float(f.get(\u0026#39;score\u0026#39;,0)))) db.commit() return redirect(url_for(\u0026#39;scores\u0026#39;)) return render_template(\u0026#39;score_form.html\u0026#39;, score=None) @app.route(\u0026#39;/scores/delete/\u0026lt;int:id\u0026gt;\u0026#39;, methods=[\u0026#39;POST\u0026#39;]) def delete_score(id): db = get_db() db.execute(\u0026#39;DELETE FROM scores WHERE id=?\u0026#39;, (id,)) db.commit() return redirect(url_for(\u0026#39;scores\u0026#39;)) # Stats @app.route(\u0026#39;/stats\u0026#39;) def stats(): sid = request.args.get(\u0026#39;sid\u0026#39;) db = get_db() if not sid: return render_template(\u0026#39;stats.html\u0026#39;, sid=None, stats=None) # calculate avg, total credits passed cur = db.execute(\u0026#39;SELECT score, scid FROM scores WHERE ssid=?\u0026#39;, (sid,)) rows = cur.fetchall() if not rows: return render_template(\u0026#39;stats.html\u0026#39;, sid=sid, stats=None) total = 0.0 cnt = 0 credits = 0.0 for r in rows: total += r[\u0026#39;score\u0026#39;] cnt += 1 if r[\u0026#39;score\u0026#39;] \u0026gt;= 60: c = db.execute(\u0026#39;SELECT credit FROM courses WHERE sid=? AND cid=?\u0026#39;, (sid, r[\u0026#39;scid\u0026#39;])).fetchone() if c: credits += c[\u0026#39;credit\u0026#39;] avg = total / cnt if cnt else 0 return render_template(\u0026#39;stats.html\u0026#39;, sid=sid, stats={\u0026#39;avg\u0026#39;:avg,\u0026#39;credits\u0026#39;:credits,\u0026#39;count\u0026#39;:cnt}) # Course ranking @app.route(\u0026#39;/rank/\u0026lt;cid\u0026gt;\u0026#39;) def rank(cid): db = get_db() cur = db.execute(\u0026#39;SELECT sname, score FROM scores WHERE scid=? ORDER BY score DESC\u0026#39;, (cid,)) rows = cur.fetchall() return render_template(\u0026#39;rank.html\u0026#39;, cid=cid, rows=rows) if __name__ == \u0026#39;__main__\u0026#39;: app.run(host=\u0026#39;127.0.0.1\u0026#39;, port=5000, debug=True) 是用flask搭的 代码不详说，就是一个非常简单的项目，.db文件是数据库，用的sqlite，打开试试，在5000端口跑起来 优雅且流畅，不禁感慨AI可以取代多少之前人工的工作，从有这个想法到落地实现这个项目仅用了20分钟不到。。。 但是在想想，以后最重要的可能就是那个想法。。。\nClaude Code 最近通过Vidar的老学长搞到了ClaudeCode的key，每天有一些额度，正好让我这个穷人体验一下。\n感受 目前的感受是快，比那个垃圾的Copilot不知道准确了多少，降低了不少重复工作\n本人还在使用中，等我之后的文章详细说说，以后他就是主力了\n","permalink":"https://lewis1766.github.io/posts/20260519/","summary":"\u003ch2 id=\"前言\"\u003e前言\u003c/h2\u003e\n\u003cp\u003e最近在 GitHub 学生包里发现了一个好东西——\u003cstrong\u003eGitHub Copilot CLI\u003c/strong\u003e\u0026hellip;\u003c/p\u003e\n\u003ch2 id=\"copilot-cli\"\u003eCopilot CLI\u003c/h2\u003e\n\u003cp\u003e听说这个产品是 \u003cstrong\u003eClaude Code\u003c/strong\u003e 的竞品，刚看新闻说微软让员工从Claude Code转用它\u003cbr\u003e\n正好对比体验一下\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"Copilot CLI 运行截图\" loading=\"lazy\" src=\"/images/copilotcli.png\"\u003e\u003c/p\u003e\n\u003ch2 id=\"大一-c-语言实践作业\"\u003e大一 C 语言实践作业\u003c/h2\u003e\n\u003cp\u003e翻到之前大一的 C 语言作业——\u003cstrong\u003e学生管理系统\u003c/strong\u003e\u0026hellip;\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"大一C语言作业截图\" loading=\"lazy\" src=\"/images/c.png\"\u003e\u003c/p\u003e\n\u003cp\u003e当时懵懂无知，完全不懂什么是 agent\u0026hellip;\u003cbr\u003e\n用 DeepSeek 改了又改，虽然（but still）仍然不会古法编程\u0026hellip;\u003c/p\u003e\n\u003cp\u003e现在用 Copilot CLI，几分钟就能写好，完全不用手。\u003cbr\u003e\n搭一个网页版吧\n\u003cimg alt=\"生成的文件\" loading=\"lazy\" src=\"/images/a.png\"\u003e\u003c/p\u003e\n\u003ch2 id=\"核心代码\"\u003e核心代码\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e flask \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e Flask, g, render_template, request, redirect, url_for\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e sqlite3\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e os\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eBASE_DIR \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003edirname(__file__)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eDB_PATH \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ejoin(BASE_DIR, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;student.db\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Flask(__name__, instance_path\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003eBASE_DIR)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eget_db\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    db \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e getattr(g, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;_database\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e db \u003cspan style=\"color:#f92672\"\u003eis\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        db \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e g\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e_database \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e sqlite3\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003econnect(DB_PATH)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003erow_factory \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e sqlite3\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eRow\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e db\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003einit_db\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    db \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e get_db()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    cur \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecursor()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    cur\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexecute(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u0026#39;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        CREATE TABLE IF NOT EXISTS students (\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            id TEXT PRIMARY KEY,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            name TEXT,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            gender TEXT,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            birth TEXT,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            address TEXT,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            phone TEXT,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            email TEXT\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        )\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    \u0026#39;\u0026#39;\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    cur\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexecute(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u0026#39;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        CREATE TABLE IF NOT EXISTS courses (\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            id INTEGER PRIMARY KEY AUTOINCREMENT,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            sid TEXT,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            cid TEXT,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            name TEXT,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            credit REAL\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        )\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    \u0026#39;\u0026#39;\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    cur\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexecute(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u0026#39;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        CREATE TABLE IF NOT EXISTS scores (\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            id INTEGER PRIMARY KEY AUTOINCREMENT,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            ssid TEXT,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            sname TEXT,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            scid TEXT,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            cname TEXT,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            score REAL\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        )\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    \u0026#39;\u0026#39;\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecommit()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003e@app.teardown_appcontext\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eclose_connection\u003c/span\u003e(exception):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    db \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e getattr(g, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;_database\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e db \u003cspan style=\"color:#f92672\"\u003eis\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003enot\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eclose()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e app\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eapp_context():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    init_db()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003e@app.route\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eindex\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e render_template(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;index.html\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Students\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003e@app.route\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/students\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estudents\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    db \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e get_db()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    cur \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexecute(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;SELECT * FROM students ORDER BY id\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    rows \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e cur\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efetchall()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e render_template(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;students.html\u0026#39;\u003c/span\u003e, students\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003erows)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003e@app.route\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/students/add\u0026#39;\u003c/span\u003e, methods\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;GET\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;POST\u0026#39;\u003c/span\u003e])\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eadd_student\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e request\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003emethod \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;POST\u0026#39;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        form \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e request\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eform\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        db \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e get_db()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexecute(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;INSERT INTO students(id,name,gender,birth,address,phone,email) VALUES (?,?,?,?,?,?,?)\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       (form[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;id\u0026#39;\u003c/span\u003e], form[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;name\u0026#39;\u003c/span\u003e], form\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;gender\u0026#39;\u003c/span\u003e,\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e), form\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;birth\u0026#39;\u003c/span\u003e,\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e), form\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;address\u0026#39;\u003c/span\u003e,\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e), form\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;phone\u0026#39;\u003c/span\u003e,\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e), form\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;email\u0026#39;\u003c/span\u003e,\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e)))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecommit()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e sqlite3\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eIntegrityError:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;学号已存在\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e400\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e redirect(url_for(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;students\u0026#39;\u003c/span\u003e))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e render_template(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;student_form.html\u0026#39;\u003c/span\u003e, student\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003e@app.route\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/students/edit/\u0026lt;sid\u0026gt;\u0026#39;\u003c/span\u003e, methods\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;GET\u0026#39;\u003c/span\u003e,\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;POST\u0026#39;\u003c/span\u003e])\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eedit_student\u003c/span\u003e(sid):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    db \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e get_db()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e request\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003emethod \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;POST\u0026#39;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        form \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e request\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eform\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexecute(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;UPDATE students SET id=?,name=?,gender=?,birth=?,address=?,phone=?,email=? WHERE id=?\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                   (form[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;id\u0026#39;\u003c/span\u003e], form[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;name\u0026#39;\u003c/span\u003e], form\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;gender\u0026#39;\u003c/span\u003e,\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e), form\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;birth\u0026#39;\u003c/span\u003e,\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e), form\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;address\u0026#39;\u003c/span\u003e,\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e), form\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;phone\u0026#39;\u003c/span\u003e,\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e), form\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;email\u0026#39;\u003c/span\u003e,\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e), sid))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecommit()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e redirect(url_for(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;students\u0026#39;\u003c/span\u003e))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    cur \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexecute(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;SELECT * FROM students WHERE id=?\u0026#39;\u003c/span\u003e, (sid,))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    student \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e cur\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efetchone()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e render_template(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;student_form.html\u0026#39;\u003c/span\u003e, student\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003estudent)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003e@app.route\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/students/delete/\u0026lt;sid\u0026gt;\u0026#39;\u003c/span\u003e, methods\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;POST\u0026#39;\u003c/span\u003e])\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003edelete_student\u003c/span\u003e(sid):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    db \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e get_db()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexecute(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;DELETE FROM students WHERE id=?\u0026#39;\u003c/span\u003e, (sid,))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexecute(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;DELETE FROM courses WHERE sid=?\u0026#39;\u003c/span\u003e, (sid,))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexecute(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;DELETE FROM scores WHERE ssid=?\u0026#39;\u003c/span\u003e, (sid,))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecommit()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e redirect(url_for(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;students\u0026#39;\u003c/span\u003e))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Courses\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003e@app.route\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/courses\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ecourses\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    db \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e get_db()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    cur \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexecute(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;SELECT * FROM courses ORDER BY sid, cid\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    rows \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e cur\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efetchall()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e render_template(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;courses.html\u0026#39;\u003c/span\u003e, courses\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003erows)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003e@app.route\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/courses/add\u0026#39;\u003c/span\u003e, methods\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;GET\u0026#39;\u003c/span\u003e,\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;POST\u0026#39;\u003c/span\u003e])\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eadd_course\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e request\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003emethod \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;POST\u0026#39;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        f \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e request\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eform\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        db \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e get_db()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexecute(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;INSERT INTO courses(sid,cid,name,credit) VALUES (?,?,?,?)\u0026#39;\u003c/span\u003e, (f[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;sid\u0026#39;\u003c/span\u003e], f[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;cid\u0026#39;\u003c/span\u003e], f[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;name\u0026#39;\u003c/span\u003e], float(f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;credit\u0026#39;\u003c/span\u003e,\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e))))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecommit()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e redirect(url_for(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;courses\u0026#39;\u003c/span\u003e))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e render_template(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;course_form.html\u0026#39;\u003c/span\u003e, course\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003e@app.route\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/courses/delete/\u0026lt;int:id\u0026gt;\u0026#39;\u003c/span\u003e, methods\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;POST\u0026#39;\u003c/span\u003e])\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003edelete_course\u003c/span\u003e(id):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    db \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e get_db()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# delete related scores\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    cur \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexecute(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;SELECT sid,cid,name FROM courses WHERE id=?\u0026#39;\u003c/span\u003e, (id,))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    row \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e cur\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efetchone()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e row:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexecute(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;DELETE FROM scores WHERE scid=? AND ssid=?\u0026#39;\u003c/span\u003e, (row[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;cid\u0026#39;\u003c/span\u003e], row[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;sid\u0026#39;\u003c/span\u003e]))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexecute(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;DELETE FROM courses WHERE id=?\u0026#39;\u003c/span\u003e, (id,))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecommit()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e redirect(url_for(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;courses\u0026#39;\u003c/span\u003e))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Scores\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003e@app.route\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/scores\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003escores\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    db \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e get_db()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    cur \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexecute(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;SELECT * FROM scores ORDER BY ssid\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    rows \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e cur\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efetchall()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e render_template(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;scores.html\u0026#39;\u003c/span\u003e, scores\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003erows)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003e@app.route\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/scores/add\u0026#39;\u003c/span\u003e, methods\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;GET\u0026#39;\u003c/span\u003e,\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;POST\u0026#39;\u003c/span\u003e])\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eadd_score\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e request\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003emethod \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;POST\u0026#39;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        f \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e request\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eform\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        db \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e get_db()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexecute(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;INSERT INTO scores(ssid,sname,scid,cname,score) VALUES (?,?,?,?,?)\u0026#39;\u003c/span\u003e, (f[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;ssid\u0026#39;\u003c/span\u003e], f[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;sname\u0026#39;\u003c/span\u003e], f[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;scid\u0026#39;\u003c/span\u003e], f[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;cname\u0026#39;\u003c/span\u003e], float(f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;score\u0026#39;\u003c/span\u003e,\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e))))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecommit()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e redirect(url_for(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;scores\u0026#39;\u003c/span\u003e))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e render_template(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;score_form.html\u0026#39;\u003c/span\u003e, score\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003e@app.route\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/scores/delete/\u0026lt;int:id\u0026gt;\u0026#39;\u003c/span\u003e, methods\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;POST\u0026#39;\u003c/span\u003e])\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003edelete_score\u003c/span\u003e(id):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    db \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e get_db()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexecute(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;DELETE FROM scores WHERE id=?\u0026#39;\u003c/span\u003e, (id,))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecommit()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e redirect(url_for(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;scores\u0026#39;\u003c/span\u003e))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Stats\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003e@app.route\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/stats\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estats\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    sid \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e request\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eargs\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;sid\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    db \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e get_db()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003enot\u003c/span\u003e sid:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e render_template(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;stats.html\u0026#39;\u003c/span\u003e, sid\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e, stats\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# calculate avg, total credits passed\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    cur \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexecute(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;SELECT score, scid FROM scores WHERE ssid=?\u0026#39;\u003c/span\u003e, (sid,))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    rows \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e cur\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efetchall()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003enot\u003c/span\u003e rows:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e render_template(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;stats.html\u0026#39;\u003c/span\u003e, sid\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003esid, stats\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    total \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0.0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    cnt \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    credits \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0.0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e r \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e rows:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        total \u003cspan style=\"color:#f92672\"\u003e+=\u003c/span\u003e r[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;score\u0026#39;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        cnt \u003cspan style=\"color:#f92672\"\u003e+=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e r[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;score\u0026#39;\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e60\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            c \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexecute(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;SELECT credit FROM courses WHERE sid=? AND cid=?\u0026#39;\u003c/span\u003e, (sid, r[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;scid\u0026#39;\u003c/span\u003e]))\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efetchone()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e c:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                credits \u003cspan style=\"color:#f92672\"\u003e+=\u003c/span\u003e c[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;credit\u0026#39;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    avg \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e total \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e cnt \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e cnt \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e render_template(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;stats.html\u0026#39;\u003c/span\u003e, sid\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003esid, stats\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e{\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;avg\u0026#39;\u003c/span\u003e:avg,\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;credits\u0026#39;\u003c/span\u003e:credits,\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;count\u0026#39;\u003c/span\u003e:cnt})\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Course ranking\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003e@app.route\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/rank/\u0026lt;cid\u0026gt;\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003erank\u003c/span\u003e(cid):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    db \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e get_db()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    cur \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e db\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexecute(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;SELECT sname, score FROM scores WHERE scid=? ORDER BY score DESC\u0026#39;\u003c/span\u003e, (cid,))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    rows \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e cur\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efetchall()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e render_template(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;rank.html\u0026#39;\u003c/span\u003e, cid\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003ecid, rows\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003erows)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e __name__ \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;__main__\u0026#39;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    app\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003erun(host\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;127.0.0.1\u0026#39;\u003c/span\u003e, port\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e5000\u003c/span\u003e, debug\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"是用flask搭的\"\u003e是用flask搭的\u003c/h2\u003e\n\u003cp\u003e代码不详说，就是一个非常简单的项目，.db文件是数据库，用的sqlite，打开试试，在5000端口跑起来\n\u003cimg alt=\"cmd\" loading=\"lazy\" src=\"/images/4.png\"\u003e\u003c/p\u003e","title":"GitHub Copilot CLI 体验"},{"content":"前言 入行漏洞挖掘以来，终于成功提交并通过审核第一个正式漏洞，记录下这次完整挖洞全过程，也算是给自己网络安全学习之路留下一份纪念。\n漏洞基础信息 关联厂商：杭州鼎文国际学校 漏洞编号：QTVA-2026-10612190 漏洞类型：信息泄露 官方评级：中危 漏洞发现过程 日常使用FOFA进行资产测绘搜集站点资产，成功捕获到该校一体化校园管理平台地址： https://pr.dingwenacademy.com/login?redirect=%2Fdashboard\n进入登录页面后常规查看前端源码与静态JS文件，在页面加载的JS资源中： https://pr.dingwenacademy.com/static/js/app.ac0b7b5b.js 这种网页一般都是前后端分离的架构，提升了用户体验不假，但是容易出现api未授权访问 搜索关键字“api”，发现暴露了后端大量业务API接口地址，逐一筛选测试接口可用性。 漏洞核心问题 发现/api/student/selectAllBy, /api/student/selectDocBy, /api/source/getSelect, /api/source/getSelectByUser 暴露大量人员信息，包含姓名，邮箱，用户名 /api/student/selectAllBy这个接口暴露微信wxpass、人员唯一ID 等核心隐私数据。 多组未授权接口组合利用，可批量抓取学校师资、生源、部门配置、业务资源等内部数据，极易造成校内人员信息批量外泄，存在隐私泄露与后续社工攻击风险。\n漏洞详情总结 平台后端整站API接口设计存在严重权限管控缺失，前端JS明文批量泄露接口路径，后台未统一做登录态校验。 公开查询类数据接口全部放任外网无权限人员任意调用，大范围触发信息泄露风险。\n安全修复方案 统一对站点所有 /api/* 路由接口增设全局请求拦截器 强制校验请求头内 Authorization: Bearer 有效登录令牌 未携带合法身份凭证直接拦截拒绝访问，禁止匿名访问业务数据接口 梳理前端JS文件，清理明文暴露的后端敏感API地址，减少接口信息泄露 区分普通访客与登录用户权限，严格划分数据查询访问权限 逐个排查全站业务接口，修复其余同类未授权访问漏洞 厂商反馈 目前该漏洞已正式收录定级，暂未收到厂商正式整改留言与修复回复，等待校方完成安全整改加固。\n挖洞心得 这是我正式提交并审核通过的第一个实战漏洞，也真切体会到信息搜集、JS源码审计、接口遍历测试在日常挖洞中实用性极强。\n本次也发现该校园管理平台存在批量接口权限漏洞，只是优先提交了危害最直观的用户信息泄露接口。后续继续深耕Web漏洞挖掘，从未授权、越权、信息泄露这类基础漏洞入手，稳步积累实战经验。\n","permalink":"https://lewis1766.github.io/posts/20260504/20260504/","summary":"\u003ch2 id=\"前言\"\u003e前言\u003c/h2\u003e\n\u003cp\u003e入行漏洞挖掘以来，终于成功提交并通过审核第一个正式漏洞，记录下这次完整挖洞全过程，也算是给自己网络安全学习之路留下一份纪念。\u003c/p\u003e\n\u003ch2 id=\"漏洞基础信息\"\u003e漏洞基础信息\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e关联厂商：杭州鼎文国际学校\u003c/li\u003e\n\u003cli\u003e漏洞编号：QTVA-2026-10612190\u003c/li\u003e\n\u003cli\u003e漏洞类型：信息泄露\u003c/li\u003e\n\u003cli\u003e官方评级：中危\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"漏洞发现过程\"\u003e漏洞发现过程\u003c/h2\u003e\n\u003cp\u003e日常使用FOFA进行资产测绘搜集站点资产，成功捕获到该校一体化校园管理平台地址：\n\u003ccode\u003ehttps://pr.dingwenacademy.com/login?redirect=%2Fdashboard\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e进入登录页面后常规查看前端源码与静态JS文件，在页面加载的JS资源中：\n\u003ccode\u003ehttps://pr.dingwenacademy.com/static/js/app.ac0b7b5b.js\u003c/code\u003e\n这种网页一般都是前后端分离的架构，提升了用户体验不假，但是容易出现api未授权访问\n搜索关键字“api”，发现暴露了后端大量业务API接口地址，逐一筛选测试接口可用性。\n\u003cimg alt=\"js\" loading=\"lazy\" src=\"/images/js.png\"\u003e\u003c/p\u003e\n\u003ch2 id=\"漏洞核心问题\"\u003e漏洞核心问题\u003c/h2\u003e\n\u003cp\u003e发现/api/student/selectAllBy, /api/student/selectDocBy, /api/source/getSelect, /api/source/getSelectByUser\n暴露大量人员信息，包含姓名，邮箱，用户名\n\u003cimg alt=\"leak\" loading=\"lazy\" src=\"/images/leak.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e/api/student/selectAllBy这个接口暴露微信wxpass、人员唯一ID 等核心隐私数据。\n\u003cimg alt=\"leak2\" loading=\"lazy\" src=\"/images/leak2.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e多组未授权接口组合利用，可批量抓取学校师资、生源、部门配置、业务资源等内部数据，极易造成校内人员信息批量外泄，存在隐私泄露与后续社工攻击风险。\u003c/p\u003e\n\u003ch2 id=\"漏洞详情总结\"\u003e漏洞详情总结\u003c/h2\u003e\n\u003cp\u003e平台后端整站API接口设计存在严重权限管控缺失，前端JS明文批量泄露接口路径，后台未统一做登录态校验。\n公开查询类数据接口全部放任外网无权限人员任意调用，大范围触发信息泄露风险。\u003c/p\u003e\n\u003ch2 id=\"安全修复方案\"\u003e安全修复方案\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e统一对站点所有 \u003ccode\u003e/api/*\u003c/code\u003e 路由接口增设全局请求拦截器\u003c/li\u003e\n\u003cli\u003e强制校验请求头内 \u003ccode\u003eAuthorization: Bearer\u003c/code\u003e 有效登录令牌\u003c/li\u003e\n\u003cli\u003e未携带合法身份凭证直接拦截拒绝访问，禁止匿名访问业务数据接口\u003c/li\u003e\n\u003cli\u003e梳理前端JS文件，清理明文暴露的后端敏感API地址，减少接口信息泄露\u003c/li\u003e\n\u003cli\u003e区分普通访客与登录用户权限，严格划分数据查询访问权限\u003c/li\u003e\n\u003cli\u003e逐个排查全站业务接口，修复其余同类未授权访问漏洞\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"厂商反馈\"\u003e厂商反馈\u003c/h2\u003e\n\u003cp\u003e目前该漏洞已正式收录定级，暂未收到厂商正式整改留言与修复回复，等待校方完成安全整改加固。\u003c/p\u003e\n\u003ch2 id=\"挖洞心得\"\u003e挖洞心得\u003c/h2\u003e\n\u003cp\u003e这是我正式提交并审核通过的第一个实战漏洞，也真切体会到信息搜集、JS源码审计、接口遍历测试在日常挖洞中实用性极强。\u003c/p\u003e\n\u003cp\u003e本次也发现该校园管理平台存在批量接口权限漏洞，只是优先提交了危害最直观的用户信息泄露接口。后续继续深耕Web漏洞挖掘，从未授权、越权、信息泄露这类基础漏洞入手，稳步积累实战经验。\u003c/p\u003e","title":"挖到第一个漏洞：杭州鼎文国际学校API未授权访问"},{"content":"\n很高兴你能来到这里。\n本人目前处在CTF（Capture the Flag，夺旗赛）知识的学习中，研究主要是web方向，萌新一枚，请多指教。\n本人对AI也非常感兴趣，欢迎志同道合的人和我畅所欲言。在这里我将主要分享我的学习过程和实战心得，也可能夹带一些个人生活（说实话我还没想好发什么）。\n我的爱好：音乐/电影/美剧/旅游\n我的微信：Q2FsaWYwcm5pYWRyZWFtaW4=（请解码）\n最后是乔布斯的一句话，我认为终身受用\n\u0026ldquo;Stay Hungry, Stay Foolish.\u0026rdquo;\n","permalink":"https://lewis1766.github.io/about/","summary":"\u003cp\u003e\u003cbr\u003e\n很高兴你能来到这里。\u003c/p\u003e\n\u003cp\u003e本人目前处在CTF（Capture the Flag，夺旗赛）知识的学习中，研究主要是web方向，萌新一枚，请多指教。\u003c/p\u003e\n\u003cp\u003e本人对AI也非常感兴趣，欢迎志同道合的人和我畅所欲言。在这里我将主要分享我的学习过程和实战心得，也可能夹带一些个人生活（说实话我还没想好发什么）。\u003c/p\u003e\n\u003cp\u003e我的爱好：音乐/电影/美剧/旅游\u003c/p\u003e\n\u003cp\u003e我的微信：Q2FsaWYwcm5pYWRyZWFtaW4=（请解码）\u003c/p\u003e\n\u003cp\u003e最后是乔布斯的一句话，我认为终身受用\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u0026ldquo;Stay Hungry, Stay Foolish.\u0026rdquo;\u003c/p\u003e\n\u003c/blockquote\u003e","title":"关于我"},{"content":"欢迎来到我的网站！\n","permalink":"https://lewis1766.github.io/posts/my-first-post/","summary":"\u003cp\u003e欢迎来到我的网站！\u003c/p\u003e","title":"第一篇文章"},{"content":"题目描述 下载附件得到一个加密的 Zip 压缩包，需要密码才能解压。\n解题思路 用 010 Editor 打开 Zip 文件，分析 Zip 文件结构。\nZip 文件结构要点 压缩源文件数据区 50 4B 03 04 头文件标记\n压缩源文件目录区 50 4B 01 02 目录文件头标记\n压缩源文件目录结束标志 50 4B 05 06 目录结束标记\n全局方式位标记 50 4B 03 04 14 00 **后 2 字节** | 数据区加密标记 |\n50 4B 01 02 14 00 **后 2 字节** | 目录区加密标记 |\n判断标准 无加密 00 00 00 00\n伪加密 00 00 09 00（或 01 00）\n真加密 | 09 00 09 00\n本题分析 本题可知是伪加密。\n改掉加密之后，我们得到了两个文件。其中一个是dll。结合题目名这是本题的关键。\n重要的是如何从dll文件中提取密钥。\ndll文件时应用程序的扩展，于是我们就要编写一个程序调用dll\n调用程序需要利用dll里的内置函数，于是我们要想办法拿到dll里的内置函数。\n可以利用vs2022自带的dumpbin来实现。\n输入命令dumpbin.exe /EXPORTS \u0026ldquo;C:\\Users\\asus\\Desktop\\Others\\CCB\\C!C!B!.dll\u0026quot;得到\n内置函数CCB\n写程序调用ccb函数，详见ccb.py\n得到密钥b31915cd51e064bbaf8d6b2790ba108df10c84358f37033cb83609e78e9a3bfb\n顺利得到flag\n","permalink":"https://lewis1766.github.io/posts/20251106/","summary":"\u003ch2 id=\"题目描述\"\u003e题目描述\u003c/h2\u003e\n\u003cp\u003e下载附件得到一个加密的 Zip 压缩包，需要密码才能解压。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"Zip\" loading=\"lazy\" src=\"/images/zip.png\"\u003e\u003c/p\u003e\n\u003ch2 id=\"解题思路\"\u003e解题思路\u003c/h2\u003e\n\u003cp\u003e用 010 Editor 打开 Zip 文件，分析 Zip 文件结构。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"图片2\" loading=\"lazy\" src=\"/images/%E5%9B%BE%E7%89%872.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"图片3\" loading=\"lazy\" src=\"/images/%E5%9B%BE%E7%89%873.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"图片4\" loading=\"lazy\" src=\"/images/%E5%9B%BE%E7%89%874.png\"\u003e\u003c/p\u003e\n\u003ch2 id=\"zip-文件结构要点\"\u003eZip 文件结构要点\u003c/h2\u003e\n\u003cp\u003e压缩源文件数据区  \u003ccode\u003e50 4B 03 04\u003c/code\u003e  头文件标记\u003c/p\u003e\n\u003cp\u003e压缩源文件目录区  \u003ccode\u003e50 4B 01 02\u003c/code\u003e  目录文件头标记\u003c/p\u003e\n\u003cp\u003e压缩源文件目录结束标志 \u003ccode\u003e50 4B 05 06\u003c/code\u003e  目录结束标记\u003c/p\u003e\n\u003ch2 id=\"全局方式位标记\"\u003e全局方式位标记\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003e50 4B 03 04 14 00\u003c/code\u003e **后 2 字节** | 数据区加密标记 |\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e50 4B 01 02 14 00\u003c/code\u003e **后 2 字节** | 目录区加密标记 |\u003c/p\u003e\n\u003ch2 id=\"判断标准\"\u003e判断标准\u003c/h2\u003e\n\u003cp\u003e 无加密  \u003ccode\u003e00 00\u003c/code\u003e  \u003ccode\u003e00 00\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e 伪加密  \u003ccode\u003e00 00\u003c/code\u003e  \u003ccode\u003e09 00\u003c/code\u003e（或 \u003ccode\u003e01 00\u003c/code\u003e）\u003c/p\u003e","title":"Zip伪加密 + DLL调用逆向题解"}]