RiK's Blog - 旧作
type: channel
link: https://pwnerik.cn/category/legacy/
description: The good old days...
items: Hackergame 2023 Writeup
items: C 动态内存扩展
items: 一些早期作品

Hackergame 2023 Writeup
type: item
date: 2023-11-05T04:02:00+00:00
description: 作者: RiK (3050/223)第一次参加 HG，明显感受到出题质量很高，做起来整体感觉很爽！（后面好难，一个都不会呃呃）取部分解出题目写一篇 WP。新人实力有限，有误望指正。1. 赛博井字棋打开题目玩了几局后发现不可能以正常方式解题。而后尝试伪造 POST 请求，发现比较复杂（作为备选方案）。打开浏览器开发人员工具 (F12) 注意到以下代码：// static/script.js async function setMove(x, y) { if (board\[x\]\[y\] != 0) { return; } if (frozen) { return; } let url = window.location.href; // 获取当前 URL let data = { x: x, y: y }; // 设置要发送的数据 return fetch(url, { method: "POST", // 设置方法为 POST headers: { "Content-Type": "application/json", // 设置内容类型为 JSON }, body: JSON.stringify(data), // 将数据转换为 JSON 格式 }).catch(errorHandler); }于是通过 Console 重新定义（覆盖）该函数并将前两个 if 语句删除，Restart，强制占用对手棋子位置，获胜得到 flag：flag{I_can_eat_your_pieces_53f95d1546}2. 组委会模拟器打开题目尝试手动撤回，不出意料消息发送过快，人工撤回不可能，于是编写 Python脚本自动撤回。（其实用 JS 直接监听更方便）import requests, re, json, asyncio async def send_delete(delay: float, id: int): await asyncio.sleep(delay) res = requests.post( "http://202.38.93.111:10021/api/deleteMessage", json={"id": id}, cookies={ "session": "[token]" }, headers={"Content-Type": "application/json"}, ) print(res.text) res = requests.post( "http://202.38.93.111:10021/api/getMessages", cookies={ "session": "[token]" }, headers={"Content-Type": "application/json"}, ) data = json.loads(res.text) illegal_req = [] id = 0 for msg in data["messages"]: if re.findall(r"hack\[[a-z]+\]", msg["text"]): illegal_req.append(send_delete(msg["delay"], id)) id += 1 await asyncio.gather(\*illegal_req) res = requests.post( "http://202.38.93.111:10021/api/getflag", cookies={ "session": "[token]" }, headers={"Content-Type": "application/json"}, ) print(res.text)由于单纯地 sleep() 后 requests.get() 的执行时间会因网络延时不断偏移预定值，可通过测量请求时间相减抵消，此处选用 asyncio 库并发解决。最后得到 flag：flag{Web_pr0gra_mm1ng_36a712733a_15fun}3. 虫由于以前玩过业余无限电，一看到这题当场乐了，使用安卓手机软件 Robot36，外录音频后自动解码 SSTV 图像结果如下：于是得到 flag：flag{SSssTV_y0u_W4NNa_HaV3_4_trY}4. Git? Git!一开始使用 git log 找了个遍发现根本没有包含 flag 的 commit，后来索性对所有文件暴力搜索关键词 "flag" 没有结果，后来意识到是它可能是以二进制形式存储。本想放弃，网上搜索发现 git reflog 可以显示存储在本地的更详细的操作历史：ea49f0c (HEAD -\> main) HEAD@{0}: commit: Trim trailing s…

C 动态内存扩展
type: item
date: 2023-09-04T12:47:00+00:00
description: 前言今天看 cppreference.com 的时候偶然发现这么个有意思的 C 语言特性（扩展），由于相应的中文资料很少（英文资料也不多），所以决定写这篇文章分享一下。本文只挑选重要的函数进行介绍。该扩展为C语言标准中可选实现内容，只有部分编译器能实现（POSIX/Linux）。本文所有内容测试环境如下：archlinux x86_64 (kernel: 6.4.12-zen1-1-zen)gcc 12.2.1 (20230801) (POSIX)glibc 2.38-3函数定义以下定义均经过修改，方便阅读。分配动态内存FILE *open_memstream (char **bufloc, size_t *sizeloc);分配动态内存到 bufloc，其大小为 sizeloc 指向的数字。返回的文件指针可用于写入数据。写入动态内存size_t getline (char **lineptr, size_t *n, FILE *stream); // 1 size_t getdelim (char **lineptr, size_t *n, int delimiter, FILE *stream); // 2传入下列参数调用函数 3。读取 stream 中内容直至读取到 delimiter，将读取数据存入 lineptr 指向的内存块并自动扩充该内存块大小，将读取结束后动态内存大小存入 n 指向的数字。getdelim(lineptr, n, '\n', stream); // getline分配并写入动态内存int asprintf (char **ptr, const char *fmt, ...);以类似于 printf 的方式将格式化内容输出至 ptr 指向的内存块并自动扩充该内存块大小。另外这个扩展还给 scanf 新增了一个格式化参数修饰符 m，可以读取任意长度的字符串（%ms）。（这个还真有用）示例代码// #define _GNU_SOURCE // 使 IDE 不要报错 #include <stdio.h> #include <stdlib.h> #include <time.h> // time() int main(void) { char *buffer = NULL; size_t size = 0; FILE *stream; size_t read; read = getline(&buffer, &size, stdin); printf("buffer 中的内容：\n%s大小：%zu\n字符数：%zu\n", buffer, size, read); free(buffer); stream = open_memstream(&buffer, &size); if (stream == NULL) { puts("无法打开动态内存数据流。"); exit(EXIT_FAILURE); } srand((unsigned int)time(NULL)); for (int i = 0; i < rand() % 100; i++) { fprintf(stream, "%d ", i); } fflush(stream); puts("在一个字符串中的随机个（0～99）数字："); puts(buffer); free(buffer); asprintf(&buffer, "一个随机数：%d", rand()); puts(buffer); free(buffer); return 0; }原理分析直接看 glibc 源码。其实就是初始分配 120 字节，当超过上限时 realloc 翻倍。// glibc/libio/iogetdelim.c __getdelim // ... if (*lineptr == NULL || *n == 0) { *n = 120; *lineptr = (char *) malloc (*n); // 初始内存大小 120 if (*lineptr == NULL) { fseterr_unlocked (fp); result = -1; goto unlock_return; } } // ... /* Make enough space for len+1 (for final NUL) bytes. */ // 考虑字符串末尾 '\0' needed = cur_len + len + 1; if (needed > *n) { char *new_lineptr; if (needed < 2 * *n) needed = 2 * *n; /* Be generous. */ new_lineptr = (char *) realloc (*li…

一些早期作品
type: item
date: 2023-06-08T16:00:00+00:00
description: 本文发布于 2026 年 3 月。想要搭建一个博客的想法从高中就有了，不过一直没有足够的动力完成这件事。直到后来在大学接触到 CTF 才重拾搭建个人网站的兴趣。在高中那段时间的一些简陋的小玩意就全都放在这里啦。（留作回忆）Minecraft Bukkit 声明式命令框架高中时（2021）和一个同学琢磨着开一个 Minecraft 插件服务器骗钱，在那段时间写了很多服务器插件。（记得当时经常需要逆向分析一些付费的闭源插件。）最终整个项目（PolarLand）因长期没有进展一直在造各种重复的轮子而永久搁置。如果那时候有现在这样的 Agentic Coding 的话大概不会放弃吧。其中一个插件是将原本重复繁琐的处理玩家命令的功能写成一个声明式框架。说实话，里面有一些想法直到今天的我看来也是十分 hack (nerd) 的。比如为了将玩家传入的 x y z 坐标自动实例化为 Location 于是在运行时编译一个 Java 类来实现；还有一个 Array 转数组的魔法操作 parsedArgs.add(parsedArray.toArray((Object[]) Array.newInstance(type.getComponentType(), 0)))；以及后面的 tab 键补全嵌套的命令参数（参数的类型是命令）功能。核心源码：/* * CommandBinder.java - A part of a declarative Bukkit command framework. * Copyright (C) 2022 pwnerik.cn * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ package net.polarmc.bukkitplugin.poleax.kit.command.parser; import com.itranswarp.compiler.JavaStringCompiler; import net.polarmc.bukkitplugin.poleax.kit.command.CommandModel; import net.polarmc.bukkitplugin.poleax.kit.command.NoSuchCommandException; import net.polarmc.bukkitplugin.poleax.kit.command.annotation.Optional; import net.polarmc.bukkitplugin.poleax.kit.command.annotation.*; import net.polarmc.bukkitplugin.poleax.kit.command.util.Util; import net.polarmc.bukkitplugin.poleax.utils.MessageUtil; import org.apache.commons.lang.StringUtils; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.World; im…