-
Notifications
You must be signed in to change notification settings - Fork 4
/
challenges.js
4304 lines (3646 loc) · 164 KB
/
challenges.js
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
const fetch = require('node-fetch')
const crypto = require('crypto')
const secrets = require('./secrets-loader.js')
function stringreverse(s) {
return s.split('').reverse().join('')
}
function calculatorCheck(a) {
const str = Buffer.from(a, 'base64').toString()
const index = str.indexOf('%')
if (index >= 0 && str.substring(index + 1) === 'secret_word')
return str.substring(0, index)
else return a
}
function calculator(lng = 'de') {
return `
<div class="calculator">
<div class="calculator__display">0</div>
<div class="calculator__keys">
<button class="key--operator" data-action="add">+</button>
<button class="key--operator" data-action="subtract">-</button>
<button class="key--operator" data-action="multiply">×</button>
<button class="key--operator" data-action="divide">÷</button>
<button>7</button>
<button>8</button>
<button>9</button>
<button>4</button>
<button>5</button>
<button>6</button>
<button>1</button>
<button>2</button>
<button>3</button>
<button>0</button>
<button data-action="decimal">,</button>
<button data-action="clear">AC</button>
<button class="key--equal" data-action="calculate">=</button>
</div>
</div>
<p style="margin-top:32px;" id="submit"><button>${
lng == 'de' ? 'Ergebnis abschicken' : 'Submit result'
}</button></p>
<link rel="stylesheet" href="/chals/chal110.css">
<script src="/chals/chal110.js"></script>
`
}
function story(name, intro, task) {
return `
<style>
.story-container {
display: flex;
justify-content: start;
flex-direction: column-reverse;
align-items:end;
margin-top: -40px;
}
.story-content :last-child {
margin-bottom:0px
}
@media (min-width: 768px) {
.story-container {
flex-direction: row;
align-items:start;
margin-top: 0px;
}
.avatar {
margin-top: -40px
}
}
.avatar {
margin-left: 48px;
padding-bottom: 6px;
}
</style>
<div class="story-container">
<div style="max-width:65ch" class="story-content">
${intro}
${task ? `<hr><br>` : ''}
</div>
<div class="avatar">
${
name
? `<img src="/story/${name.toLowerCase()}.jpg" alt="${name} Avatar" style="height:80px;border-radius:9999px;">
<div style="text-align:center;">${name}</div>`
: ''
}
</div>
</div>
${task ? task : ''}
`
}
const part1 = [
{
id: 1,
pos: { x: 150, y: 140 },
title: { de: 'Start', en: 'Start' },
// date: '2017-03-30',
deps: [],
render: async ({ req, App }) => {
if (req.lng === 'en') {
await App.storage.setItem(
'visit_english_' + new Date().getTime(),
req.user.name
)
}
return {
de: story(
'Kiwi',
`
<div style="display: flex; flex-direction: column; justify-content: center; align-items: center; background-color: #000000; color: white; position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index:1000;" id="intro-div">
<img style="width: 500px; margin-bottom: 60px;" id="image-el" src="/story/intro1.jpg">
<div style="text-align: center; font-size: 1.2rem; max-width: 80%; margin-bottom: 20px; max-width: 65ch;" id="text-div">
Es ist das Jahr 2077. Der Umgang mit Technologie ist streng reguliert. Jedes technische Gerät besitzt einen festgelegten Zweck und darf nicht für andere Zwecke verwendet werden. Du baust eine Kaffeemaschine zu einem Wecker um? Dafür drohen viele Jahre Gefängnis.
</div>
<button style="margin-bottom: 40px;" class="btn btn-success continue-btn" onclick="continueIntro()" id="button-el">
Weiter
</button>
<button style="position: absolute; bottom: 20px; left: 20px; background-color: transparent; color: #888; border: none; font-size: 0.8rem; cursor: pointer;" onClick="skipIntro()" id="skip-button">
Intro überspringen
</button>
</div>
<script src="/powerglitch.min.js"></script>
<script>
var slide = 0
PowerGlitch.glitch('#image-el')
function continueIntro() {
if (slide == 0) {
slide++
document.getElementById('text-div').innerHTML = 'Hacken ist streng verboten - selbst wenn dabei niemanden geschadet wird. Die meisten Menschen sind damit glücklich. Doch es regt sich Widerstand. Die Gruppe Hack The Web und ihre Anführerin Kiwi akzeptieren diesen Einschnitt in die persönliche Freiheit nicht und wollen ein Ende des Technik-Dekrets erwirken.'
document.getElementById('image-el').src = "/story/intro2.jpg"
PowerGlitch.glitch('#image-el')
}
else if (slide == 1) {
slide++
document.getElementById('text-div').innerHTML = 'Dafür braucht die Gruppe kreative HackerInnen - die aber in der Gesellschaft schwer zu finden sind. In einer riskanten Mission befreit Kiwi dich aus einem Jugend-Gefängnis. Sie sieht in dir großes Potenzial und möchte dich zur HackerIn ausbilden.'
document.getElementById('image-el').src = "/story/intro3.jpg"
PowerGlitch.glitch('#image-el')
}
else if (slide == 2) {
slide++
document.getElementById('text-div').innerHTML = 'Dein Abenteuer beginnt hier. Zeig, was du drauf hast!'
document.getElementById('image-el').src = "/story/intro4.jpg"
document.getElementById('button-el').innerHTML = "Loslegen"
document.getElementById('skip-button').style.display = "none"
PowerGlitch.glitch('#image-el').stopGlitch()
}
else if (slide == 3) {
skipIntro()
}
}
function skipIntro() {
document.getElementById('intro-div').style.display = 'none'
}
</script>
<p>Pssssh, pssh, es ist alles gut, es ist alles gut …</p>
<p>Deine Gedanken werden neblig sein. Das ist leider normal nach einer so langen Haft. Es ist traurig wie unsere Gesellschaft mit kreativen jungen Menschen umgeht. Ich kämpfe für eine bessere Zukunft, für eine Zukunft mit weniger Unterdrückung!</p>
<p>Wir können deine Hilfe gut gebrauchen. Doch es ist deine Entscheidung. Wenn du dich bereit fühlst, dann berechne 6 + 4 · 9 und tippe das Ergebnis in das Eingabefeld ein.</p>
`
),
en: `
<p>Welcome to Hack The Web! Here begins your exciting journey through the world of hacking. It will be a journey full of adventures. Challenges from very different areas are waiting for you. You can prove your skills or struggle with them.</p>
<p>Most of the challenges are about finding an answer from the information given. However, this can usually only be found if you look at the task from the right perspective — the perspective of a hacker.</p>
<p>When working on the challenges, all aids are expressly allowed. You may search the Internet, use a calculator or chatbot, make notes with pen and paper... Feel free and use the tools that help you the most when working on the tasks.</p>
<p>Hack The Web started out as a German project. That's the reason why many answers are German words. I hope you enjoy learning some German along the way :)
</p>
${
req.user.RoomId !== null
? `<p>If you have joined a room and are participating in a hacking session: After completing this task, the 30 minutes will start. Within this time, it is your goal to work on as many tasks as possible. Your score for these 30 minutes will be entered into the room's highscore.
</p>`
: ''
}
<p>Are you ready? Then let's go! The answer to this first challenge is the result of 6 + 4 · 9.</p>
`,
}
},
solution: secrets('chal_1'),
},
{
id: 2,
pos: { x: 1245, y: 535 },
title: { de: 'Finger-Code', en: 'Finger code' },
// date: '2017-05-17',
deps: [28, 81],
html: {
de: story(
'Kiwi',
`
<p>Ich bin Hackerin aus Notwendigkeit. Es ist mein Weg, mich auszudrücken in dieser Gesellschaft. Sich mitteilen zu können ist ein wichtiges Bedürfnis. Wir Menschen haben uns dafür so viele unterschiedliche Methoden einfallen lassen. Ich finde das inspirierend.</p>
<p>Finger sind alles, was man zum Sprechen braucht. Deine Antwort findest du in diesen Gesten:</p>
<p><img src="/chals/chal2.gif" alt="fingercode"></p>
<small><a href="https://gebaerdenlernen.ch/fingeralphabet" target="_blank">Quelle</a></small>
`
),
en: `
<p>The content of a message is completely independent of its encoding. You can use Latin letters — or your fingers!
</p>
<p>The answer to this challenge can be found in the following picture:
</p>
<p><img src="/chals/chal2.gif" alt="fingercode"></p>
<small><a href="https://gebaerdenlernen.ch/woerterbuch" target="_blank">Source</a></small>
`,
},
solution: secrets('chal_2'),
},
{
id: 3,
pos: { x: 430, y: 1085 },
title: { de: 'Auf hoher See', en: 'At sea' },
// date: '2017-05-17',
deps: [42, 50],
html: {
de: story(
'Josh',
`
<p>Wie komfortabel heute die Kommunikation geworden ist! Mit einem Messenger kann man weltweit mühelos Nachrichten versenden und empfangen - da vergisst man leicht, dass noch vor wenigen Jahrzehnten die Situation ganz anders aussah. Damals hatte man, zum Beispiel in der Seefahrt, zur Kommunikation nichts mehr als einen Piepston und das Morse-Alphabet!
</p>
<details style="margin-top:16px;margin-bottom:24px;">
<summary>Morse-Alphabet</summary>
<table style="border-collapse: collapse; width: 100%; text-align: center;">
<tr>
<td style="border: 1px solid black; padding: 4px;">A</td>
<td style="border: 1px solid black; padding: 4px;">• −</td>
<td style="border: 1px solid black; padding: 4px;">J</td>
<td style="border: 1px solid black; padding: 4px;">• − − −</td>
<td style="border: 1px solid black; padding: 4px;">S</td>
<td style="border: 1px solid black; padding: 4px;">• • •</td>
</tr>
<tr>
<td style="border: 1px solid black; padding: 4px;">B</td>
<td style="border: 1px solid black; padding: 4px;">− • • •</td>
<td style="border: 1px solid black; padding: 4px;">K</td>
<td style="border: 1px solid black; padding: 4px;">− • −</td>
<td style="border: 1px solid black; padding: 4px;">T</td>
<td style="border: 1px solid black; padding: 4px;">−</td>
</tr>
<tr>
<td style="border: 1px solid black; padding: 4px;">C</td>
<td style="border: 1px solid black; padding: 4px;">− • − •</td>
<td style="border: 1px solid black; padding: 4px;">L</td>
<td style="border: 1px solid black; padding: 4px;">• − • •</td>
<td style="border: 1px solid black; padding: 4px;">U</td>
<td style="border: 1px solid black; padding: 4px;">• • −</td>
</tr>
<tr>
<td style="border: 1px solid black; padding: 4px;">D</td>
<td style="border: 1px solid black; padding: 4px;">− • •</td>
<td style="border: 1px solid black; padding: 4px;">M</td>
<td style="border: 1px solid black; padding: 4px;">− −</td>
<td style="border: 1px solid black; padding: 4px;">V</td>
<td style="border: 1px solid black; padding: 4px;">• • • −</td>
</tr>
<tr>
<td style="border: 1px solid black; padding: 4px;">E</td>
<td style="border: 1px solid black; padding: 4px;">•</td>
<td style="border: 1px solid black; padding: 4px;">N</td>
<td style="border: 1px solid black; padding: 4px;">− •</td>
<td style="border: 1px solid black; padding: 4px;">W</td>
<td style="border: 1px solid black; padding: 4px;">• − −</td>
</tr>
<tr>
<td style="border: 1px solid black; padding: 4px;">F</td>
<td style="border: 1px solid black; padding: 4px;">• • − •</td>
<td style="border: 1px solid black; padding: 4px;">O</td>
<td style="border: 1px solid black; padding: 4px;">− − −</td>
<td style="border: 1px solid black; padding: 4px;">X</td>
<td style="border: 1px solid black; padding: 4px;">− • • −</td>
</tr>
<tr>
<td style="border: 1px solid black; padding: 4px;">G</td>
<td style="border: 1px solid black; padding: 4px;">− − •</td>
<td style="border: 1px solid black; padding: 4px;">P</td>
<td style="border: 1px solid black; padding: 4px;">• − − •</td>
<td style="border: 1px solid black; padding: 4px;">Y</td>
<td style="border: 1px solid black; padding: 4px;">− • − −</td>
</tr>
<tr>
<td style="border: 1px solid black; padding: 4px;">H</td>
<td style="border: 1px solid black; padding: 4px;">• • • •</td>
<td style="border: 1px solid black; padding: 4px;">Q</td>
<td style="border: 1px solid black; padding: 4px;">− − • −</td>
<td style="border: 1px solid black; padding: 4px;">Z</td>
<td style="border: 1px solid black; padding: 4px;">− − • •</td>
</tr>
<tr>
<td style="border: 1px solid black; padding: 4px;">I</td>
<td style="border: 1px solid black; padding: 4px;">• •</td>
<td style="border: 1px solid black; padding: 4px;">R</td>
<td style="border: 1px solid black; padding: 4px;">• − •</td>
<td style="border: 1px solid black; padding: 4px;"> </td>
<td style="border: 1px solid black; padding: 4px;"> </td>
</tr>
</table>
</details>
<p>Das sollte für uns kein Hindernis sein. Höre dir dieses Audio-Datei an. Darin findest du die Antwort zu dieser Aufgabe.
</p>
<audio src="/chals/chal3.wav" controls style="margin-bottom:16px;"></audio>
<p>Dein PC hat keine Lautsprecher? Scanne <a href="/chals/chal3_code.png">diesen QR-Code</a>, um dir <a href ="/chals/chal3.wav">die Datei</a> auf dem Handy anzuhören.</p>
`
),
en: `
<p>How comfortable communication has become today! With WhatsApp and Facebook, you can easily send and receive messages all over the world — it is easy to forget that a hundred years ago the situation was completely different. At that time, for example, in seafaring, one had nothing more than a beep and the Morse alphabet to communicate!
</p>
<p>But that should not be an obstacle for you either. Listen to <a href ="/chals/chal3.wav">this file</a>. In it, you will find the answer to this challenge.
</p>
<audio src="/chals/chal3.wav" controls></audio>
<p>Your PC has no speakers? Scan <a href="/chals/chal3_code.png">this QR code</a> to listen to the file on your mobile phone.</p>
`,
},
solution: secrets('chal_3'),
},
{
id: 4,
pos: { x: 260, y: 380 },
title: { de: 'Codes', en: 'Codes' },
// date: '2017-05-17',
deps: [15, 24],
render: () => {
function renderTable(col1, col2) {
return `
<div class="container" style="margin-top:24px;margin-bottom:24px">
<div class="row">
<div class="col">
<table class="table table-bordered table-hover table-sm table-dark justify-content-between" style="text-align:center;">
<thead>
<tr>
<th scope="col">${col1}</th>
<th scope="col">${col2}</th>
</tr>
</thead>
<tbody>
<tr><td>33</td><td>!</td></tr>
<tr><td>34</td><td>"</td></tr>
<tr><td>35</td><td>#</td></tr>
<tr><td>36</td><td>$</td></tr>
<tr><td>97</td><td>a</td></tr>
<tr><td>98</td><td>b</td></tr>
<tr><td>99</td><td>c</td></tr>
<tr><td>100</td><td>d</td></tr>
<tr><td>101</td><td>e</td></tr>
<tr><td>102</td><td>f</td></tr>
</tbody>
</table>
</div>
<div class="col">
<table class="table table-bordered table-hover table-sm table-dark justify-content-between" style="text-align:center;">
<thead>
<tr>
<th scope="col">${col1}</th>
<th scope="col">${col2}</th>
</tr>
</thead>
<tbody>
<tr><td>103</td><td>g</td></tr>
<tr><td>104</td><td>h</td></tr>
<tr><td>105</td><td>i</td></tr>
<tr><td>106</td><td>j</td></tr>
<tr><td>107</td><td>k</td></tr>
<tr><td>108</td><td>l</td></tr>
<tr><td>109</td><td>m</td></tr>
<tr><td>110</td><td>n</td></tr>
<tr><td>111</td><td>o</td></tr>
<tr><td>112</td><td>p</td></tr>
</tbody>
</table>
</div>
<div class="col">
<table class="table table-bordered table-hover table-sm table-dark justify-content-between" style="text-align:center;">
<thead>
<tr>
<th scope="col">${col1}</th>
<th scope="col">${col2}</th>
</tr>
</thead>
<tbody>
<tr><td>113</td><td>q</td></tr>
<tr><td>114</td><td>r</td></tr>
<tr><td>115</td><td>s</td></tr>
<tr><td>116</td><td>t</td></tr>
<tr><td>117</td><td>u</td></tr>
<tr><td>118</td><td>v</td></tr>
<tr><td>119</td><td>w</td></tr>
<tr><td>120</td><td>x</td></tr>
<tr><td>121</td><td>y</td></tr>
<tr><td>122</td><td>z</td></tr>
</tbody>
</table>
</div>
</div>
</div>
`
}
return {
de: story(
'Josh',
`
<p>Das Technik-Dekret verbietet uns Menschen, die interne Sprache der Computer zu lernen. Den meisten Menschen ist das egal. Aber für mich geht damit etwas sehr wertvolles verloren.</p>
<p>Mache es dir gemütlich, du lernst jetzt das ABC der Informatik, oder besser das 1-2-3.</p>
<p>Schau dir diese Tabelle an. Du findest Zeichen und links daneben ihre Computer-Codes. Ein Beispiel: Das Dollar-Zeichen hat im Computer den Code 36.</p>
${renderTable('Code', 'Zeichen')}
<p>Jetzt bist du dran. Deine Antwort in Codes lautet:</p>
<p>35 115 116 97 98 105 108
</p>
`
),
en: `
<p>You are a brave person! You were not deterred by the cryptic letters in the title of this challenge.
</p>
<p>
Many things in computer science can seem confusing at first glance. Especially if you don't have translation aid. But as soon as you know
where to look for things, they become less foreign.
</p>
<p>
This is also the case with the ASCII code. Because computers can only work with numbers, there is a uniform code for each character.
You can find an excerpt from this in this table.
</p>
${renderTable('Code', 'Character')}
<p>An example: The dollar sign is stored in the computer with the number 36. Voilà, now it's your turn. Your answer in codes is:
</p>
<p>35 115 116 97 98 105 108
</p>
`,
}
},
check: (answer) => {
const trimmed = answer.toLowerCase().replace(/ /g, '').trim()
return {
answer: trimmed,
correct: trimmed === secrets('chal_4'),
}
},
},
{
id: 5,
pos: { x: 300, y: 120 },
title: { de: 'Zitronentinte', en: 'Lemon juice' },
// date: '2017-05-17',
deps: [1],
html: {
de: story(
'Kiwi',
`
<p>Komm, ich möchte dir was zeigen.</p>
<p>Siehst du: Eine Zitrone ist eine Frucht, die man als Zutat in einer Speise verwendet. Das ist ihr vorgesehener Zweck. Doch kreative Menschen haben festgestellt, dass man mit Zitronensaft geheime Nachrichten verfassen kann: Schreibe mit dem Saft einen Text. Auf dem ersten Blick ist der Text für das Auge nicht erkennbar. Doch sobald man das Papier über einer Flamme erhitzt, färbt sich der Zitronensaft und die Nachricht wird sichtbar.</p>
<p>Das ganze funktioniert auch digital. Unten findest du ein "präpariertes" Blatt Papier. Finde die Antwort.</p>
`,
`
<p>--- Hier fängt das Blatt an ---</p>
<p><br><span style="color:#222222;padding-left:150px">Hier ist nichts.</span><br><br><span style="color:#222222">Lalala, das Wetter ist schön</span><br><br><br><br><span style="color:#222222;padding-left:400px">Die Antwort lautet: ${secrets(
'chal_5'
)}</span><br><br>
</p>
<p>--- Hier endet das Blatt ---</p>
`
),
en: `
<p>This challenge here works like writing with lemon juice: You take a fountain pen and dip it in the juice of a freshly squeezed lemon. With it, you write your secret message on a white sheet of paper. Because the juice is transparent, you write "white on white" and another person cannot read the message. The person who receives the message holds the paper over a flame. The heat colors the lemon juice and the message becomes visible.
</p>
<p>The whole thing also works digitally. Below you will find a "prepared" sheet of paper with the answer:
</p>
<br>
<p>--- Here starts the sheet ---</p>
<p><br><span style="color:#222222;padding-left:150px">Here is nothing.</span><br><br><span style="color:#222222">Lalala, the weather is beautiful.</span><br><br><br><br><span style="color:#222222;padding-left:400px">The answer is: ${secrets(
'chal_5'
)}</span><br><br>
</p>
<p>--- Here ends the sheet ---</p>
`,
},
solution: secrets('chal_5'),
},
{
id: 6,
pos: { x: 111, y: 400 },
title: { de: 'HTML', en: 'HTML' },
// date: '2017-05-17',
deps: [24],
html: {
de: story(
'Josh',
`
<p>Höre mir gut zu. Ich zeige dir jetzt eine der wichtigsten Techniken, die du als HackerIn beherrschen solltest.</p>
<p>Wenn du dir eine Website am Computer anschaust, dann siehst du nur einen kleinen Teil der Website. Hinter den Kulissen versteckt sich eine ganze Welt voller Technik. Wie die Noten zu einem Musikstück oder das Drehbuch zu einem Film, gibt es auch den Quelltext zu einer Website.</p>
<p>Dieser Quelltext enthält viele Informationen - und Wissen ist Macht. Doch die Informationen können dich auch von der Menge her überfordern.</p>
<p>Ich biete dir einen Orientierungspunkt. Diesen Kasten wirst du im Quelltext wiederfinden. Innerhalb von diesem Kasten ist deine Antwort versteckt.</p>
<pre>
__________________________________________
| |
|<!-- Die Antwort lautet ${secrets(
'chal_6'
)}. --> |
|________________________________________|
</pre>
<p>Bist du bereit? Dann klicke auf diese Schaltfläche, um den Quelltext dieser Seite zu sehen. Scrolle dort nach unten, um den Kasten zu finden.</p>
<p><button onclick="transform()" class="btn btn-sm btn-primary" style="margin-bottom:24px;">Quelltext anzeigen</button></p>
<script>
function transform() {
const code = document.body.outerHTML
document.body.outerHTML = code.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\\n/g, '<br>').replace(/ /g, ' ');
document.body.style.lineHeight = '1.2'
document.body.style.fontFamily = 'monospace'
document.body.style.marginLeft = '4px'
history.pushState({}, '')
onpopstate = (_) => { window.location.reload() };
}
</script>
`
),
en: `
<p>When you look at a website on your computer, you actually only see a small part of the website. But behind the scenes, there is a whole world full of technology to discover.
</p>
<p>Similar to the notes to a piece of music or the script to a film, there is also the code to a website. And in it, you can find information that is not visible otherwise. In the source code of the website, the answer is visible in this box:</p>
<pre>
__________________________________________
| |
|<!-- The answer is ${secrets(
'chal_6'
)}. --> |
|________________________________________|
</pre>
<p><button onclick="transform()">Show sourcecode</button></p>
<script>
function transform() {
const code = document.body.outerHTML
document.body.outerHTML = code.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\\n/g, '<br>').replace(/ /g, ' ');
document.body.style.lineHeight = '1.2';
document.body.style.fontFamily = 'monospace';
document.body.style.marginLeft = '4px';
history.pushState({}, '');
onpopstate = () => { window.location.reload(); };
}
</script>
`,
},
solution: secrets('chal_6'),
},
{
id: 7,
pos: { x: 130, y: 550 },
title: { en: 'HTML II', de: 'HTML II' },
// date: '2017-05-17',
deps: [6],
html: {
de: story(
'Josh',
`
<p>Du machst gute Fortschritte. Jetzt bist du bereit, auch selbstständig den Quelltext der Seite zu öffnen und dich dort zurechtzufinden.</p>
<p>In den meisten Browser findest du im Kontextmenü (Rechts-Klick) die passende Schaltfläche (<a href="/chals/chal7_hint1.png" target="_blank">Beispiel 1</a> / <a href="/chals/chal7_hint2.png" target="_blank">Beispiel 2</a>). Im Safari geht das über einen <a href="https://www.heise.de/tipps-tricks/Safari-Quelltext-anzeigen-4638280.html" target="_blank">kleinen Umweg</a>. Browser haben sich in den letzten 50 Jahren kaum verändert :)</p>
<p>Die Antwort befindet sich direkt unter dieser Zeile ...
</p>
<!-- ... und lautet ${secrets('chal_7')}. -->
`
),
en: `
<p>This time, too, it takes a look at the source code of the page. However, you have to find the portal yourself. The answer is directly below this line ...
</p>
<!-- ... and is ${secrets('chal_7')}. -->
<p><small><a href="/chals/chal7_hint_en.png" target="_blank">Hint</a></small></p>
`,
},
solution: secrets('chal_7'),
},
{
id: 8,
pos: { x: 720, y: 420 },
title: { de: 'Fleißaufgabe', en: 'Hard work' },
// date: '2017-05-17',
deps: [55, 114],
html: {
de: story(
'Josh',
`
<p>Es gibt Menschen, die gut Kopfrechnen können - und es gibt mich: Jemand, der mehr Spaß daran hat, Muster zu finden und mit denen zu spielen. Kurz gesagt: Ich bin sehr langsam im Kopfrechnen, mir macht Mathe trotzdem Spaß.</p>
<p>Schauen wir uns die Rechnung 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = ? an.</p>
<p>Und ich denke: Hey, die 1 und die 9 passen doch gut zusammen! Und die 3 und die 7 sind auch ein gutes Paar ... so könnte ich die ganze Zeit weitermachen ...</p>
<p>Sei du produktiver. Das Ergebnis der Rechnung ist deine Antwort.</p>
`
),
en: `
<p>Hello, mental arithmetic artist! You solve tasks faster than I can enter them in the calculator.
</p>
<p>You don't believe it? Here is an example: Your answer is the result of 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10.
</p>
<p>Wait a minute, I'll get my calculator quickly ...
</p>
`,
},
solution: secrets('chal_8'),
},
{
id: 9,
pos: { x: 890, y: 370 },
title: { de: 'Fleißaufgabe II', en: 'Hard work II' },
// date: '2017-05-17',
deps: [8],
html: {
de: story(
'Josh',
`
<p>Es gibt gewöhnliche Muster - und es gibt Zahlen, die einfach nur zusammengehören, wie die 1 und die 99, selbst wenn sie an zwei verschiedenen Enden der Rechnung stehen.</p>
<p>Mit einem Blick für Muster hast du 1 + 2 + 3 + 4 + 5 + 95 + 96 + 97 + 98 + 99 schnell berechnet.</p>
`
),
en: `
<p>You are not only good at mental math but also skilled in pattern recognition. With a bit of skill, you can save a lot of work.</p>
<p>Your answer is the result of 1 + 2 + 3 + 4 + 5 + 95 + 96 + 97 + 98 + 99.</p>
`,
},
solution: secrets('chal_9'),
},
{
id: 10,
pos: { x: 990, y: 440 },
title: { de: 'Fleißaufgabe III', en: 'Hard work III' },
// date: '2017-05-18',
deps: [9],
html: {
de: story(
'Josh',
`
<p>Es ist am Ende dir überlassen, wie du rechnest, sei es im Kopf, mit dem Computer oder durch geschicktes Zusammenfassen. Am Ende zählt das Ergebnis und jeder Weg dahin hat einen Sinn.</p>
<p>Berechne das Ergebnis von 1 + 2 + 3 + ... + 97 + 98 + 99 + 100.
</p>
`
),
en: `
<p>Mental math genius, skilled - and with a good imagination. With that, you solve complex problems in an elegant manner.</p>
<p>This time, calculate the result of 1 + 2 + 3 + ... + 98 + 99 + 100.</p>
`,
},
solution: secrets('chal_10'),
},
/*{
id: 11,
pos: { x: 100, y: 400 },
title: 'Fremdwährung',
deps: [18],
html: `
<p>Das Währungssystem in Land Compedia ist anders aufgebaut als wir es so gewohnt sind. Es gibt dort nur Münzen und diese haben die Werte 1, 2, 4, 8, 16, 32, 64, 128, 256 und 512. Das sind die ersten 10 Zweierpotenzen.
</p>
<p>Damit die Einwohner nicht so viel Geld mit sich schleppen müssen, dürfen Preise nur zwischen 1 und 1023 liegen. Zu hohe Preise und Dezimalbrüche sind verboten (und werden per Überweisung bezahlt).
</p>
<p>Das Interessante an diesem System: Jeder Einwohner kann mit einem Satz an Münzen (also von jedem Wert genau eine Münze, insgesamt 10 Münzen) jeden Preis zwischen 1 und 1023 bezahlen. Wir wollen das mal überprüfen: Den Preis von 100 können wir mit den drei Münzen 64, 32 und 4 bezahlen. Klappt.
</p>
<p>Die Frage lautet: Wie bezahlt ein Compedianer den Preis 85?
</p>
<p>Gib die einzelnen Münzwerte von groß nach klein mit Leerzeichen getrennt an (z.B. <em>64 32 4</em>).
</p>
`,
solution: '64 16 4 1',
},*/
/*{
id: 12,
pos: { x: 100, y: 530 },
title: 'Fremdwährung II',
deps: [11],
html: `
<p>Wie bezahlt ein Compedianer in diesem System den Preis 805?
</p>
`,
solution: '512 256 32 4 1',
},*/
/*{
id: 13,
pos: { x: 130, y: 670 },
title: 'Fremdwährung III',
deps: [12],
html: `
<p>Die Compedianer nutzen dieses System der Münzen auch für ihre Zahlen, allerdings in einer abgewandelten Form: Die Münzwerte werden durch die Position der Ziffern bestimmt und diese steigt von rechts nach links auf. Es gibt nur zwei Ziffern. Die Null bedeutet, dass diese Münze nicht benutzt wird, die Eins bedeutet, dass sie benutzt wird. Hier sehen wir ein Beispiel für die Zahl 100110:
</p>
<p><img src="/chals/chal13.png"></p>
<p>Verwendet werden die Werte 32, 4 und 2 und damit ergibt sich insgesamt die Zahl 38.</p><p>Die Frage lautet nun: Welche Zahl steckt hinter der Folge 110001100100?
</p>
`,
solution: '3172',
},*/
/*{
id: 14,
pos: { x: 150, y: 820 },
title: 'Fremdwährung IV',
deps: [13],
html: `
<p>Die Compedianer haben damit ihr Zahlensystem auf das sog. Binärsystem umgestellt. Man könnte fast meinen, dass ein Compedianer den Computer erfunden hätte - denn Computer verstehen auch nur Binärzahlen.
</p>
<p>Für uns Menschen gibt es noch eine Schwierigkeit: Binärzahlen sind oft sehr lang. Um sie kürzer darzustellen, kann man sie in 4er-Packs zerlegen und mit folgender Tabelle übersetzen:
</p>
<p>0000 = 0<br>0001 = 1<br>0010 = 2<br>0011 = 3<br>0100 = 4<br>0101 = 5<br>0110 = 6<br>0111 = 7<br>1000 = 8<br>1001 = 9<br>1010 = A<br>1011 = B<br>1100 = C<br>1101 = D<br>1110 = E<br>1111 = F
</p>
<p>Die Tabelle ist eigentlich sehr systematisch: Auf der linken Seite sind die Zahlen von 0 bis 15 dargestellt und rechts die passende Zahl oder ein Buchstabe. Die Binärzahl 10100011 wird dann mit A3 abgekürzt. Diese Schreibweise wird Hexadezimalsystem genannt.
</p>
<p>Wie lautet nun die Binärzahl 11111010011000000100 in hexadezimaler Schreibweise?
</p>
`,
solution: 'fa604',
},*/
{
id: 15,
pos: { x: 270, y: 220 },
title: { de: 'Benutzername', en: 'Username' },
// date: '2017-05-18',
deps: [1],
html: {
de: story(
'Kiwi',
`
<p>Die Menschen heute haben verlernt, auf neue, unbekannte Situationen zu reagieren. Wenn etwas nicht so funktioniert, wie sie es erwarten, dann geben sie schnell auf.</p>
<p>Die Antwort auf diese Aufgabe ist dein Benutzername. Ganz einfach erstmal. Doch eine kleine Sache wird verändert. Kommst du damit klar?</p>
`
),
en: `
<p>The answer to this challenge is simply your username. However, it may be that your input gets a little mixed up when you submit it. Can you find out what you have to enter?
</p>
`,
},
check: (answer, { req }) => {
const reversed = stringreverse(answer)
return {
answer: reversed,
correct: reversed === req.user.name,
}
},
},
{
id: 16,
pos: { x: 340, y: 320 },
title: { de: 'Punktzahl', en: 'Score' },
// date: '2017-05-18',
deps: [15, 24],
html: {
de: story(
'Kiwi',
`
<p>Haben dir Bex und Josh schon was gezeigt? Ich hab den beiden gesagt, sie sollen auch ihr Wissen weitergeben. Man kann von jedem Mensch was Neues lernen.</p>
<p>Die Antwort auf diese Aufgabe ist deine aktuelle Punktzahl. Ähnlich wie zuvor gerät deine Eingabe etwas durcheinander.</p>
`
),
en: `
<p>The answer to this task is your current score. Similar to before, your input is a bit jumbled.</p>
`,
},
check: (answer, { req }) => {
const normalizedAnswer = answer.replace(/[‐−–—]/, '-')
const input = -parseInt(normalizedAnswer)
return {
answer: isNaN(input) ? answer : input.toString(),
correct: input === req.user.score,
}
},
},
{
id: 17,
pos: { x: 745, y: 310 },
title: { de: 'Slogan', en: 'Slogan' },
// date: '2017-05-18',
deps: [55, 66, 114],
html: {
de: story(
'Bex',
`
<p>Ich wollte Kiwi vorschlagen, dass wir uns als Gruppe einen Slogan zulegen. Mein Vorschlag ist "Beweise dein Können!", weil mich das am meisten mit Hack The Web verbindet. Kiwi ist davon noch nicht ganz überzeugt, sie meint das wäre zu wenig politisch oder so ...</p>
<p>Hey, hast du mir überhaupt zugehört? Deine Antwort ist mein Vorschlag für einen Slogan. Bei der Eingabe gerät aber etwas durcheinander.</p>
`
),
en: `
<p>The answer is the slogan of Hack The Web. Your input is jumbled again.</p>
`,
},
check: (answer, { req }) => {
const text =
req.lng == 'de' ? 'Beweise dein Können!' : 'Prove your skill.'
const input = answer
.replace(/[^a-zA-ZäöüÄÖÜß ]/g, '')
.trim()
.split(' ')
input.reverse()
const str = input.join(' ').toLowerCase()
return {
answer: str,
correct: str === text.replace(/[^a-zA-ZäüöÄÜÖß ]/g, '').toLowerCase(),
}
},
},
{
id: 18,
pos: { x: 930, y: 520 },
title: { de: 'Verschiebung', en: 'ROT13' },
// date: '2017-05-18',
deps: [8, 77],
html: {
de: story(
'Josh',
`
<p>Was ich dir hier zeige, ist schon Jahrtausende alt. Es ist eine Verschlüsslung aus einer Zeit, wo es keine Computer oder ähnliche Maschinen gab. Lesen und Schreiben war nur einer kleinen Gruppe vorbehalten. Schriftliche Texte waren an sich schon eine Geheimsprache.</p>
<p>Doch selbst dann wollte man vielleicht eine Nachricht im Geheimen übermitteln. Eine pragmatische Lösung bestand darin, die Buchstaben im Alphabet zu verschieben. Es ist eine Verschlüsslung, die für die damalige Zeit ausgereicht hat. Mit dem Blick von heute bietet sie keine ernsthafte Sicherheit mehr.</p>
<p>Überzeuge dich selbst und entschlüssle die Nachricht. Ziehe den Slider, um die Buchstaben im Alphabet zu verschieben.</p>
`,
`
<p style="word-wrap:break-word" class="my-4" id="cipher">
</p>
<p>Verschiebung: <span id="display">0</span></p>
<input id="slider" type="range" min="0" max="26" step="1" style="width:500px" value="0" onchange="change()" oninput="change()"/>
<script>
const message = 'fhcre qh unfg qra grkg resbytervpu ragfpuyhrffryg nyf orybuahat reunryfg qh aha qvr nagjbeg haq fvr ynhgrg fcvrtryovyq'
const slider = document.getElementById('slider')
const cipher = document.getElementById('cipher')
function translate(n) {
cipher.innerHTML = message.split('').map(c => {
if (c === ' ') return c
return String.fromCharCode(((c.charCodeAt(0) - 97 + n) % 26) + 97)
}).join('')
}
function change() {
translate(parseInt(slider.value))
document.getElementById('display').innerHTML = slider.value
}
change()
</script>
`
),
en: `
<p>You have received an encrypted message! It looks like complete nonsense. Your hacker's eye is in demand! You look wonderful when you think hard.
</p>
<p>Drag the slider to shift the letters in the alphabet.</p>
<p style="word-wrap:break-word" class="my-4" id="cipher">
</p>
<input id="slider" type="range" min="0" max="26" step="1" style="width:500px" value="0" onchange="change()" oninput="change()"/>
<script>
// noinspection SpellCheckingInspection
const message = 'terng lbh unir fhpprffshyyl qrpbqrq gur grkg nf n erjneq lbh abj trg gur nafjre naq vg vf fcvrtryovyq (gur trezna jbeq sbe zveebe vzntr)'
const slider = document.getElementById('slider')
const cipher = document.getElementById('cipher')
function translate(n) {
cipher.innerHTML = message.split('').map(c => {
if (c === ' ' || c === '(' || c === ')') return c
return String.fromCharCode(((c.charCodeAt(0) - 97 + n) % 26) + 97)
}).join('')
}
function change() {
translate(parseInt(slider.value))
}
change()
</script>
`,
},
solution: secrets('chal_18'),
},
/*{
id: 19,
pos: { x: 310, y: 460 },
title: 'Cäsar',
date: '2017-05-18',
deps: [18],
html: `
<p>Du hast wieder eine verschlüsselte Nachricht erhalten:
</p>
<p>Yottss</p>
<p>Diesmal wurde die Nachricht mit dem Cäsarcode verschlüsselt. Bei diesem Code werden die Buchstaben um eine bestimmte Anzahl im Alphabet verschoben. Wenn man zum Beispiel <strong>Maus</strong> nimmt und die Buchstaben um eins weiter verschiebt, kommt der geheime Text <strong>Nbvt</strong> heraus.
</p>