Zeka 的记事本

2021 年 1 月
红米 AC2100 开启 SSH 权限
在 2021 年 1 月 29 日说: 刷机 路由器

TL;DR 看这里,成功版本为 2.0.23 稳定版。

之前按照 这篇 想开启路由器的 telnet 权限。

dalao 写了一些脚本,但是遇到了很多问题,包括但不限于:

  • 由于忘关火绒导致 nc 被删除,弹出 nc.exe不是内部或外部命令,也不是可运行的程序或批处理文件。8081端口被占用,请检查。解决方法为进入火狐的恢复区恢复文件,并添加信任,以免误删。
  • 获取包的时候脚本报错,但还是提示 PPPOE 获取成功。这个问题原因为演示版本为 1.0.14,而新路由器被官方自动升级为了 2.0.23,方法已不再适用。解决方法为从 官方救砖工具以及原厂固件备份 文件夹中手动上传 1.0.14 包升级 ROM。
  • 第一次失败,无法继续。解决方法为断开 WAN LAN 口相连线,然后重试。

简单看了一下,dalao 应该是开启了一个 http 服务器(python -m http.server),然后在反弹 shell 那几个阶段从本地服强制覆盖官方文件。然后之所以破解包那么大是因为居然有整个 python,,,

爪巴了。

突然看到 帖子说 有 XSS 注入漏洞可以钻,试了下直接拿下了 SSH 的 root 权限:

首先注销登陆的账户,然后重新登陆,这时观察浏览器顶上的 url,会有 stok 的参数,这就是 token 啦。有了 token 按照帖子里的办法就办法注入了,只需要两次就行。一次开启 SSH 功能,第二次是将密码修改为 admin。第二次是可选的,但是不这样的话需要找到无序的默认密码,不方便我们后续操作。

去掉 # 开头的注释,把链接复制到浏览器里面,注意把 <STOK> 替换为自己的。

# enable SSH

http://192.168.31.1/cgi-bin/luci/;stok=<STOK>/api/misystem/set_config_iotdev?bssid=Xiaomi&user_id=longdike&ssid=-h%3B%20nvram%20set%20ssh_en%3D1%3B%20nvram%20commit%3B%20sed%20-i%20's%2Fchannel%3D.*%2Fchannel%3D%5C%22debug%5C%22%2Fg'%20%2Fetc%2Finit.d%2Fdropbear%3B%20%2Fetc%2Finit.d%2Fdropbear%20start%3B

# (optional) change password to `admin`
http://192.168.31.1/cgi-bin/luci/;stok=<STOK>/api/misystem/set_config_iotdev?bssid=Xiaomi&user_id=longdike&ssid=-h%3B%20echo%20-e%20'admin%5Cnadmin'%20%7C%20passwd%20root%3B

然后就可以愉快的登陆啦(密码为 admin)

当然可以直接拿这个注入漏洞修改很多东西www,不过这样还是太麻烦了,所以直接拿到 SSH 权限上去吧。

img 标签底下的一点点空白
在 2021 年 1 月 27 日说: CSS 前端

最近突然发现站点的 img 标签不能占满全部空间,而是留下了一层空。指定 height:100% 没有效果。

搜了下,在 这里 找到了答案。只需将图片的 display 设置成 block 就好了。

简单来说,图片默认的 display 属性为 inline 而不是 block。这导致了其展示与文字类似(联想图片可以通过浮动设置文字环绕)。

默认的文字排版方式为 baseline,这个排版的影响一般只体现在 西文 中。因此图片多出来的部分恰恰就是它的小尾巴。因此另一种解决方式为设置 vertical-align 为 bottom。

图片没有占用全部空间,留出了一层空隙
从 Nuxt 查看 CORS 行为
在 2021 年 1 月 26 日说: 前端 网络

CORS 是浏览器为了避免恶意请求做出的一项保护措施。其行为由浏览器控制,而决定是否放行则由服务器添加相应请求头,由浏览器检查完成。

换句话说,如果没有浏览器的限制,正常的请求是不可能出现 CORS 问题的。

Nuxt 恰好是 SSR 框架,也就是说部分请求是在服务端完成的,部分请求是在浏览器完成的。可以考察这一限制。

在服务端的请求不受到浏览器影响,因此只要接口无误,就能保证渲染出来。但是在浏览器就没有那么简单了。

要弄明白的一点是,对于前后端开发,CORS 基本是由后端配置的,前端只需要关心能否请求到数据。前端不需要关系的原因为浏览器自动完成了所有操作。而后端则往往由对应模块完成。

步骤大概是这样的(阮老师的教程 写的很详细):

前端发起请求,浏览器检查请求头,查看是否为简单请求(简单来说,header 足够简单,请求局限于 POST 和 GET,默认是不带 cookie 的)。

如果是简单请求,则浏览器在 header 添加 origin,并说明 origin(域名)。之后再检查服务器的回应,不管服务器响应的 body 是什么,只检测 header,如果没有出现 Access-control-allow-origin 字段,或者不合法,那么此次请求就会被丢弃。也就是说数据到了浏览器,但是被浏览器拦截了,不允许 JS 拿到数据并进一步动作。如果存在请求头,则数据正常到达,表现和没有跨域一样。

如果是非简单请求,则浏览器首先发出的不是我们的请求,而是一个 OPTIONS 类型的请求(请求自然不带响应内容)。对于有 CORS 模块的后端,会返回几个字段:

  • Access-Control-Request-Method
  • Access-Control-Request-Headers
  • Access-Control-Allow-Origin

非简单请求与简单请求的区别就是方法与 header,这也就是预检请求的意义。预检请求检查方法与响应头是否允许。如果不被许可自然就拦截了。如果通过,就再发起请求。也就是说需要请求两次。为了不频繁发送请求,浏览器会对预检请求进行缓存,从而避免多次 OPTIONS 请求。

此外不论是简单请求还是非简单请求,对 cookie 都有更严格限制,比如 Access-Control-Allow-Origin 必须详细指定域名,不能是宽泛的 *,还需要加上额外的 Access-Control-Allow-Credentials = true 的 header。

对于正确配置了 CORS 的后端,会按照期望进行响应。接下来分析下没有配置 CORS 的后端服务器行为。

对于没有配置 CORS 的后端,有什么请求就会有什么响应。最大的特点是一定不会有 CORS headers。对于简单请求,即使数据送到了浏览器,浏览器也会拦截并丢弃。对于非简单请求,OPTIONS 请求后端无法进行正确答复,请求无法继续,即使后端进行了正确响应,浏览器也会拦截。

CORS 只能阻止接口被滥用。假设有一台正确配置了 CORS 的银行服务器 A ,那么恶意页面 B 就无论如何无法对 A 发送合法的转帐请求,从而避免了安全事故。

但是 CORS 不是万能的。比如它无法防范信息收集。毕竟信息收集的服务器是由坏人控制的,他知道要配置好 CORS 从而窃取用户信息。此外,如果对于本站点发动了 XSS 攻击,那么请求是不会触发 CORS 的,浏览器无法拦截。

对于不能让其他页面随随便便调用的 API(比如用户数据),CORS 应该尽可能阻止请求,只运行在自己的域名上使用。而对于一些开放接口(比如 一言 的接口),它们需要能够在不同页面展示,就需要设置所有域名允许访问了。

上面是在应用层次。随着前后端分离的影响,数据接口与页面接口渐渐分离,导致了跨域问题频发。对于简单页面,虽然部署时可以通过 nginx 统一,但是开发的时候还是经常遇到。对此的解决方案是后端安装并正确配置 CORS 即可。此外,虽然是开发环境的解决方案,但是完善 CORS 总归是没错的,因此开发完成后不需要移除 CORS(当然还是需要合理配置)。

替换 node-sass 为 dart-sass
在 2021 年 1 月 25 日说: 前端

在这里 曾提到过 node-sass 兼容性问题,对此官方的做法是换用 dart-sass。

替换只需要两行就行了:

yarn remove node-sass
# dart-sass package name 
yarn add sass 

安装会丝滑很多。

修复 KDE 主题 WhiteSur Aurorae 底部边界透明问题
在 2021 年 1 月 24 日说: KDE Linux

对于 4k 屏幕来说,各种主题兼容性都不太好,往往存在缩放问题。为此 WhiteSur Aurorae 主题提供了不同的缩放比(1.25, 1.5, 2)。

对于我的屏幕,1.25 倍缩放比是合适的,但是出现了透明的边框。而作者提供的另一种主题 Sharp 消去了底部边框,所以没有这个问题。但是很可惜的是 Sharp 主题没有提供不同的缩放比,也就是说要么把 Sharp 改造成 1.25 倍的,要么将 1.25 倍的白边修复。

打开主题文件夹,发现主要装饰是一个矢量图(decoration.svg)。不知道是出于疏忽还是怎么,这个矢量图底部是透明的,于是一下子就找到了问题,只要修改填充颜色即可。

由于手头没有 SVG 编辑工具,于是暴力拿浏览器打开,找到相应的样式:

opacity: 0.6;
fill: #f5f5f5;
fill-opacity: 1;
stroke: none;
stroke-width: 1.41421;

不知为何设置了 opacity,以及与主题不同的颜色,修改成如下即可:

opacity: 1;
fill: #ffffff;
fill-opacity: 1;
stroke: none;
stroke-width: 1.41421;

这样的地方一共需要修改三处,修改完成后重启就完成了。

但是这样还是有一个 bug,当处于 deactivate 模式时,透明度又来了。

主题透明底部
/static/55c7fe5411ff902ffadd1dfae2dc8ea7/7902e/screenshot_20210124_101025.jpg
Ubuntu 配置 dhcp
在 2021 年 1 月 18 日说: 网络 Linux

Ubuntu Server 18 LTS

试了试刀片服务器,由于安装的时候没有链接网络,所以安装的时候没有进行网络配置。安装好后虽然能上去,但是不能正常上网。

在 Ubuntu 17 之后,配置网络的文件改为了 netplan。

# automatically generate config file
# file locate at /etc/netplan/*.yml
sudo netplan generate

生成的配置就是 .yml 文件。 在修改这个文件前,首先要检查网络接口名称,使用 ifconfig -a 指令可以看到所有网络接口,直接运行 ifconfig 可以看到正在运行的接口。

这台服务器有四个网口,所以在使用的时候需要注意区分。在使用网口一(ifconfig 得到名称为 eno1)的时候需要配置网口一。

network:
  ethernets:
    eno1:
      addresses: []
      dhcp4: true # 开启 dhcp,使用动态 ip 分配
    # other configurations
  version: 2

之后就是检查与应用了:

sudo netplan try
# success
sudo netplan apply

之后就能配置完毕了。

使用 mutt wizard 配置 gmail
在 2021 年 1 月 17 日说: Linux

参考的是 Mutt 终端邮箱,gmail 流程稍有不同。

使用顺利,但是在生成完密钥,输入帐号密码登陆 gmail 的时候出现了问题:

mw -a [email protected] -x "mypasswd"

提示密码错误,按照某个 issue 提到的,密码中的特殊字符需要转义,如 ! 需要转化为 \!。测试后失败。

再依据 这个 issue 提到的,由于我的 gmail 开启了多步验证,所以不允许任意 app 登陆。mutt 作为一个 app,需要使用 google 生成一个 app token 登陆(也就是以 app 形式登陆,参考 OAuth 模型,不直接使用主密码有利于防止第三方客户端滥用帐号的全部权限)。

在 这里 下面的 “App passwords” 申请一个密钥,中间要求输入帐号密码确认,确认后点击生成就能获取一个全新的密钥。

再使用这个密钥登陆就可以啦:

mw -a [email protected] -x "apppasswd"
Nginx 反代 jupyter
在 2021 年 1 月 8 日说: Nginx 网络

Nginx 反代理 jupyter 可以让控制更灵活(并不。

为了安全,jupyter 有一些基础的限制,比如默认开在本地,不允许远端访问等等。要想使用 nginx 反代,必须加以设置。

Nginx 的设置文件 参考这篇。

添加所需 header 就没有问题了。

此外,jupyter 需要打开远端访问设置。首先初始化配置:

jupyter notebook --generate-config

初始化后的文件默认保存在 home 目录下的 jupyter_notebook_config.py 中。文件里面有很详细的注释了。对于开启 Nginx 访问,需要允许远端访问:

c.NotebookApp.allow_remote_access = True

默认是通过 token 访问的,这样会在 url 后跟随一长串的 token,不美观,访问也不方便。为此设置密码访问:

jupyter notebook password

确认密码就好了。之后只要将域名,证书配置正确就能正常运行了。

记一次 crontab 配置错误引发的灾难
在 2021 年 1 月 4 日说: Linux

书写 cron 定时同步脚本时,时间参数设置出现了错误:

* * 17 * * *
# except:
# 0 0 17 * * *
# or:
# 0 17 * * *

由于第一位(秒钟)与第二位(分钟)设置为了 *。导致 crontab 在 17 点时每过一秒执行一次任务。刚好同步脚本用到向 telegram 发送信息,于是出现了对 telegram 的小 d。在我还没意识到发生什么的 51 分钟里,telegram channel 已经出现了 1k+ 条消息(由于本地程序执行也需要时间,所以实际上不可能一秒执行一次)。

换作其他平台(比如莫名其妙把我的开发者号封了的 twitter),这个 bot 肯定是废了。但是 telegram 仍然正常运行。

也许这次没有触碰到 telegram 的上限?毕竟换算下来频率大概 3s 请求一次。

不过不管怎样,也提醒了我 cron 时间设置一定要检查好。毕竟 cron 执行本身是无声的,很有可能出现错误配置却没有发现的情况。

找了找,果然发现了 cron 可视化网站(crontab.guru)。它支持将书写好的时间转化为人类可读的格式,从而帮助你发现错误。

举例来说,将我的错误时间放上去,会提示:

# * 17 * * *
At every minute past hour 17.

这样一下就知道出错了。

/static/3cb9644c58ebb7c8c97cdfcfe20f79d2/03908/screenshot_20210104_115457.jpg
Deno 与 top level await
在 2021 年 1 月 2 日说: 前端 Deno

单线程 JavaScript 能获得成功的一大原因在于其强大的异步能力。而作为 Node 的 “纠错者”,Deno 提供了更完善的异步支持。async await 满天飞

一个特征是 Deno 支持 top level await。

top level await 特性似乎仍然处于提案阶段,各大浏览器似乎除了最新版 Chrome 没有支持的。

相信学习 JS 的人一开始对于 JS 没有 sleep 函数感到困惑。你无法直接让程序休眠一段时间,JS 只提供了 setTimeout 与 setInterval 方法。这是为了防止主线程阻塞。对于单线程程序,运行在浏览器里的 JS 主线程发生阻塞将会发生无法预知的效果。为此,浏览器只支持回调形式的延时,Top level 的执行在没错误的情况下是不会阻塞的。

但是有了而 top level await 之后,sleep 就变得顺理成章了:

// define sleep function
const sleep = (sec: number) => {
    return new Promise((reslove) => {
        setTimeout(reslove, sec);
    });
};

// use in top level
console.log('execute at time 0');
await sleep(3);
console.log('execute at time 3');

有人说 Top-level await is a footgun,理由也很简单,阻塞了主线程执行,可能一个再正常不过的请求就会导致执行阻塞。

当然,只要加个 wrapper,就能实现伪 top level await 了 机智的地球人:

(async()=>{
    // everthing here!!!
    // I am top level :)
    await sleep(3);
})();

使用自然见仁见智了,但是如果运行环境不是浏览器,那么 Deno 的这个特性将会带来不少便利。比如上面提到的 sleep 函数,以及异步迭代器(for await),请求发送等等。