Mion's Blog - 2021年9月
type: channel
link: https://jlpt.qwq.cc/2021/09/
description: 一切是否安好？
items: 在宝塔下使用Umami自建站点访问统计系统
items: 使用代理为docker-compose加速
items: 关于FTP协议与FTP安全的浅谈
items: [CTF]关于PHP5下foreach运行模式的讨论
items: 使用ESP8266+RC522+MG995低成本改造宿舍门禁支持NFC刷卡与远程控制

在宝塔下使用Umami自建站点访问统计系统
type: item
date: 2021-09-18T14:48:00+08:00
description: 序 一直以来就有想要给无人问津的博客添加一个访问统计。在尝试过百度统计、Google Analytics后发现总是会被Adblock Plus拦截，且本身的需要仅仅是需要一个简单的访问统计和来源分析，用不着太复杂的功能，于是准备自建站点访问统计。 Umami Umami是一个简介且易于使用的自建网站访问分析系统，基于Node.js构建且支持PostgreSQL与MySQL数据库。实测能够很好的解决被Adblock插件屏蔽的问题。 官网：https://umami.is/ 文档：https://umami.is/docs/ GitHub：https://github.com/mikecao/umami 安装与配置 安装环境 宝塔 7 Nginx 1.21 MySQL 5.6 Docker-compose 数据库配置 首先从https://github.com/mikecao/umami/blob/master/sql/schema.mysql.sql获取SQL文件，在宝塔中新建数据库，在这里选择utf8mb4字符集。 然后通过宝塔导入SQL文件。 Docker与docker-compose安装 在宝塔【软件管理】 - 【运行环境】中安装 Docker管理器自动配置好Docker环境，之后在终端中执行以下指令获取最新版docker-compose: # curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose # chmod +x /usr/local/bin/docker-compose # ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose # docker-compose --version 如果最后成功输出版本信息则代表成功安装。与此同时如果正确配置了pip，也可以执行以下指令进行安装： # pip install docker-compose docker-compose.yml 由于宝塔环境已经带有MySQL环境，在这里我们仅需要使用Umami的Docker镜像即可，在这里提供一份我魔改后的docker-compose.yml文件，将以下的数据库信息修改后保存至本地即可，我选择保存至/home/umami目录中。 version: '3' services: umami: image: ghcr.io/mikecao/umami:mysql-latest network_mode: "host" environment: DATABASE_URL: mysql://[用户名]:[密码]@localhost:3306/[数据库名] DATABASE_TYPE: mysql HASH_SALT: [随便编写一段字符串] restart: always 接下来使用docker-compose构建容器，若下载速度较慢，请参考本文章：使用代理为docker-compose加速 # cd /home/umami # docker-compose up -d 至此容器构建完成，Umiami运行在http://127.0.0.1:3000下。 使用Nginx进行反向代理与跨域配置 在宝塔中新建网站，配置SSL后选择反向代理，配置如下： 之后在【配置文件】第7行后添加以下内容来配置跨域： ... root /www/wwwroot/xxx; add_header Access-Control-Allow-Origin * always; add_header Access-Control-Allow-Methods GET,POST,DELETE; add_header Access-Control-Allow-Header Content-Type,*; #SSL-START SSL相关配置，请勿删除或修改下一行带注释的404规则 ... 若使用CDN服务，也需要在CDN处配置跨域。 添加站点与使用 访问刚才配置好的站点，使用默认账户名admin与密码umami进行登录。（题外话：写到这里被老师点起来回答CRC的过程了，记录一下，吓死去...） 选择【Settings】-【Websites】-【Add website】，填写网站名称与域名后，将获得的代码添加至网站 标签之前。如果以上步骤未出现差错的话，刷新Umami即可获得访问记录。（右上角球形图标可以切换语言） 结 类似于Umami这类网站访问统计系统还有很多，但它简单与轻量的特性非常符合我的需…

使用代理为docker-compose加速
type: item
date: 2021-09-11T11:13:55+08:00
description: 序 在生产环境中经常会使用docker-compose来部署项目，由于众所周知的原因，在国内网络环境中下载部分托管在第三方平台的docker镜像会有下载缓慢的问题。下面将介绍快速使用代理为docker-compose加速。 .env 文件 在Docker文档中提到Docker-compose支持加载当前工作目录下的.env文件，原文如下： Compose supports declaring default environment variables in an environment file named .env placed in the project directory. Docker Compose versions earlier than 1.28, load the .env file from the current working directory, where the command is executed, or from the project directory if this is explicitly set with the --project-directory option. This inconsistency has been addressed starting with +v1.28 by limiting the default .env file path to the project directory. You can use the --env-file commandline option to override the default .env and specify the path to a custom environment file. 综上，我们在与docker-compose.yml同目录下创建.env文件： HTTP_PROXY=proxy_url:port //例 HTTP_PROXY=127.0.0.1:1080 HTTPS_PROXY=proxy_url:port FTP_PROXY=proxy_url:port NO_PROXY=no_proxy_url 然后再运行docker-compose up即可。

关于FTP协议与FTP安全的浅谈
type: item
date: 2021-09-10T20:49:00+08:00
description: 序 这里是计算机网络课程的第一个作业，仅此记录一下并提出一些自己的思考。 FTP协议初步分析 测试环境 FTP Server 10.60.8.254 : 21/20 vsFTPD 3.0.3 username : mion password : password FTP Client 10.27.157.176 FTP 0.17-34.1.1 分析工具 Wireshark 3.4.4 Fillter : ip.addr == 10.60.8.254 and ftp and ftp-data 注：由于仅探究FTP的行为，在此忽略TCP相关报文。 在FTP主动模式下传输文件 用户行为 FTP客户端使用账户并在主动模式下连接FTP服务器 FTP客户端上传文件"file" FTP客户端断开连接 数据包分析 以下数据包为从Wireshark导出后经过整理产生的表格。 源 目标 报文 说明 10.60.8.254:21 10.27.157.176:59220 Response: 220 (vsFTPd 3.0.3) 经过TCP三次握手后，FTP服务器响应220代表准备连接 10.27.157.176:59220 10.60.8.254:21 Request: USER mion 发起 USER 指令 10.60.8.254:21 10.27.157.176:59220 Response: 331 Please specify the password. 响应331 准备校验密码 10.27.157.176:59220 10.60.8.254:21 Request: PASS password 发起PASS指令 10.60.8.254:21 10.27.157.176:59220 Response: 230 Login successful. 响应230 登录成功 10.27.157.176:59220 10.60.8.254:21 Request: SYST 发起 SYST 指令，获取FTP服务器系统类型 10.60.8.254:21 10.27.157.176:59220 Response: 215 UNIX Type: L8 响应 系统类型为UNIX 10.27.157.176:59220 10.60.8.254:21 Request: TYPE I 切换传输模式为 Binary模式 10.60.8.254:21 10.27.157.176:59220 Response: 200 Switching to Binary mode. 响应 200 成功 10.27.157.176:59220 10.60.8.254:21 Request: PORT 10,27,157,176,151,199 发起PORT指令，建立主动模式文件传输连接，客户端监听38855端口 10.60.8.254:21 10.27.157.176:59220 Response: 200 PORT command successful. Consider using PASV. 响应 200 并推荐采用被动模式 10.27.157.176:59220 10.60.8.254:21 Request: STOR file 发起 STOR 命令 要求存储文件为 file 10.60.8.254:21 10.27.157.176:59220 Response: 150 Ok to send data. 响应150 准备接收文件 10.27.157.176:38855 10.60.8.254:20 FTP Data: 5 bytes (PORT) (STOR file) 文件传输包，通过主动模式传输 10.60.8.254:21 10.27.157.176:59220 Response: 226 Transfer complete. 响应226 文件传输完成 10.27.157.176:59220 10.60.8.254:21 Request: QUIT 发起 QUIT 指令 10.60.8.254:21 10.27.157.176:59220 Response: 221 Goodbye. 响应 221 结束连接 总结分析 从以上信息我们可以得出FTP 主动模式工作方式如下： FTP Client 发起 PORT 命令，携带参数为监听端口。其中参数前四位为IP地址，后两位为端口号，计算方法： $$ 端口号=(第一位\times256)+第二位 $$ 其中，开启的端口号为某一随机端口，而非网络上流传的N+1端口。根据RFC 959，此观点也得到了证实: 3.2. ESTABLISHING DATA CONNECTIONS The mechanics of transferring…

[CTF]关于PHP5下foreach运行模式的讨论
type: item
date: 2021-09-08T20:09:00+08:00
description: 序 这是一道群里大佬出的红包题，由于我是非预期解题，这里给出一下出题人Write Up和自己的一些思考。 原题 PHP Ver : 5.3.29 <?php ini_set("display_errors", "On"); error_reporting(E_ALL | E_STRICT); $flag=0; $array = array('MXPUMXPUMXPUMXPU' => 1, 'NWPUNWPUNWPUNWPU' => 2, 'MXOvMXOvMXOvMXOv' => 3,'NWOvNWOvNWOvNWOv' => 'phpinfo();'); $ref = &$array; if (isset($_GET['data_key']) && isset($_GET['data_value'])) { $data_key = $_GET['data_key']; $data_value = $_GET['data_value']; if (preg_match('/MX|PU|NW|Ov/i', $data_key)) { die('nonono'); } else{ foreach ($array as $key => $value) { if ($flag===0){ unset($array['NWPUNWPUNWPUNWPU']); $array[$data_key] = $data_value; $flag=1; } if($key=='NWOvNWOvNWOvNWOv'){ call_user_func('assert',$value); die(''); } if (current($array) === false) { call_user_func('assert',$value); } } } } else{ highlight_file(__FILE__); } 题解 注意到是php版本5，用了foreach方法，注意到php5中数组和php7存在区别，具体可见： https://stackoverflow.com/questions/10057671/how-does-php-foreach-actually-work/14854568#14854568 https://www.phpinternalsbook.com/php5/hashtables/hash_algorithm.html 了解到hash算法是djbx33a后，考虑hash碰撞。由于该hash算法的特性，两两⼀组进行碰撞，碰撞出array_key=O6Q4O6Q4O6Q4O6Q4. POC static inline unsigned long zend_inline_hash_func(const char *arKey, unsigned int nKeyLength) { register unsigned long hash = 5381; /* variant with the hash unrolled eight times */ for (; nKeyLength >= 8; nKeyLength -= 8) { hash = ((hash << 5) + hash) + *arKey++; hash = ((hash << 5) + hash) + *arKey++; hash = ((hash << 5) + hash) + *arKey++; hash = ((hash << 5) + hash) + *arKey++; hash = ((hash << 5) + hash) + *arKey++; hash = ((hash << 5) + hash) + *arKey++; hash = ((hash << 5) + hash) + *arKey++; hash = ((hash << 5) + hash) + *arKey++; } switch (nKeyLength) { case 7: hash = ((hash << 5) + hash) + *arKey++; case 6: hash = ((hash << 5) + hash) + *arKey++; case 5: hash = ((hash << 5) + hash) + *arKey++; case 4: hash = ((hash << 5) + hash) + *arKey++; case 3: hash = ((hash << 5) + hash) + *arKey++; case 2: hash = ((hash << 5) + hash) + *arKey++; case 1: hash = ((hash << 5) + …

使用ESP8266+RC522+MG995低成本改造宿舍门禁支持NFC刷卡与远程控制
type: item
date: 2021-09-08T17:40:00+08:00
description: 序 这是一个从刚入学就挖下的坑，宿舍老旧的门锁与会捉迷藏的钥匙总把我锁在外面，室友有时也没有那么可靠。于是准备把门锁做非破坏性的改造，支持上手机控制。后来又考虑到需要在断网的时候也能够正常访问，又加入了NFC刷卡开门。由于东西仅限自娱自乐且宿舍楼道有完备的安防监控，本项目没有准备任何访问控制。以下是实现的过程。 本项目源码已打包至https://github.com/MoeMion/Magic_Door/. 材料准备 ESP8266开发板 整个系统的控制中枢，支持Wi-Fi连接并且附带丰富的引脚，常用于物联网开发。在这里我选择了CH340处理器的版本，并在Arduino IDE上进行编程开发。（关于Arduino IDE与CH340驱动的问题可以通过搜索引擎快速解决） 价格：13 元 附ESP8266引脚定义图示.注意，D0(GPIO16) 仅能用于GPIO读写，不支持PWM/I2C/OW信号传输。 MF RC522 模块 负责NFC通信。由于需求简单，这里选择的版本不支持加密卡读写。 价格：12 元 MG995舵机 用来拉动机械门闩。 价格：15元 注意：MG995电机有多个版本，请选购180°带限位版本，360°版本仅能通过PWM信号控制旋转时间，不能控制具体角度！由于舵机不正确使用易烧坏，请小心使用！ 引脚解释： 棕 : GND 红 : VCC （5V或3.3V均可，实测5V转动速度更快） 黄： PWM信号 MH-FMD 无源蜂鸣器 用于输出声音提醒。 价格：2元 杜邦线若干、热熔胶枪 连接各部分传感器。主要用到了公对母与母对母两种。 MG995舵机控制 装置的核心功能，需要将舵机物理连接到门闩。 实现目标 控制舵机旋转一定角度拉动机械结构开门，并在一定时间后复位。 开机时自动复位。 防止在开门时间内重复动作。 防止delay()函数带来的进程阻塞。 接线 ESP8266 MG995 VU VCC GND(临近VU) GND D3(GPIO0) PWM 参考代码 为实现防止进程阻塞，这里使用CxgJSTime库，GitHub Repo:https://github.com/chengxg/cxg-arduino-lib/tree/master/CxgJSTime 以下的代码仅为精简过后的该部分功能实现代码，仅供参考。 #include <Arduino.h> #include <Servo.h> #include <cxg_JSTime.h> Servo servo; //初始化舵机对象 JSTime jsTime; //初始化jstime对象 int servoStatus = 0; //标记舵机状态，0为放下1为拉起 void setup() { servo.attach(0, 500, 2500); //第一个坑，参数：PWM对应的GPIO接口,最小PWM信号,最大PWM信号，不同舵机参数不一样，默认参数不适用于本舵机。搜索引擎上大部分文档不会给出后两个参数！ servo.write(1); //参数为旋转的角度，通电后将电机复位，为0时偶尔会造成舵机卡死 } void opendoor() { if(servoStatus){ return; } servoStatus = 1; //标记舵机升起 servo.write(90);//舵机旋转90度，拉起门栓。实测90度够用，若长度不够可以改成180度 buzzersuccess(); //控制蜂鸣器播放成功提示音 int timeId = jsTime.setTimeout([]() { servo.write(1); //复位舵机 servoStatus = 0; //标记舵机放下 }, 10000); //延迟10秒,舵机复位，放下门栓 } void loop() { jsTime.refresh(); //刷新jsTime对象 } Web控制 通过无线网络接入来控制舵机开关。 实现目标 使用ESP8266WiFi库接入无线局域网。 使用ESP8266WebServer库实现WebServer以相应请求。 实现开门、心跳检测、重启、关闭面板LED灯等操作。 网络接入 ESP8266模块仅支持2.4G的Wi-Fi连接。此外在连接到无线路由器后需要绑定IP地址。若需要外网访问的话还得进行内网穿透。在这里我使用部署在宿舍的树莓派进行转发。 参考代码 #include <Arduino.h> #include <ESP8266WiFi.h> #include <ESP8266WebServer.h> ESP8266WebServer web(80); //初始化web对象 void setup(){ //连接网络 WiFi.begin("SSID", "PASSWO…