R·ex / Zeng


音游狗、安全狗、攻城狮、业余设计师、段子手、苦学日语的少年。

Rex 的除夕夜加密红包 Writeup

注意:本文发布于 2639 天前,文章中的一些内容可能已经过时。

先吐槽一下这次的界面好了。前端确实是随手写的,加了一段 prism.js 做代码高亮;本来想做优雅链接来着,结果 Openshift 上面 Nginx 老是调不好。刚才又调了一下,终于可以了,于是把所有题目的链接都改成了优雅链接(https://hongbao.rexskz.info/{code})。

然后在 index.php 的一开始写了如下几句:

if (!preg_match('/^[0-9A-Za-z_]+$/', $_GET['code'])) die('Access denied');
sleep(1);
require_once "{$_GET['code']}.php";

第一句为了防止任意文件包含,第二句是为了防止暴力破解口令,第三句加载对应关卡的变量,然后下面就是将这些变量填充到固定的模板里。下面就看一下具体的题目吧!

Level 1

给个入口好了:https://hongbao.rexskz.info/first

const img = <img src="2.png" />;
const code = hongbao_decode(img);
const curUrl = location.href;
const newUrl = curUrl.replace('first', code);
if (/\d{8}/.test(code)) {
    console.log('Wrong!');
}
console.log(`The code is: ${code}`);
console.log(`Next level: ${newUrl}`);

一段自认为还比较标准的 JSX 代码,其中 hongbao_decode 函数显然不是什么系统函数,大概能知道这是让你自己想的。
那么 2.png 是什么东西呢?打开网址 https://hongbao.rexskz.info/2.png 看一下:

0

看起来是一个二维码被打乱了顺序。纠正之后扫出来是 Li4uLi4gLS4uLi4gLi0tLS0gLS0tLi4gLi4uLi4gLS0tLi4gLi4uLi0gLi4tLS0=,显然是个 Base64,解密之后是 ..... -.... .---- ---.. ..... ---.. ....- ..---,显然是个摩斯电码,解密之后是 56185842,发现刚好符合 /\d{8}/,因此推测这就是答案,可以通过访问 newUrl 来验证。

Level 2

上来就是一段 PHP,其中 $input 可以发现是一段混淆压缩之后的 JavaScript,尝试着对其解密。注意,因为这是写在 PHP 里的,所以有些字符是转义字符,不能直接复制粘贴运行得出答案。简便的方法是将这一段写成 PHP 然后执行。解密结果是 123467@13457@36@136@136@123467@2346@13457。然后看到下面的代码是先用 @ 打散成数组,然后做一个类似于 LED 的加密,例如 1 对应的是最上面那根横线。这样解密之后得到 92177942

Level 3

题目首先要求输入一个满足要求的字符串。限制条件分别为:

  1. 必须由 1-4 组成,长度为 8;
  2. 第零位必须比第一位要小;
  3. 1-4 必须都要出现,并且数字 i 第一次与最后一次出现的位置刚好隔了 i 个字符,也可以推出来 1-4 分别出现了两次。

通过简单的编程枚举,可以确定唯一满足答案的字符串是 23421314(灵感来源于我初三的时候看到的一篇文章 一个数字问题:23421314,这篇文章里面的代码现在看起来似乎太复杂了一些。发空间链接只是为了秀一下发布日期大家不要在意,这个数字网上也能很容易地搜到相关的文章)。diff 变量是一段 Base64,不断解密之后得到 23220328,于是答案为 23421314 + 23220328 = 46641642

Level 4

题目中什么提示也没有,因此考虑抓包,发现一个请求头:

The-File-You-Must-See: https://hongbao.rexskz.info/_

下载下来之后 file 一下发现是个 .tar.gz 的压缩包,里面有一个 .git 文件夹,还有个 last.sh,里面写了最后一关的地址是 'https://hongbao.rexskz.info/final_' + code。发现这个 Git 仓库有好多 commit,于是不断退回到每一个 commit 查看里面的 README.md(其实只有这一个文件),最后拼起来就是 code 的值 09154542

Level 5

首先提示说必须满足 isset($_GET['number']) && preg_match('/^\d{1,10}$/', $_GET['number']),下面还贴心地并不给出了满足条件的一个链接 https://hongbao.rexskz.info/final_09154542?number=0

然后大家就看到了全蛋男神的语录,并且发现下面的链接中 number 改成了 1,点进去发现是另外一条语录……(完整的语录一共有 100 条,详见文章末尾。)

但是究竟有多少条语录呢?如果闲的无聊可以一条条看,会发现这是个 100 的循环,但是可以每次在后面加个 0,会发现 10000100000000 是两个分割点,因此考虑答案可能是这之间的某个数。

# number == 10000 时
$_GET['number'] === 10000
Seems no more fun.
Why not try https://hongbao.rexskz.info/final_09154542?number=10001 ? Maybe the reward is waiting for you!

# number == 100000000 时
$_GET['number'] === 100000000
Number is toooooooooooooooooooooooooooooooooooooo large!
For god's sake, trust me, there's no reward here at all!
Why not try https://hongbao.rexskz.info/final_09154542?number=100000001 ? Alright I'm just kidding.

写一段程序不断二分访问,最终得到那个特殊的 number24361(灵感来源于爱因斯坦的那个“两打和十九的平方”的梗)。

# number == 100000000 时
Congratulations! But the answer is not the code, you need more answer.
Why not try https://hongbao.rexskz.info/final_09154542?number=24362 ? But this is exactly the answer, it's no use to try again...

Another answer 在下面的倒计时里,然而这个倒计时是到二月底的……查看源代码可以发现:

var timestamp = 1488297599; // 2017-02-28 23:59:59
var seconds;
var a = setInterval(function () {
    seconds = parseInt(new Date().valueOf() / 1000);
    var diff = timestamp - seconds;
    if (diff > 0) {
        document.getElementById("countdown").innerHTML = 'Another answer will show in ' + diff + ' seconds...';
    } else {
        document.getElementById("countdown").innerHTML = 'Another answer is <a href="https://hongbao.rexskz.info/____">THIS</a> !';
        clearInterval(a);
    }
}, 500);

这都什么破名字……下载下来后发现是个 32 位的 ELF 文件。用 IDA 反编译一下发现其实非常简单:

1

int getData()
{
  int result; // eax@1
  int v1; // [sp+8h] [bp-10h]@1
  int v2; // [sp+Ch] [bp-Ch]@1

  v2 = *MK_FP(__GS__, 20);
  sub_4A0("Do you know what year is it: ");
  v1 = 0;
  sub_4D0("%d", &v1);
  result = delta[v1 % 10] + 1323624;
  if ( *MK_FP(__GS__, 20) != v2 )
    _stack_chk_fail_local(*MK_FP(__GS__, 20) ^ v2);
  return result;
}
int __cdecl main(int argc, const char **argv, const char **envp)
{
  getData();
  sub_4A0("The encrypted data `dat = %d`.\n");
  sub_4B8("The code in php is `'0' . (number + dat)`, remember the number?");
  sub_4B8("It's not too difficult to get RMB 50!");
  return 0;
}

为什么我的 IDA 字体改了呢,因为这一版 Windows 里面的 Fixedsys 字体是乱码……顺便我已经懒到代码格式都不想改了……

main 函数很简单,下面那三个一看就是 printf,然后输出的数字应该就是 getData 的返回值,于是重点看到这个函数。其中 v2 在逻辑上来看没啥意义,唯一有意义的是 delta[v1 % 10] + 1323624v1 又是 scanf 得出来的,因此应该是 2017,返回值为 delta[7] + 1323624。双击 delta 查看里面的数据,既然是 int 那么每一位应该占四个字节。想方设法转换成如下的形式:

.data:00002020 ; int delta[]
.data:00002020 delta           dd 435
.data:00002024                 dd 654
.data:00002028                 dd 67
.data:0000202C                 dd 54643
.data:00002030                 dd 5425
.data:00002034                 dd 46
.data:00002038                 dd 564
.data:0000203C                 dd 6457
.data:00002040                 dd 657
.data:00002044                 dd 56

所以返回值是 6457 + 1323624 = 1330081,然后看最后的输出,结果应该是 '0' + (24361 + 1330081) = '01354442'。只可惜最后没人拿到这个五十元的红包。


附录:全蛋男神的语录

```php $word = [ "我是富土康三号流水线的张全蛋", "英文名叫 Michael Jack", "法文名叫霍雷呆-杰Q赖", "我的工作是组装手机", "那些大牌子的手机啊", "都是我们代生产的", "什么 Samsong 啊,诺 ki 拉啊,阿普啊,华强北啊", "我都有摸过", "我是我们流水线的纪检员", "那根据不同商家的要求啊,肯定是不一样的", "像我们这种国际化的 enterprise", "对质量的要求肯定是 very 的 high", "毕竟我们也算是半个外企嘛", "做的东西肯定是 niubility 的", "像素高屏幕大电量足跑马灯", "哈哈哈哈哈", "小米手机是怎么检测的呢", "我们就用一根温度计", "这就是 thermometer", "如果小米手机的开机温度低于 85 摄氏度的话", "就说明这部手机是不合格的", "那就要打回去重做", "我是怎么检测锤子手机的质量的呢", "作为有情怀的国产手机", "质量一定要过硬", "一锤子下去", "完好无损的那些才可以放到市场上去售卖", "(所以我到现在都还没有看到哪里有卖)", "哈哈哈哈哈哈哈哈", "我喜欢的人是 4 号流水线的李小花 Isabella Li", "她正在和 2 号流水线上的赵铁柱谈恋爱", "赵铁柱他们班最近在代工那个什么 Apple Watch 嘛", "他每个月连奖金总共有三千两百多块", "她是因为钱才跟他在一起的", "他连 QQ 会员都不是!那个苹果婊", "Stupid", "苹果这个没有质检这个环节", "就算 iPhone 多烂你们都抢得头破血流嘛", "还用质检条毛啊", "那个 Apple Watch 那么烂,你们还不是那肾来换", "啊买了个表买了个表", "Stupid,哈哈哈哈哈哈哈哈哈", "像我们富士康这样的 transnational enterprise", "经常会和不同国家的客户说一些技术上的 meeting 啊", "在我们厂里不会说英语啊,都会被经理 fire 掉的", "Fire in the hole", "简直 so no face", "那个 2 号流水线的赵铁柱说的都是什么 Chingilsh", "我听都听不懂", "Sorry, I don't know wha七 you say~", "哈哈哈……咳……哈哈哈哈哈哈哈", "我的英语算是很好的", "那一般国外的厂商都是我负责接待的嘛", "欧美的客户比较多", "只有我能和他们 communication", "我就在手机里下载学英语的 APePe 嘛", "30 天走遍美国、6 周流利英语、少林晨读 500 句", "There's a fire starting in my heart~", "Reaching a fever piss and it's bringing me out the dark~", "那些外国甲方的脾气很差的", "还好我英语过硬,有时候就得我出面哄啊", "他们谈僵了我就赶紧说:Relax you gays~", "但是有时候我越哄他们他们就越生气……", "(Gays 啊伙伴啊,不是 G-a-y-s 吗?)", "(同、同性……?!)", "唉总之那些外国人的脾气都很差", "有一次我给几个来自 United Condom 的领导安排住酒店", "那外资方代表嘛我肯定要按最高规格去接待", "我就安排他们住,如家,都是大床房,哈哈哈哈哈哈", "然后我就和他们说嘛,you tonight sleep in asshole", "他们好像还很不高兴……", "(如家嘛 asshole,asshole!不是asshole……?)", "最近我在忙什么呢?最近在帮大众公司返修那批有问题的汽车嘛", "他们家的汽车不过关就拿去售卖了", "卖条毛啊,最后还不是全部召回求我们,返修", "唉哟我都没眼看了", "那款车子的后悬挂系统开着开着,是会断掉的", "对方公司委托我们诊断一下", "就是断了嘛还诊断条毛啊", "Suspension system,术语就是底大杠,就是车子的后悬挂系统", "它有个承轴,压力大嘛就顶不住了,Undingable", "你想想看", "你唱着歌儿,开着刚买来的车和家人兜风", "旁边是你心爱的 WiFi,后面是你的 children", "突然后悬挂断了,你的轮子出现在你的视野里", "你以为它要变成大黄蜂,其实是后悬挂断了,what the fuck", "撞在水泥墩子上,失去了年轻的生命", "他们的质检员是……羊驼吗", "我组装的卡丁车都比它的质量好", "我们虽然是底层的技术工,还是在心底保有良知的", "大众那边派来一个鬼佬外资方代表", "赵铁柱他们都不敢骂,他们英语不好嘛", "我是我们车间英语最好的,是众望所归", "我就上去骂那个鬼佬:hey man, you are good. 才怪咧", "他以为我在夸他!", "Hey!你个吊毛!", "Do you know your suspension system very cheap!", "Very very cheap! You silly B!", "Hui duan!Shen me gui!Ni ma **!Son of bick!", "There's a fire starting in my heart~", "Reaching a fever piss and it's bringing me out the dark~", ]; ```
Disqus 加载中……如未能加载,请将 disqus.com 和 disquscdn.com 加入白名单。

这是我们共同度过的

第 3072 天