coolshell 谜题通关

| 分类 计算机知识  | 标签 coolshell 

###一、前言

周末在微博上看到 coolshell 博主陈皓搞了一个编程小游戏的页面,过关制的。感觉很有趣,就打开看了看。有空没空搞了3天才算搞定,感觉眼界开阔了一些,但是对每一关涉及到的知识都了解的太浅,这里仅仅记录一下通关过程,至于涉及到的知识会在最近学习一下:)

首先,游戏地址是:coolshell 大闯关

游戏规则很简单。每一关都需要得到一个结果,把这个结果填进 url 即可进入下一关。下面是通关攻略(强烈建议自己先试试,每一关如果20分钟都没思路就可以看看攻略了)

###二、通关过程

####0. first.html

这一关由两部分组成:

  1. 一段乱七八糟的符号
  2. 一个提示语:My brain has been fucked

当我打开这个页面的时候,感觉这啥玩意啊。难道是正则表达式提取?于是看了看+号,依次是1个,2个,3个……然后又找了各种规律找不到,很是郁闷。于是就去干别的了。等我无聊的时候打开了这个页面的源代码,灵光一现发现上面不是纯文本,而是一段 code,那提示语应该跟 code 相关吧?于是就在网上开始搜,百度必应不出意料的呵呵呵(原谅我一直黑,但这是事实啊。。),于是用 google 开始搜,(⊙o⊙)…然后发现 fuck 被 google 过滤了,和简单,把安全过滤去掉就好了(中文版 google 是不能去掉安全过滤的,你懂的。所以切换到中文繁体,然后在右下方的设置里面去掉安全过滤之后拉到最下面保存即可)。然后看了几个网页,进了英文版的 wikipedia,然后答案就很明显了。原来有门编程语言叫做 brainfuck。之后就很 easy 了,可以看看这是静态还是动态的,静态的就找个编译器和解释器,动态的直接在网上找个解释器就好。我随手搜了个在线运行的网站,把代码贴进去。执行结果是welcome,于是下一关就被打开了。

总结一下:

  • brainfuck wiki
  • 找一个在线执行 brainfuck 代码的网站,比如这个brainfuck
  • 贴进去点击 Run,看输出就哦了

####1. welcome.html

这关很简单的其实,根据等比数列,可以首先得到一个数字:18 * 108=1944。然后试一下,发现这个1944对了。但是还有其他答案,应该是在那句话里。这次聪明了直接 google,然后直接知道是42。然后发现也对了,但是没有进入下一关。从 X * Y 那个来看,难道是求一下乘积?尝试着 1944 * 42 = 81648。然后就过关了= =

总结一下:

  • 生命、宇宙以及任何事情的终极答案——42,为什么?你丫不会 google 啊

####2. 81648.html

一个硕大的键盘,鼠标滑过图片发现可以点击。然后会进入一个 wiki,大概看看介绍,这个布局是为了提高打字速度设计的,跟目前的布局也是一一对应的,然后自己人肉翻译一下即可,得到下面的代码:

1
main() { printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60);}

发现原来是一段 C 代码,用 gcc 编译执行后,输出 unix,得解。

总结一下:

  • 为打字出现的Dvorak Simplified Keyboard和目前使用的QWERTY键盘布局
  • 那段代码很有厉害,可自行 google 一下

####3. unix.html

出来一个二维码,用微信扫一下发现是一个字典。结合二维码下面那一段话,就非常简单了。写段程序翻译一下即可。随手写了一个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include<stdio.h>
#include<ctype.h>
#include<string.h>
#include<stdlib.h>

#define N 1000
char a[] = "abcdefghijklmnopqrstuvwxyz";
char b[] = "pvwdgazxubqfsnrhocitlkeymj";
char ci[N];

char find(char c) {
  int i;
  for(i = 0; i < 26; i++) {
    if(c == b[i]) {
      break;
    }
  }
  return a[i];
}

int main() {
  char *str = "Wxgcg txgcg ui p ixgff, txgcg ui p epm. I gyhgwt mrl lig txg ixgff wrsspnd tr irfkg txui hcrvfgs, nre, hfgpig tcm liunz txg crt13 ra \"ixgff\" tr gntgc ngyt fgkgf.";

  int len = strlen(str);
  for(int i = 0; i < len; ++i) {
    char c = str[i];
    if(isalpha(c) && islower(c)) {
      ci[i] = find(c);
    } else {
      ci[i] = c;
    }
  }

  printf("%s\n", ci);
  return 0;
}/*output:
Where there is a shell, there is a way. I expect you use the shell command to solve this problem, now, please try using the rot13 of "shell" to enter next level.
*/

发现输出需要用到 rot13,这是啥?!google 一下就知道了,原来就是一个简单的加密工具,因为英文字母有26个,13对,所以正好可以一一对应。然后 google 一下使用方法就可以了,或者懒得直接找一个在线 rot13转换的工具,输入 shell 后得到结果:furyy

总结一下:

####4. furyy.html

因为以前在玩正则表达式的游戏时遇到个这个模式,瞬间就知道这个是考察正则的了。根据那个单词,知道是回文字符串。根据图示知道需要找出能匹配左边8个单词的模式,然后提示语说在源码中有东西。打开源代码拉到最下面有一大段文本,保存到一个文件中。

这时候思路已经很明显了,用找出来的模式去匹配这段文本。那么,首先就需要找出这个模式,如果以前学过正则表达式的话,应该是很 easy 的。如果不太会,在下面总结的时候我会推荐一个讲解正则表达式很好的地方,配套有一个练习的地方(额,难度略高)。

找出来这个模式也很简单,人肉看下就是:

  • 第一个字符是大写或者数字
  • 第二个字符是大写或者数字
  • 第三个字符是小写
  • 第二个字符
  • 第一个字符

所以,考察的就是最简单的正则表达式,其中回文也可以用正则中的()来匹配。这样答案就出来了:

([A-Z])([0-9])[a-z]\2\1|([0-9])([A-Z])[a-z]\4\3

然后有输入了,有处理过程了,执行一下即可得到输出:

egrep -o '([A-Z])([0-9])[a-z]\2\1|([0-9])([A-Z])[a-z]\4\3' palindrome

然后就可以得到答案:

E1v1E
4FaF4
9XrX9
O3i3O
0MaM0
4GbG4
M5l5M
0WeW0
Y0s0Y

这几个都是回文串,我们根据 cat 是最中间小写字母的原则拿出来,得到答案:variables

总结一下:

####5. variables.html

妈蛋这个页面让我困了大半天,不知道想表达什么意思。我以为是那个数字有特殊的含义,google 了半天找到看起来靠谱的英文。好像是美国哪个州的 zipcode 啥的,填进去各种404,让我很是崩溃。。。 最后也没搞定,是看了网上已经出来的攻略才知道。。(这次写攻略才发现那句提示有点作用,让你 keep try…)

原来需要拿那个数字替换 url 中的2014,于是我就替换了,大概替换了10多次,还是需要替换。。估计要写个程序的样子,于是用 shell 写了个 while 循环,里面就是一个简单的 curl 命令,最后得到了答案:tree

总结一下:

  • 善于观察,这道题如果仔细看说不定会找到思路,,,,不过嘛,,,,,,,,,,遇到我这种智商的就,,,,,,,不说了,擦泪去

####6. tree.html

这道题就简单了,就是一个树。扫了一眼就知道题意是由中序和后序还原树,然后求得最深路径。于是写了一段代码,特么由于好久没碰指针,各种凌乱,吭哧吭哧花了将近1个小时才搞定,,,真是弱爆了。。。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include<iostream>
#include<ctype.h>
#include<stdio.h>
#include<string.h>
using namespace std;

struct Node
{
  char value;
  Node *left;
  Node *right;
};

string t_in, t_post;
char in[100], post[100];
char deep[100], final[100];
int maxlen;

void init() {
  int p = 0;
  for(int i = 0; i < t_in.length(); i++) {
    if(isalnum(t_in[i]))
      in[p++] = t_in[i];
  }

  p = 0;
  for(int i = 0; i < t_post.length(); i++) {
    if(isalnum(t_post[i]))
      post[p++] = t_post[i];
  }
}

Node* build(char *in, char *post, int len) {
  if(len == 0)
    return NULL;

  Node *cur = new Node;
  cur->value = post[len - 1];
  int lenp = strchr(in, cur->value) - in;
  cur->left = build(in, post, lenp);
  cur->right = build(in + lenp + 1, post + lenp, len - 1 - lenp);

  return cur;
}

void pre_order(Node *root) {
  if(root == NULL) {
    return ;
  }

  cout<<root->value;
  pre_order(root->left);
  pre_order(root->right);
}

void find(Node *root, int depth) {
  if(root == NULL) {
    if(depth - 1 > maxlen) {
      maxlen = depth - 1;
      memcpy(final, deep, sizeof(deep));
    }
    return ;
  }

  deep[depth] = root->value;
  find(root->left, depth + 1);
  find(root->right, depth + 1);
}

int main(void) {
  Node *root = new Node;
  t_in = "T, b, H, V, h, 3, o, g, P, W, F, L, u, A, f, G, r, m, 1, x, J, 7, w, e, 0, i, Q, Y, n, Z, 8, K, v, q, k, 9, y, 5, C, N, B, D, 2, 4, U, l, c, p, I, E, M, a, j, 6, S, R, O, X, s, d, z, t";
  t_post = "T, V, H, o, 3, h, P, g, b, F, f, A, u, m, r, 7, J, x, e, w, 1, Y, Q, i, 0, Z, n, G, L, K, y, 9, k, q, v, N, D, B, C, 5, 4, c, l, U, 2, 8, E, I, R, S, 6, j, d, s, X, O, a, M, p, W, t, z";
  init();
  cout<<in<<endl;
  cout<<post<<endl;
  root = build(in , post, strlen(in));
  pre_order(root);
  cout<<endl;
  maxlen = 0;
  find(root, 0);
  cout<<final<<endl;
  return 0;
}/*output:
TbHVh3ogPWFLuAfGrm1xJ7we0iQYnZ8Kvqk9y5CNBD24UlcpIEMaj6SROXsdzt
TVHo3hPgbFfAumr7Jxew1YQi0ZnGLKy9kqvNDBC54clU28EIRS6jdsXOaMpWtz
zWbTghHV3oPp8LFGuAfn01rmwxJ7eiQYZ25vKqk9yCBNDU4lcMIEaOj6SRXsdt
zWp8LGn01wxJ7
*/

然后使用上面给的 openssl 命令进行解密即可:

echo "U2FsdGVkX1+gxunKbemS2193vhGGQ1Y8pc5gPegMAcg=" | openssl enc -aes-128-cbc -a -d -pass pass:zWp8LGn01wxJ7

得到答案:nqueens

总结一下:

  • 二叉树遍历,又中序、后序还原树结构,或者由其中2种序列还原树结构
  • openssl 是神马东西?怎么使用?

####7. nqueens.html

这个一看就是9皇后问题,以前写过8皇后。这里是要输出所有的9皇后序列,然后要满足那个等式。于是写了一个9皇后输出所有的序列:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

const int N = 10;
bool visit[N][N];
int total, sum;

bool is_put(int x, int y)					  //当前行、列
{
	for(int i = 1; i < x; ++i)
	{
		if(visit[i][y])						  //行
			return false;
		for(int j = 1; j <= 9; ++j)
		{
			if(visit[i][j] && j - i == y - x) //主对角线
				return false;
			if(visit[i][j] && j + i == y + x) //副对角线
				return false;
		}
	}

	return true;
}

void print() {
	for(int j = 9; j >= 1; j--)
		for(int i = 1; i <= 9; i++)
			if(visit[i][j])
				cout<<i;
	cout<<endl;
}

void DFS(int n)
{
	if(n > 9)
		return ;

	for(int i = 1; i <= 9; ++i)
	{
		visit[n][i] = true;
		if(is_put(n, i)) //当前能放
		{
			if(n == 9) {
				sum++;
				print();
			}
				
			DFS(n + 1);
		}

		visit[n][i] = false;
	}
}



int main()
{
	memset(visit, false, sizeof(visit));
	sum = 0;
	DFS(1);
	cout<<sum<<endl;
	return 0;
}

这个程序会输出所有9皇后的序列 。一共352个。然后代入那个公式,因为我的 mac 上没有 sha1这个命令,然后我一 google 发现 python 有个现成的库,巨简单。。。于是就写了 python 程序,搞定之。

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/python

import hashlib

passwd="zWp8LGn01wxJ7"

array=(748396251, 753968241, 538479261, 649582731, 579382461, 849362751, 853972461, 473862951, 536972481, 579428631, 793528641, 463928571, 473825961, 368529741, 379425861, 475296831, 695283741, 758293641, 835296471, 738246951, 368249751, 592473861, 742963581, 642793581, 642839751, 625793841, 629538471, 526938471, 594682713, 683792514, 539682417, 384792516, 394852617, 963728514, 793824615, 493627518, 463925817, 738629514, 538629714, 539428617, 538429617, 369724815, 685297413, 964285713, 794258613, 468257913, 758296314, 369257418, 582736914, 942736815, 382497516, 625794813, 529637418, 428397516, 257936418, 269358417, 285396417, 295384716, 584973162, 849357162, 853697142, 953847162, 536974182, 374859162, 847926135, 946827135, 973825164, 538629147, 536928147, 386925147, 396824175, 974286135, 479258136, 936275184, 639258174, 637285149, 637249185, 637248159, 358296174, 396257148, 358297146, 359247186, 394286175, 374296158, 374295186, 852974136, 642859137, 942586137, 582963147, 592683147, 642853197, 372859164, 372864159, 526974138, 524973168, 528379164, 528374196, 429368157, 257948136, 258693174, 258693147, 249753168, 296358147, 296374185, 248396157, 579481362, 586931742, 946831752, 479631852, 473691852, 386491572, 849731625, 863971425, 473861925, 463971825, 536971428, 369581427, 369741825, 968241753, 468251973, 475291683, 479261358, 468271359, 475291386, 738251946, 736251948, 935281746, 936271485, 369281475, 572681493, 572481963, 742951863, 572481396, 742861359, 742591386, 742581369, 582931746, 582731946, 572631849, 362951847, 392581746, 372481596, 925741863, 829631475, 926831475, 296471358, 279631485, 286931475, 249731685, 869314752, 736814952, 936418572, 695813724, 495813627, 796318524, 468317529, 495316827, 736815924, 635819724, 835916427, 635819427, 368519724, 396417528, 697418253, 958417263, 964718253, 469318257, 495317286, 485317269, 485316297, 639714258, 635814279, 639418257, 637419258, 369714258, 359417268, 862714953, 852417963, 852914736, 752814936, 972418536, 852417936, 792613584, 962713584, 682713594, 752813964, 352817469, 362714859, 352814796, 825714693, 427915863, 724918536, 724619538, 427918536, 429518637, 728613594, 925713864, 425813697, 726318594, 427318596, 275814639, 259418637, 257413968, 586137942, 574139682, 584136972, 853174692, 574138629, 574136928, 368147529, 695184273, 647185293, 748159263, 948136275, 649137285, 647139285, 963185247, 683195247, 953168247, 693184275, 368159247, 369184275, 394186275, 574182963, 584172639, 647182539, 849152637, 649152837, 683192574, 953172864, 853162974, 386192574, 379152864, 357142869, 528147963, 724185963, 824179635, 528179364, 529168374, 524179368, 526137948, 275194683, 258196374, 258136974, 257138649, 247139685, 263184975, 751693842, 581473692, 741853692, 861357942, 741396852, 471396852, 631849752, 751863924, 691473825, 461973825, 861379425, 831479625, 951468273, 461958273, 791358246, 741386295, 741369285, 731685249, 731958246, 631479258, 681592473, 851692473, 571682493, 681742953, 641792853, 841752693, 471692853, 951842736, 581942736, 941582736, 471852936, 481572639, 631852974, 531682479, 571428693, 741529683, 741829635, 741926835, 461528379, 531728649, 531629748, 261958473, 281479635, 261748359, 241796358, 261753948, 261379485, 617483592, 714693582, 714853962, 814639752, 615793824, 814736925, 318497526, 615794283, 518637249, 419637285, 814752963, 413692857, 319752864, 316852497, 317582469, 314792586, 518427963, 716924835, 716824935, 417926835, 415926837, 718529364, 815726394, 516428397, 415827369, 716258493, 615297483, 714286935, 415297386, 317286495, 174839625, 174835926, 148397526, 157938246, 185397246, 185369247, 168374295, 157942863, 159642837, 174692538, 146392857, 147382596, 138692574, 168524973, 147925863, 169528374, 175829364, 146825397, 136824975, 184279635, 159268374, 164279358, 157263948, 164283975, 137285946, 162974835, 142869357, 152693847)


for code in array:
  if(hashlib.sha1(passwd + str(code) + "\n").hexdigest() == "e48d316ed573d3273931e19f9ac9f9e6039a4242"):
    print code

原谅我用这么搓比的方法吧= =因为我用 C 跑出来的9皇后所有的解,不想用 python 再写一遍了,于是用 vim 的宏录制把结果放到 python 的 tuple 里面,然后遍历就 ok 了,hiahiahia~~~

程序的结果是:953172864

总结一下:

  • N 皇后问题,8皇后一共92个解,如果不算旋转,一共12个独立解。而9皇后有352个解
  • 学会使用 sha1,虽然我图省事用了 python 打表。妈蛋看了别人攻略,全程 python,代码比我短一大截啊!!!妈妈我也要用 python

####8. 953172864.html

这道题算是比较简单了,说白了就是24进制。如果想省事可以直接用 google 计算器,反正最大的就是26^8,反正大数最后都转成字符串,长度无所谓的。所以直接在 google 搜索框里面输入对应的计算公式,结果就出来了。。。但是我当时不知道啊!摔!!!不过还好 java 有大数类,非常简单,松松的无压力。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import java.math.BigInteger;

public class BigNumber {
	public static void main(String[] args) {
		BigInteger bigInteger = BigInteger.ZERO;
		bigInteger = bigInteger.add(BigInteger.valueOf(3*26*26*26*26).multiply(BigInteger.valueOf(26*26*26*26)));
		bigInteger = bigInteger.add(BigInteger.valueOf(15*26*26*26).multiply(BigInteger.valueOf(26*26*26*26)));
		bigInteger = bigInteger.add(BigInteger.valueOf(15*26*26).multiply(BigInteger.valueOf(26*26*26*26)));
		bigInteger = bigInteger.add(BigInteger.valueOf(12*26*26).multiply(BigInteger.valueOf(26*26*26)));
		bigInteger = bigInteger.add(BigInteger.valueOf(19*26*26).multiply(BigInteger.valueOf(26*26)));
		bigInteger = bigInteger.add(BigInteger.valueOf(8*26).multiply(BigInteger.valueOf(26*26)));
		bigInteger = bigInteger.add(BigInteger.valueOf(5*26*26));
		bigInteger = bigInteger.add(BigInteger.valueOf(12*26));
		bigInteger = bigInteger.add(BigInteger.valueOf(12));
		
		System.out.println(bigInteger);
		
		BigInteger bigInteger2 = BigInteger.ZERO;
		bigInteger2 = bigInteger2.add(BigInteger.valueOf(19*26*26).multiply(BigInteger.valueOf(26*26)));
		bigInteger2 = bigInteger2.add(BigInteger.valueOf(8*26*26).multiply(BigInteger.valueOf(26)));
		bigInteger2 = bigInteger2.add(BigInteger.valueOf(5*26*26));
		bigInteger2 = bigInteger2.add(BigInteger.valueOf(12*26));
		bigInteger2 = bigInteger2.add(BigInteger.valueOf(12));
		
		System.out.println(bigInteger2);
		
		System.out.println(bigInteger.divide(bigInteger2));
		
	}
}/*output:
751743486376
8826856
85165
*/

刚开始直接在 valueOf() 里面搞一大串数字相乘,发现结果竟然是负数,debug 了一下吐血的发现:尼玛 valueOf() 里面还是 Integer 类型啊,真是傻逼到家了。。。。。赶紧把相乘分开,结果就出来了。。。。。。。。。这智商,哎。。。

得到85165之后,用24除就可以得到答案了:DUYO

总结一下:

  • Java 大数类的应用
  • google 搜索框好强啊!!!!有时间了解了解 google 搜索框还能干啥~

####9. DOYO.html

打开一看,竟然是一头猪。。。还以为要讽刺我呢~~~然后这次聪明点了,先拿鼠标去晃,果然有东西。于是准备 google。然后发现 google 又被 GFW 艹了。。。懒得重启,就小心翼翼的打开 bing,输入关键字 pigpen freemason,出来了几个看着还靠点谱的网页。在第一个点进去就明白了:bing 终于良心了一次。然后就知道其实是根据字母和边框组成了加密方式。。。。人肉翻译一下就得到了结果是 HELLO WORLD。。于是又贱兮兮的去用百度,第一个竟然是 wikipedia !!!我吓得不轻啊,baidu 和 bing 这俩极品竟然也能返回一次正确结果啊。。。。然后重启 goagent 后用 google,果然第一位直接就是 wikipedia 了,意料之中,低调低调。

于是答案就是:HELLO WORLD,但是很悲剧的输入后发现又404了。。魂淡。。难道还要进行什么转换??又尝试看了网页的源代码,发现了这样一句话:

Combine these two words with using lowercase

然后我又看了原网页,用鼠标滑过那个加密信息,直接也显示了那句话。。。。。。。

所以最终的答案就是:helloworld

然后就通关了!!!可惜我搞定的时候已经过了3天了,Top100已经满了,,,而且我还看过一次别人的攻略。。。囧。。

总结一下:

###三、8月12日更新

我勒个去,原来还有一个隐藏关卡。。。在最后一关 helloworld.html 中,一个大大的 shutdown 图片。其他也没啥了,查看网页源码、鼠标乱晃都没有啥收获。。。最后还是去看了别人的攻略。。。原来是下载这个图片,用 vim 直接打开,发现会有 rar 字样的字符,尝试改名之后解压,会发现一个 helloworld.txt,打开之后最下面才是隐藏关卡的答案:DennisRitchie.html

原来是纪念Dennis Ritchie的,上面有它的照片和主页,点进去膜拜了一下~~~

###四、通关感受

总之,玩了这个游戏吧,感觉知识面还是太窄,而且很多东西都是知道个皮毛。比如 openssl,前阵子爆出来的 heartbeat 漏洞闹出了那么大的动静,但是也仅仅只是知道有 bug,具体是什么也没有追究过。也没有具体了解过 openssl 的原理。。不过还好知道点基础的,比如 openssl 是工作在传输层和应用层之间,将应用层的数据进行加密后才传给传输层,使用最广泛的就是 https。嗯,最近抽空把这个相关的东西看看吧。。。。

另外基本功还是得抽空复习复习,一个简单的二叉树、N 皇后都搞了小半天,真是弱爆了。。。。

虽然通关了,但是像最后一关的标题一样,仅仅是 helloworld。那么第一步就是把涉及到的知识都学一下吧,fighting~~


上一篇     下一篇