diff --git a/content/generated/metas.json b/content/generated/metas.json
index 343edb4..9c050e6 100644
--- a/content/generated/metas.json
+++ b/content/generated/metas.json
@@ -1,9 +1,10 @@
{
- "tags": [["open-keyprec", 1], ["技术", 1], ["日记", 2], ["梦", 1], ["心理", 1], ["影评", 1]],
+ "tags": [["ctf", 1], ["open-keyprec", 1], ["技术", 1], ["日记", 2], ["梦", 1], ["心理", 1], ["影评", 1]],
"categories": [["置顶", 1], ["技术", 1], ["日记", 2], ["梦", 1], ["想想想", 1], ["影评", 1]],
- "pins": [9],
+ "pins": [10],
"posts": [
- {"id": 9, "title": "部落格索引", "subtitle": "按分类、标签检索", "category": "置顶", "pinned": 1, "file": "content/posts/Index.md", "tags": [], "date": "2023-11-14T06:46:25.169204", "url_name": "Index", "content": "按分类检索:\n\n\n\n按主题检索:\n\n"},
+ {"id": 10, "title": "部落格索引", "subtitle": "按分类、标签检索", "category": "置顶", "pinned": 1, "file": "content/posts/Index.md", "tags": [], "date": "2023-11-19T04:37:58.117395", "url_name": "Index", "content": "按分类检索:\n\n\n\n按主题检索:\n\n"},
+ {"id": 9, "title": "CyberSci 2023 CTF 网安比赛 Writeup", "subtitle": "你是来打网安还是修 Bug 的?🌚", "tags": ["ctf"], "file": "content/posts/2023-11-18 CyberSci Canada Writeup.md", "date": "2023-11-18T00:00:00", "url_name": "2023-11-18-CyberSci-Canada-Writeup", "content": "我解的五道题都是 Defense 分类的,Defense 规则是修好一个服务器端让攻击方的 PoC 脚本失效就能拿分(这不是我维护服务器日常做的事情吗 ;-;\n\n前三道题「CFP」是一套 PhP + Nginx 写的用来上传作业文档的服务器,后两道题「Swag Shop」是一套 Go GIN 写的购物服务器,全都跑在 docker compose 容器里(然而这两个语言我都没用过呜呜呜)\n\n知道问题的时候修一个 bug 很容易,但是 PoC 机并不会告诉你 bug 在哪里,所以解题的第一步是去查 HTTP log 找到被攻击的方法。\n\n## 前三道题 - Call for Presentations\n\n### Attack 1\n\n前三道题的部署结构我真的太熟悉了,因为我自己的所有服务器都是 Nginx + Docker,直接 `tail -f /var/log/nginx/access.log` 读出所有的请求,整理出一个攻击从开始到结束的所有请求,再 `cat /tmp/nginx-req-body/{n}/` 来读出每个请求内容。看一下请求过程如下:\n\n1. 注册一个帐号\n2. 登录这个帐号\n3. 换一个不同的密码登录这个帐号还登进去了??\n\n啊所以难道给我的这套代码登录甚至没有验证密码的吗 (╯’ – ‘)╯︵ ┻━┻\n\n![[2023-11-18 22-02 2.png|欣赏一下屎山代码]]\n\n看看源代码 lib.php 确实数据库密码验证逻辑写得乱七八糟,数据库直接 string concat,密码甚至没 hash... 好直接让 GPT4 重写了一遍登录和注册这两个函数,然后 PoC 就失效了,拿分拿分 🌚\n\n![[2023-11-18 22-03.png|GPT4 帮我修好了!]]\n\n(不过我至今没弄懂 PhP 要怎样把 log 打到能看到的地方... 打比赛的时候试了几个不同的方法都看不到 log 就算了算了直接把 curl hydev.org/say 写进去了,发到 /say 的东西会转发到我的 Telegram 上hhhh\n\n### Attack 2\n\n第一个好简单。第二个攻击的请求乍一看好像没什么问题,但是仔细看看就会发现 PoC 机注册的帐号的名字和请求提交的 JWT Token 名字不一样然后还莫名过签证验证了... 为什么呢?\n\n![[image_2023-11-18_21-58-35 1.png|第二个攻击的 Log]]\n\n看一眼代码确实,签名居然不是密码学签名,而是直接把请求 JWT 里面的东西 hash 了一遍,验证签名和 hash 相等???🫠 这种客户端能生成的东西还算签名吗?算了交给 GPT4 去改,果然改完就过了。\n\n### Attack 3\n\n第三个攻击感觉是最简单的,看日志内容发现用户上传了五个不同的文件,但是看请求内容那一步就马上发现不对劲了——五个文件中有一个是 PhP 文件,里面是攻击代码,居然直接以 .php 结尾被传进代码旁边的子目录了。泰经典辣,甚至没有用 GPT4,直接给 portal.php 上传文件的代码加一个文件结尾检查就过了(虽然如果是现实中真的遇到这种情况的话肯定要检测文件内容的)\n\n## 后二道题 - Swag Shop\n\n上一道题因为是 PhP,改完代码直接 `compose up --build -d` 重新跑容器也只要几秒。但是这两道题是用 Go 写的,而 Go 是需要编译的语言,所以发现的第一件事情是 `docker build` 居然要两分钟 (╯’ – ‘)╯︵ ┻━┻\n\n磨刀不误砍柴工,先把本地 Go 环境和依赖装上,把 SSL cert 挪到该放的地方,带缓存的编译重跑就只需要不到一秒了。\n\n![[2023-11-18 22-52.png]]\n\n## Attack 1\n\n第一道题非常非常简单,跑起来之后看 HTTP 访问日志马上就看到了一条野生 SQL 语句 👀 原来要修的是 SQL 注入。看看代码,main 里面定义了这个 `/shop/items/:item` 节点的函数是 DescribeItem(),把整个函数拷给 GPT4 重写拿分()\n\n![[2023-11-18 22-56.png|GPT4 不知道今天帮了我多少忙]]\n\n### Attack 2\n\n第二道题我觉得是这五道题里面最难的,因为攻击方法并不明显。整个日志看起来都非常正常,我为了让日志看起来更整洁还隐藏了签名验证的部分,日志里实现的操作都是用户正常使用会用到的。看了超级超级久还没发现问题,但是把签名打出来发现了不同请求的签名长度不一样,所以猜猜可能是签名验证的问题就去检查了一下签名验证的代码,然后发现了这堆鬼东西:\n\n![[2023-11-18 23-01.png|他们自己实现了一个 ASN 验证,后面是五百行的我都看不懂的纯正密码学]]\n\n不懂就不要随便自己实现加密算法啊啊啊 (╯’ – ‘)╯︵ ┻━┻\n\n密码学真的有太多我看不懂的理论数学,所以我也看不出他们的实现有没有 Bug,但是总之先试试让 GPT4 用标准库重写一遍 VerifyASN 吧... 重写完重跑一遍居然就真的就过了 🌚\n\n## 总结\n\n总之五道 Defense 题全都解出来啦,然后看时间不够快赶不上 One Among Us 的手工活动就赶快走了。感觉很开心!这是我参加的第一个有 Defense 题型的 CTF,感觉是和 Web 题完全反过来的题型。Defense 少见可能是因为这种题比较难封沙盒吧,不过第一次知道原来像我这样的平凡全栈技能也能在 CTF 上起到作用。\n\n原本登记了这次比赛只是因为 UofTCTF 他们组缺人,去之前还觉得自己一年没打过 CTF 了说不定一道题都做不出来呢,结果发现并没有全都忘掉也很开心。居然比同组的那些 UofTCTF 活跃队员分还高一些(不过也是因为 Defense 题更简单啦)总之虽然已经退坑了但是偶尔打打 CTF 还是很好玩的!"},
{"id": 8, "title": "开源打击琴!第二天", "subtitle": "绝赞设计中 ⭐️", "tags": ["open-keyprec"], "file": "content/posts/2023-03-15 OKP Day 2.md", "date": "2023-03-15T00:00:00", "url_name": "2023-03-15-OKP-Day-2", "content": "#open-keyprec 开源打击琴的第二天\n\n今天在设计琴键布局呢,决定了做五个八度的马林巴琴布局,从 C2 到 C7 一共 61 个琴键。为了不用手动复制 60 遍写了脚本自动生成琴键!FreeCAD 可以用 py 写脚本真是省了不知道多少时间哇(虽然学 API 可能用了更久hhh)。原本是按照 78-194mm 等比例分布琴键长度,但是觉得看起来太规整了,改成用三点的方式找到了一个抛物曲线计算长度,效果好棒!\n\n
生成的 61 个琴键模型,高度是条抛物线\n\n然后算下来打印时间大概要 91.5h,如果 24h 无间断打印的话要 3.8 天... 今天发现 Cura 的一个实验性功能可以让多个模型在同一个平台上顺序打印,很灵车但是好想试试,如果可以的话睡觉的时候也能让打印机工作了(打印机加油!\n\n真正打印的时候才发现这个打印机有好多问题,果然不应该相信半价全新... 首先是自动调平不工作,而且因为这款 \"Smart\" 打印机的受众是富家小孩,设计师去掉了需要耐心的手动调平旋钮。研究了一下发现是固件逻辑每次回零都会把调平 Mesh 关掉,也就是说自动调平完全没有用到。解决方案就是在 GCode 开始段回零之后加一句 `M420 S1` 重新启用调平... 创想啊你完全不测试你的代码么 (╯’ – ‘)╯︵ ┻━┻\n\n
自动调平 Mesh 可视化(好歪!)\n\n然后看到印床底下有一颗孤零零的螺丝 ;-;;; 估计要拆下整个 y 轴才能取出来,好麻烦啊,不过有一点点小风险也没关系?\n\n
卡在床下面的螺丝\n\n今天下午和聊聊去拼装模型爱好者的店买了喷漆罐,打算喷成 V7530BCF 那样的金属黑色。给 PLA 喷漆也很讲究呢,需要先喷 Primer,喷漆,再喷保护层,还要一个通风柜... 原本想在厕所开上换气喷,但是看到成分里含有机溶剂,只能等天暖在外面喷了呜呜。\n\n晚上复用器芯片到了,因为 D1 ESP32 控制板只有六个模拟输入,用来接 61 个琴键肯定不够,所以就改成了用四个 16 输入的复用器去读四个输入啦。去焊了四片芯片上的 96 个引脚。开始焊之前觉得 96 个引脚好多好可怕,但是熟练之后发现其实可以很快的,焊最后一个芯片的 24 根引脚只花了两分钟,离成为一个合格的工程师更近了!零件还缺 60 个 1MΩ 电阻和 60 个二极管和一些转接头就收集齐了!"},
{"id": 7, "title": "Snowy World", "subtitle": "一个 telnet 协议的 ASCII 动画", "file": "content/posts/2023-03-09 Telnet Game.md", "tags": [], "date": "2023-03-09T00:00:00", "url_name": "2023-03-09-Telnet-Game", "content": "
\n\n写了一个 telnet 协议的 ascii 动画!(花了一整天又没什么用,但是好好玩ww\n\n用指令 `telnet hydev.org` 连接哦。记得用一个好用一点的终端,比如 kitty / iTerm2\n\n\n
\n 用 cool-retro-term 登录 ptt.cc 论坛的 telnet\n\n\n昨天和鱼塔闲聊,从某紫底绿字网页聊到复古终端又聊到 telnet 论坛。这是我第一次见到 telnet 协议的论坛哇,连进 ptt 和水木论坛转了转,完全被五颜六色的字符画和各种小彩蛋吸引住了 qwq 决定我也写一个简单 ascii 动画放进我的小小角落...\n\n...然后就这样花掉了一整天 🌚\n\n刚开始用 python 两个小时写好了 telnet 监听、雪花、字符画、移动,简简单单地一层一层字符打上去,但是这样会让图层闪来闪去。然后改成了存 framebuffer 2d 矩阵,先把不同图层叠到缓存里再统一渲成一层命令行能懂的控制符,但是 py 矩阵遍历真的好慢好慢,用上 numpy 也依然非常慢,渲染一帧要 42ms。好像这个问题并没有解... 用 numba JIT 把遍历函数编译成二进制也只优化到了 16ms。无奈啊,可能方便的语言就是跑不快,借这个契机开始学 rust 了!\n\n\n
\n Python 渲染日志,一圈需要 45ms\n\n\nrust 确实好不方便,因为不能有全局变量,用 struct + impl 强行模拟了 OOP 的对象,把全局全都写在 struct Main 里面 🌚。但是有时候又不能当作对象,遇到了比如可变指针借用的问题,把常量和变量分开存解决了,还有生命周期什么的,总之是好多写完了也没太学懂的概念。昨天折腾到凌晨五点 rua 完了,没想到同一个 2d 数组遍历只是用 rust 重写就只占用 0.12ms 了哇,350 倍啊 350 倍!\n(╯’ – ‘)╯︵ ┻━┻\n\n~~就此立 flag,以后新坑绝对不会再碰 python 了~~。明明同样是 O(n * m) 的代码居然会差这么多... 现实中优化算法常量也很重要呢\n\n\n
\n Rust 可变 &self 指针借用的报错\n\n\n接下来想要把写完的命令行程序接到 telnet 协议上,可是 rust 没有做好的 telnet 服务器库,怎么办呢?先是试着用 tokio 手搓一个协议库,发现没办法读未缓存的原始键盘事件,去 SO 问了。之后尝试调用 c 的 libtelnet 库,跑起来到处报 SIGSEGV 呜呜呜。最后还是直接用 py 的代码开子进程做了一个中继,收到客户端的输入转发给 rust,收到 rust 的输出再转发给客户端... 意外地效果还不错。\n\n写完装进 docker 里面部署上去啦。花了一整天,但是学到了 rust,动画的效果也不错,总之很开心。写着写着有点想用这个框架写一个小游戏... 但是不太会游戏设计呢,再想想。"},
{"id": 6, "title": "用校园网搭建服务器!", "subtitle": "在宿舍折腾网络的一篇记录w", "tags": ["技术"], "category": "技术", "file": "content/posts/2022-01-30 Router.md", "date": "2022-01-30T00:00:00", "url_name": "2022-01-30-Router", "content": "欢迎欢迎!我是 UofT 的大一新生,这是我在宿舍折腾网络的一篇记录w\n\n## 1. 搭建 FRP 实现内网穿透\n \n\n\n## 2. OpenWRT 中继学校 WPA-EAP 网络实现远程重启\n\n搭建好内网穿透之后又遇到了新的问题——因为台式机服务器装的黑苹果配置不是很稳定,它有时候会整个屏幕绿掉,必须强制重启才行,应该是 kernel panic 吧。我不在宿舍的时候回宿舍重启又太麻烦了,如果可以远程重启...\n\n想起来之前摸鱼的时候看到向日葵有做过远程重启的设备,所以就去查了下,结果发现就只是一个智能插座,在主板上配置好插电自动开机就好啦。但是这又有一个问题——宿舍里所有的网络,无论是 UofT Wifi 还是 eduroam 还是有线以太网,都需要 WPA/WPA2/WPA3-Enterprise EAP PEAP MSCHAPv2 用户名+密码验证... 可是智能插座只支持简单的 WPA-PSK 密码验证。所以就需要一个可以连上外网、又可以开 WPA-PSK WiFi 的无线路由器了。\n\n刚开始,我想过几个不同的方案:\n\n### a. 用手机连 Wifi 开热点(失败)\n\n之前无意间发现了我的 Mi Mix2S (Android 11 EvolutionX) 可以边连 Wifi 边开热点,不知道是怎样实现的。所以我想,如果用旧的华为 Mate8 这样一边连着学校的 PEAP 一边开热点就可以了。但是开机之后,我发现 Mate8 的原生系统 Android 8 EMUI 8.0 并不支持同时连 Wifi 开热点。我听说用 VPN Hotspot 可以实现无线中继,下载试了下却发现没有 Root 就不能改 SSID 和密码,每次开的 SSID 和密码都是随机的。所以花了超级多精力解锁 BootLoader、刷 Magisk、然后发现 Root 之后也不能改无线中继的 SSID 和密码... 改完之后重开中继的 SSID 还是 DIRECT-{随机}-HUAWEI, 密码还是八位随机字符。不过还是试了下用智能插座连这个无限中继,只能赌无线中继不会重启、不会关机、不会被电源管理杀掉... \n\n结果是,在台式死机之前智能插座就先下线了,回宿舍看了一眼发现手机不知道为什么重启进 Recovery 了。失败失败(\n\n### b. 用手机连数据卡开热点(太贵了)\n\n然后想到如果可以再买一张手机卡只用来开热点就解决了嘛,但是发现这边不像国内那样 ¥10/mo 就能买一张卡,这边最便宜的流量卡要 CA$15/mo,换算出来要 ¥75/mo 了,够买一个路由器了(\n\n### c. 用路由器中继\n\n然后就是现在的解决方案啦,用路由器中继学校的 PEAP。首先要做的是买一个路由器,可是这边新的路由器也真的很贵,亚马逊上最便宜的 TP-Link AC750 要 $35 = ¥175... 所以去二手市场逛了逛,很幸运的看到了附近有人 $10 出路由器,一个 Netis WF2780 和一个小米路由 R4。\n\n首先试了 WF2780,但是它好像没接好 WAN 就完全不能用的样子,SYS 灯一直在闪,网线连上电脑也没办法获取到 IP,手动分配 IP 到 192.168.1.2 也进不去管理页面。可能是坏了吧,也可能这个路由器本来就是这样?不懂,下一个(\n\n然后试了 R4,可是用小米官方的固件,无限桥接模式并不能连上 PEAP 验证的 UofT Wifi 或者 eduroam,有线桥接模式把 WAN 口接上也提示识别错误。所以只能试试 OpenWRT 啦。\n\n### 1. 给小米路由 R4 刷 OpenWRT\n\n这里我跟了 https://www.wyr.me/post/619 这个教程,很轻松地就刷好了!\n\n在电脑上要做的事情:\n\n1. 网线连上路由器,登录管理后台(我是 http://192.168.31.1)\n2. 复制管理后台登录之后 URL 里面的 stok 参数\n3. 执行以下指令,输入路由器的 IP 和刚才复制的 stok\n\n```sh\ngit clone https://github.com/acecilia/OpenWRTInvasion\ncd OpenWRTInvasion\npip3 install -r requirements.txt\npython3 remote_command_execution_vulnerability.py\n```\n\n然后就有 ssh 啦!接下来用了这个固件:https://github.com/ioiotor/mir4-ss,下载 [openwrt-ramips-mt7621-xiaomi_mir4-squashfs-kernel1.bin](https://github.com/ioiotor/mir4-ss/releases/download/V19.07.4/openwrt-ramips-mt7621-xiaomi_mir4-squashfs-kernel1.bin) 和 [openwrt-ramips-mt7621-xiaomi_mir4-squashfs-rootfs0.bin](https://github.com/ioiotor/mir4-ss/releases/download/V19.07.4/openwrt-ramips-mt7621-xiaomi_mir4-squashfs-rootfs0.bin)\n\n4. 在电脑上执行以下指令:\n\n```sh\nmkdir temp\ncd temp\nwget https://github.com/ioiotor/mir4-ss/releases/download/V19.07.4/openwrt-ramips-mt7621-xiaomi_mir4-squashfs-kernel1.bin\nwget https://github.com/ioiotor/mir4-ss/releases/download/V19.07.4/openwrt-ramips-mt7621-xiaomi_mir4-squashfs-rootfs0.bin\npython3 -m http.server\n```\n\n5. 登录进 SSH Shell 之后在路由器上执行指令:\n\n```sh\ncd /tmp\nwget http://{电脑 IP 地址}/openwrt-ramips-mt7621-xiaomi_mir4-squashfs-kernel1.bin\nwget http://{电脑 IP 地址}/openwrt-ramips-mt7621-xiaomi_mir4-squashfs-rootfs0.bin\nmtd write openwrt-ramips-mt7621-xiaomi_mir4-squashfs-kernel1.bin kernel1\nmtd write openwrt-ramips-mt7621-xiaomi_mir4-squashfs-rootfs0.bin rootfs0\nnvram set flag_try_sys1_failed=1\nnvram commit\nreboot\n```\n\n然后就好啦,重启之后就是 OpenWRT 了(虽然默认没有开 WLAN,所以只能网线连到路由器)\n\n### 2. OpenWRT 连接到 PEAP 网络\n\n登录上管理页面,改完管理密码之后,我试了直接把 wlan0 改成 client mode 去连学校的网,但是发现这里也只支持密码验证的 WPA-PSK 而不支持用户名+密码的 WPA-EAP。然后查了一下发现只要把预装的 wpad-basic 换成完整的 wpa-cli + wpa-supplicant + hostapd 就可以了。但是还有一个问题就是我的路由器现在没有网,所以不能在线安装软件包。我的解决方案是用电脑先连上学校的 WIFI,再把电脑的网线连到路由器的 LAN 口上,然后在电脑上开桥接模式路由器就有网了!\n\n之后,ssh 进路由器,执行以下指令:\n\n```sh\nopkg update\nopkg remove wpad-basic\nopkg install wpa-cli wpa-supplicant hostapd nano\nreboot\n```\n\n等重启好之后,管理页面里面 Wireless Security 那一栏的验证方式里面就有 WPA2-EAP 了!接下来把学校的验证信息填进去,然后保存就连上啦!UofT 的配置如下:\n\n```txt\nEncryption : WPA2-EAP (strong security)\nCipher : auto\nEAP-Method : PEAP\n...\nCertificate Constraaint (Domain) : radius.wireless.utoronto.ca\n...\nAuthentication : EAP-MSCHAPv2\nIdentity : 你的 UTORid\nPassword : 你的 UTORid 密码\n```\n\n接下来把 WIFI 配置一下,让智能插座连上这个 WIFI 就好了!"},