initial commit

This commit is contained in:
Robbe De Greef 2022-11-24 18:03:20 +01:00
commit 9dee21c349
148 changed files with 37866 additions and 0 deletions

287
.gitignore vendored Normal file
View File

@ -0,0 +1,287 @@
# Created by https://www.toptal.com/developers/gitignore/api/node,macos,python
# Edit at https://www.toptal.com/developers/gitignore?templates=node,macos,python
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
.env*.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
pytestdebug.log
# Translations
*.mo
*.pot
# Django stuff:
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
doc/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
pythonenv*
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# profiling data
.prof
# End of https://www.toptal.com/developers/gitignore/api/node,macos,python
/blinky/code/blinky/build

View File

View File

@ -0,0 +1,18 @@
# Title
Fighting scientists
# Description
A war has occured in the science faculty, the physicists and NLP-scientists had an argument about frequencies and the order of magnitude of them in x-rays.
Because they like to taunt each other someone has deleted all code and wrote 2 txt's after each other so it's very clear what type their shared document had.
Besides this I do like watching people argue and lose there minds, I also like the first order Taylor expansion of the sine function, just the abilty to say sin(x) = x.
It's remarkable no?
# files
swt.txt.txt
# deployment
n/a just open a scripting language that's able to open txt files
# type
Steganography

View File

@ -0,0 +1,17 @@
# Fighting Scientists
# Description
A war has occured in the science faculty, the physicists and NLP-scientists had an argument about frequencies and the order of magnitude of them in x-rays.
Because they like to taunt each other someone has deleted all code and wrote 2 txt's after each other so it's very clear what type their shared document had.
Besides this I do like watching people argue and lose there minds, I also like the first order Taylor expansion of the sine function, just the abilty to say sin(x) = x.
It's remarkable no?
# Files
swt.txt.txt
# How to solve
Easy, just use a tool that counts every character, if you then print every letter in descending order the flag will appear.
# flag
IGCTF{EOAN}

File diff suppressed because one or more lines are too long

4
README.md Normal file
View File

@ -0,0 +1,4 @@
# IGCTF writeups 2020-2021
You can find all the challenges here in these folders. Each challenge folder should contain a SOLUTION.md that contains a (possible) solution for the challenge.
Have fun!

38
Risky-Business/README.md Normal file
View File

@ -0,0 +1,38 @@
== Title ==
Risky Business
== Description ==
Warning: Difficult challenge.
I found a RISC-V emulator lying around. I heard that there's a flag in there somewhere...
To help you get started, I'll give you an ELF binary that runs on the emulator. It won't help you find the flag, but it will help you figure out what the binaries look like.
== Flag ==
IGCTF{RISC-V_is_amazing_and_so_are_you}
== Files ==
Participants should receive the riscv_sim_RV64 and the example file.
== Deployment ==
/
== Solution ==
First of all, a command that lets you compile riscv assembly code for the emulator:
Of course, clang needs to be compiled with support for riscv.
clang -nostdlib -Ttext 0x80000000 --target=riscv64-unknown-freebsd -march=rv64g -mno-relax -o binary source.S
Before we move on to writing some code, we can have a look at the emulator in Ghidra.
Searching for strings will allow us to find a number of strings called FLAG_PART1, FLAG_PART2, etc.
Upon further inspection, these variables will contain (contiguous) addresses of parts of the flag starting at 0xd000.
These raw addresses are not addressable. There is still an offset missing. Searching through the address space in assembly, or closely inspecting the decompiled emulator should yield the correct offset, namely 0x2000000 (start of CLINT).
Writing some assembly code that reads these addresses into registers should print the flag in hexadecimal format in the log of the emulator.
An example is given in the solution/ directory. This directory also contains some macros that take care of the initialisation of the emulator. They can be found online, for example here: https://github.com/riscv/riscv-test-env/blob/master/p/riscv_test.h
The other macro file can be found in the same repository.
Compiling and running the provided code will load the flag in register x12. Grepping on "x12" through the logs of the emulator will yield the flag in hex.

BIN
Risky-Business/example Executable file

Binary file not shown.

BIN
Risky-Business/riscv_sim_RV64 Executable file

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
#include "test_macros.h"
RVTEST_RV64U
RVTEST_CODE_BEGIN
li x10, 0x2000000
li x11, 0xd000
add x10, x10, x11
ld x12, (x10)
addi x10, x10, 8
ld x12, (x10)
addi x10, x10, 8
ld x12, (x10)
addi x10, x10, 8
ld x12, (x10)
addi x10, x10, 8
ld x12, (x10)
RVTEST_PASS
RVTEST_CODE_END
.align 6; .global tohost; tohost: .dword 0;

View File

@ -0,0 +1,267 @@
#ifndef _ENV_PHYSICAL_SINGLE_CORE_H
#define _ENV_PHYSICAL_SINGLE_CORE_H
#include "encoding.h"
//-----------------------------------------------------------------------
// Begin Macro
//-----------------------------------------------------------------------
#define RVTEST_RV64U \
.macro init; \
.endm
#define RVTEST_RV64UF \
.macro init; \
RVTEST_FP_ENABLE; \
.endm
#define RVTEST_RV64UV \
.macro init; \
RVTEST_VECTOR_ENABLE; \
.endm
#define RVTEST_RV32U \
.macro init; \
.endm
#define RVTEST_RV32UF \
.macro init; \
RVTEST_FP_ENABLE; \
.endm
#define RVTEST_RV32UV \
.macro init; \
RVTEST_VECTOR_ENABLE; \
.endm
#define RVTEST_RV64M \
.macro init; \
RVTEST_ENABLE_MACHINE; \
.endm
#define RVTEST_RV64S \
.macro init; \
RVTEST_ENABLE_SUPERVISOR; \
.endm
#define RVTEST_RV32M \
.macro init; \
RVTEST_ENABLE_MACHINE; \
.endm
#define RVTEST_RV32S \
.macro init; \
RVTEST_ENABLE_SUPERVISOR; \
.endm
#if __riscv_xlen == 64
# define CHECK_XLEN li a0, 1; slli a0, a0, 31; bgez a0, 1f; RVTEST_PASS; 1:
#else
# define CHECK_XLEN li a0, 1; slli a0, a0, 31; bltz a0, 1f; RVTEST_PASS; 1:
#endif
#define INIT_XREG \
li x1, 0; \
li x2, 0; \
li x3, 0; \
li x4, 0; \
li x5, 0; \
li x6, 0; \
li x7, 0; \
li x8, 0; \
li x9, 0; \
li x10, 0; \
li x11, 0; \
li x12, 0; \
li x13, 0; \
li x14, 0; \
li x15, 0; \
li x16, 0; \
li x17, 0; \
li x18, 0; \
li x19, 0; \
li x20, 0; \
li x21, 0; \
li x22, 0; \
li x23, 0; \
li x24, 0; \
li x25, 0; \
li x26, 0; \
li x27, 0; \
li x28, 0; \
li x29, 0; \
li x30, 0; \
li x31, 0;
#define INIT_PMP \
la t0, 1f; \
csrw mtvec, t0; \
/* Set up a PMP to permit all accesses */ \
li t0, (1 << (31 + (__riscv_xlen / 64) * (53 - 31))) - 1; \
csrw pmpaddr0, t0; \
li t0, PMP_NAPOT | PMP_R | PMP_W | PMP_X; \
csrw pmpcfg0, t0; \
.align 2; \
1:
#define INIT_SATP \
la t0, 1f; \
csrw mtvec, t0; \
csrwi satp, 0; \
.align 2; \
1:
#define DELEGATE_NO_TRAPS \
csrwi mie, 0; \
la t0, 1f; \
csrw mtvec, t0; \
csrwi medeleg, 0; \
csrwi mideleg, 0; \
.align 2; \
1:
#define RVTEST_ENABLE_SUPERVISOR \
li a0, MSTATUS_MPP & (MSTATUS_MPP >> 1); \
csrs mstatus, a0; \
li a0, SIP_SSIP | SIP_STIP; \
csrs mideleg, a0; \
#define RVTEST_ENABLE_MACHINE \
li a0, MSTATUS_MPP; \
csrs mstatus, a0; \
#define RVTEST_FP_ENABLE \
li a0, MSTATUS_FS & (MSTATUS_FS >> 1); \
csrs mstatus, a0; \
csrwi fcsr, 0
#define RVTEST_VECTOR_ENABLE \
li a0, (MSTATUS_VS & (MSTATUS_VS >> 1)) | \
(MSTATUS_FS & (MSTATUS_FS >> 1)); \
csrs mstatus, a0; \
csrwi fcsr, 0; \
csrwi vcsr, 0;
#define RISCV_MULTICORE_DISABLE \
csrr a0, mhartid; \
1: bnez a0, 1b
#define EXTRA_TVEC_USER
#define EXTRA_TVEC_MACHINE
#define EXTRA_INIT
#define EXTRA_INIT_TIMER
#define INTERRUPT_HANDLER j other_exception /* No interrupts should occur */
#define RVTEST_CODE_BEGIN \
.section .text.init; \
.align 6; \
.weak stvec_handler; \
.weak mtvec_handler; \
.globl _start; \
_start: \
/* reset vector */ \
j reset_vector; \
.align 2; \
trap_vector: \
/* test whether the test came from pass/fail */ \
csrr t5, mcause; \
li t6, CAUSE_USER_ECALL; \
beq t5, t6, write_tohost; \
li t6, CAUSE_SUPERVISOR_ECALL; \
beq t5, t6, write_tohost; \
li t6, CAUSE_MACHINE_ECALL; \
beq t5, t6, write_tohost; \
/* if an mtvec_handler is defined, jump to it */ \
la t5, mtvec_handler; \
beqz t5, 1f; \
jr t5; \
/* was it an interrupt or an exception? */ \
1: csrr t5, mcause; \
bgez t5, handle_exception; \
INTERRUPT_HANDLER; \
handle_exception: \
/* we don't know how to handle whatever the exception was */ \
other_exception: \
/* some unhandlable exception occurred */ \
1: ori TESTNUM, TESTNUM, 1337; \
write_tohost: \
sw TESTNUM, tohost, t5; \
j write_tohost; \
reset_vector: \
INIT_XREG; \
RISCV_MULTICORE_DISABLE; \
INIT_SATP; \
INIT_PMP; \
DELEGATE_NO_TRAPS; \
li TESTNUM, 0; \
la t0, trap_vector; \
csrw mtvec, t0; \
CHECK_XLEN; \
/* if an stvec_handler is defined, delegate exceptions to it */ \
la t0, stvec_handler; \
beqz t0, 1f; \
csrw stvec, t0; \
li t0, (1 << CAUSE_LOAD_PAGE_FAULT) | \
(1 << CAUSE_STORE_PAGE_FAULT) | \
(1 << CAUSE_FETCH_PAGE_FAULT) | \
(1 << CAUSE_MISALIGNED_FETCH) | \
(1 << CAUSE_USER_ECALL) | \
(1 << CAUSE_BREAKPOINT); \
csrw medeleg, t0; \
1: csrwi mstatus, 0; \
init; \
EXTRA_INIT; \
EXTRA_INIT_TIMER; \
la t0, 1f; \
csrw mepc, t0; \
csrr a0, mhartid; \
mret; \
1:
//-----------------------------------------------------------------------
// End Macro
//-----------------------------------------------------------------------
#define RVTEST_CODE_END \
unimp
//-----------------------------------------------------------------------
// Pass/Fail Macro
//-----------------------------------------------------------------------
#define RVTEST_PASS \
fence; \
li TESTNUM, 1; \
li a7, 93; \
li a0, 0; \
ecall
#define TESTNUM gp
#define RVTEST_FAIL \
fence; \
1: beqz TESTNUM, 1b; \
sll TESTNUM, TESTNUM, 1; \
or TESTNUM, TESTNUM, 1; \
li a7, 93; \
addi a0, TESTNUM, 0; \
ecall
//-----------------------------------------------------------------------
// Data Section Macro
//-----------------------------------------------------------------------
#define EXTRA_DATA
#define RVTEST_DATA_BEGIN \
EXTRA_DATA \
.pushsection .tohost,"aw",@progbits; \
.align 6; .global tohost; tohost: .dword 0; \
.align 6; .global fromhost; fromhost: .dword 0; \
.popsection; \
.align 4; .global begin_signature; begin_signature:
#define RVTEST_DATA_END .align 4; .global end_signature; end_signature:
#endif

8
WIP_Challenges Normal file
View File

@ -0,0 +1,8 @@
Vermeld hier challenges waar je momenteel aan bezig bent, tot welke categorie
ze behoren, hoe ze moeten opgelost worden en moeilijk je zelf schat dat die
challenge zal zijn.
- Een serie van Scheme challenges, nog niet (helemaal) uitgewerkt (Robin)
- Een reeks (eenvoudige) webchallenges (Benj)
- Een encription challenge zoals die van vorig jaar (Decrypt Me) maar met een nieuwe sleutel (Benj)

23
ancient_stone/README.md Normal file
View File

@ -0,0 +1,23 @@
== Title ==
Ancient Stone
== Description ==
On my way to Munster, during my trip to Ireland, I found some weird markings on a stone laying on the side of the road. Grooves in the stone seemed to try to tell me a message. Half an hour of decoding later, and I did not manage to figure out any meaning. As I was very intrigued by this stone, I made note of the markings on a piece of paper I had brought along. Might you help me decipher the ancient knowledge given by the markings?
Note: This challenge does not follow the standard flag format, however the flag still starts with "IG".
== Flag ==
IGTOBEORNOTTOBE
== Files ==
Participants should receive the scribbles.png file.
== Deployment ==
/
== Solution/Writeup ==
This markings are an ancient writing system called Ogham.
The word "Ogham" was spelled out by the first letter of each sentence of the description. Munster and Ireland were also hints, since the system originated from there.
The following image can be used to decode the message.
https://en.wikipedia.org/wiki/Ogham#/media/File:All_Ogham_letters_including_Forfeda_-_%C3%9Cbersicht_aller_Ogham-Zeichen_einschlie%C3%9Flich_Forfeda.jpg

17
ancient_stone/bliep.md Normal file
View File

@ -0,0 +1,17 @@
== Title ==
Ancient Stone
== Description ==
On my way to Munster, during my trip to Ireland, I found some weird markings on a stone laying on the side of the road. Grooves in the stone seemed to try to tell me a message. Half an hour of decoding later, and I did not manage to figure out any meaning. As I was very intrigued by this stone, I made note of the markings on a piece of paper I had brought along. Might you help me decipher the ancient knowledge given by the markings?
Note: This challenge does not follow the standard flag format, however the flag still starts with "IG".
== Files ==
Participants should receive the scribbles.png file.
== Deployment ==
/
40 punten
Gewoon de foto in het bestand decoderen. Zou niet zo moeilijk moeten zijn, description goed lezen.

BIN
ancient_stone/scribbles.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

70
break_the_gate/1.php Normal file
View File

@ -0,0 +1,70 @@
<?php
require('flags.php');
if(!isset($_COOKIE['currentLevel'])) {
setcookie("currentLevel", "Flags_will_appear_here_when_you_complete_a_level...", time()+24*60*60);
}
switch ($_COOKIE['currentLevel']) {
case $flag_1:
header('Location: 2.php');
break;
case $flag_2:
header('Location: 3.php');
break;
case $flag_3:
header('Location: 4.php');
break;
case $flag_4:
header('Location: 5.php');
break;
case $flag_5:
header('Location: final.php');
break;
default:
break;
}
?>
<!DOCTYPE html>
<html>
<head>
<title>Level 1</title>
<meta charset="UTF-8">
<meta name="author" content="Benjamin Ver">
<link rel="stylesheet" type="text/css" href="css/jquery-ui.css">
<link rel="stylesheet" type="text/css" href="css/normalize.css">
<link rel="stylesheet" type="text/css" href="css/main.css">
<script type="text/javascript" src="script/jquery.js"></script>
<script type="text/javascript" src="script/jquery-ui.js"></script>
<script type="text/javascript" src="script/main.js"></script>
<script type="text/javascript" src="script/1.js"></script>
</head>
<body>
<div class="front">
<div class="lock intel">
<img src="img/lock_locked.jpg">
</div>
<!-- username: admin, password: admin -->
<table class="unlockpad intel">
<tr>
<td class='formInfo'>Username:</td>
<td><input type="text" name="user" id="inp_user"></td>
</tr>
<tr>
<td class='formInfo'>Password:</td>
<td><input type="password" name="passw" id="inp_passw"></td>
</tr>
<tr>
<td colspan='2'>
<button id='submit'>Give it a shot...</button>
</td>
</tr>
</table>
</div>
<div class="half left"></div>
<div class="half right"></div>
</body>
</html>

73
break_the_gate/2.php Normal file
View File

@ -0,0 +1,73 @@
<?php
require('flags.php');
if(!isset($_COOKIE['currentLevel'])) {
setcookie("currentLevel", "Flags_will_appear_here_when_you_complete_a_level...", time()+24*60*60);
}
switch ($_COOKIE['currentLevel']) {
case $flag_1:
break;
case $flag_2:
header('Location: 3.php');
break;
case $flag_3:
header('Location: 4.php');
break;
case $flag_4:
header('Location: 5.php');
break;
case $flag_5:
header('Location: final.php');
break;
default:
header('Location: 1.php');
break;
}
?>
<!DOCTYPE html>
<html>
<head>
<title>Level 2</title>
<meta charset="UTF-8">
<meta name="author" content="Benjamin Ver">
<link rel="stylesheet" type="text/css" href="css/jquery-ui.css">
<link rel="stylesheet" type="text/css" href="css/normalize.css">
<link rel="stylesheet" type="text/css" href="css/main.css">
<script type="text/javascript" src="script/jquery.js"></script>
<script type="text/javascript" src="script/jquery-ui.js"></script>
<script type="text/javascript" src="script/main.js"></script>
<script type="text/javascript"> var userDb = {}; </script>
<script type="text/javascript" src="script/2.js"></script>
<script type="text/javascript" src="script/ssdb.js"></script>
</head>
<body>
<div class="front">
<div class="lock intel">
<img src="img/lock_locked.jpg">
</div>
<table class="unlockpad intel">
<tr>
<td class='formInfo'>Username:</td>
<td><input type="text" name="user" id="inp_user"></td>
</tr>
<tr>
<td class='formInfo'>Password:</td>
<td><input type="password" name="passw" id="inp_passw"></td>
</tr>
<tr>
<td colspan='2'>
<button id='submit'>Give it a shot...</button>
</td>
</tr>
</table>
</div>
<div class="half left"></div>
<div class="half right"></div>
</body>
</html>

70
break_the_gate/3.php Normal file
View File

@ -0,0 +1,70 @@
<?php
require('flags.php');
if(!isset($_COOKIE['currentLevel'])) {
setcookie("currentLevel", "Flags_will_appear_here_when_you_complete_a_level...", time()+24*60*60);
}
switch ($_COOKIE['currentLevel']) {
case $flag_1:
header('Location: 2.php');
break;
case $flag_2:
break;
case $flag_3:
header('Location: 4.php');
break;
case $flag_4:
header('Location: 5.php');
break;
case $flag_5:
header('Location: final.php');
break;
default:
header('Location: 1.php');
break;
}
?>
<!DOCTYPE html>
<html>
<head>
<title>Level 3</title>
<meta charset="UTF-8">
<meta name="author" content="Benjamin Ver">
<link rel="stylesheet" type="text/css" href="css/jquery-ui.css">
<link rel="stylesheet" type="text/css" href="css/normalize.css">
<link rel="stylesheet" type="text/css" href="css/main.css">
<script type="text/javascript" src="script/jquery.js"></script>
<script type="text/javascript" src="script/jquery-ui.js"></script>
<script type="text/javascript" src="script/main.js"></script>
<script type="text/javascript" src="script/1.js"></script>
</head>
<body>
<div class="front">
<div class="lock intel">
<img src="img/lock_locked.jpg">
</div>
<table class="unlockpad intel">
<tr>
<td class='formInfo'>Username:</td>
<td><input type="text" name="user" id="inp_user"></td>
</tr>
<tr>
<td class='formInfo'>Password:</td>
<td><input type="password" name="passw" id="inp_passw"></td>
</tr>
<tr>
<td colspan='2'>
<button id='submit'>Give it a shot...</button>
</td>
</tr>
</table>
</div>
<div class="half left"></div>
<div class="half right"></div>
</body>
</html>

109
break_the_gate/4.php Normal file
View File

@ -0,0 +1,109 @@
<?php
require('flags.php');
if(!isset($_COOKIE['currentLevel'])) {
setcookie("currentLevel", "Flags_will_appear_here_when_you_complete_a_level...", time()+24*60*60);
}
switch ($_COOKIE['currentLevel']) {
case $flag_1:
header('Location: 2.php');
break;
case $flag_2:
header('Location: 3.php');
break;
case $flag_3:
break;
case $flag_4:
header('Location: 5.php');
break;
case $flag_5:
header('Location: final.php');
break;
default:
header('Location: 1.php');
break;
}
$fa = 0;
if (isset($_GET['try'])) {
$fa = intval($_GET['try']);
}
$fa100 = floor($fa / 100);
$fa -= 100 * $fa100;
$fa10 = floor($fa / 10);
$fa -= 10 * $fa10;
$fa1 = $fa;
?>
<!DOCTYPE html>
<html>
<head>
<title>Level 4</title>
<meta charset="UTF-8">
<meta name="author" content="Benjamin Ver">
<link rel="stylesheet" type="text/css" href="css/jquery-ui.css">
<link rel="stylesheet" type="text/css" href="css/normalize.css">
<link rel="stylesheet" type="text/css" href="css/main.css">
<link rel="stylesheet" type="text/css" href="css/pl.css">
<?php if (isset($_GET['try']) && $_GET['try'] != 732) { echo "<style> .w {color: red;} </style>"; } ?>
<script type="text/javascript" src="script/jquery.js"></script>
<script type="text/javascript" src="script/jquery-ui.js"></script>
<script type="text/javascript" src="script/main.js"></script>
<script type="text/javascript" src="script/pl.js"></script>
<script type="text/javascript">
$(document).ready(function(){
<?php
require('flags.php');
if ($_GET['try'] == 732) {
echo 'document.cookie = "currentLevel=' . $flag_4 . '"' . ";\n";
echo 'goNext();';
} elseif (isset($_GET['try'])) {
echo 'errorAnimation();';
}
echo "\n";
?>
})
</script>
</head>
<body>
<div class="front">
<div class="lock intel">
<img src="img/lock_locked.jpg">
</div>
<table class="unlockpad intel">
<tr>
<td><div class='triangle up' id='100up'></div></td>
<td><div class='triangle up' id='10up'></div></td>
<td><div class='triangle up' id='1up'></div></td>
</tr>
<tr>
<td class='digit w' id='num100'><?php echo $fa100; ?></td>
<td class='digit w' id='num10'><?php echo $fa10; ?></td>
<td class='digit w' id='num1'><?php echo $fa1; ?></td>
</tr>
<tr>
<td><div class='triangle down' id='100down'></div></td>
<td><div class='triangle down' id='10down'></div></td>
<td><div class='triangle down' id='1down'></div></td>
</tr>
</table>
</div>
<div class="half left"></div>
<div class="half right"></div>
<form action='4.php' method='GET'>
<input type='hidden' name='try' id='try'>
</form>
</body>
</html>

70
break_the_gate/5.php Normal file
View File

@ -0,0 +1,70 @@
<?php
require('flags.php');
if(!isset($_COOKIE['currentLevel'])) {
setcookie("currentLevel", "Flags_will_appear_here_when_you_complete_a_level...", time()+24*60*60);
}
switch ($_COOKIE['currentLevel']) {
case $flag_1:
header('Location: 2.php');
break;
case $flag_2:
header('Location: 3.php');
break;
case $flag_3:
header('Location: 4.php');
break;
case $flag_4:
break;
case $flag_5:
header('Location: final.php');
break;
default:
header('Location: 1.php');
break;
}
?>
<!DOCTYPE html>
<html>
<head>
<title>Level 5</title>
<meta charset="UTF-8">
<meta name="author" content="Benjamin Ver">
<link rel="stylesheet" type="text/css" href="css/jquery-ui.css">
<link rel="stylesheet" type="text/css" href="css/normalize.css">
<link rel="stylesheet" type="text/css" href="css/main.css">
<script type="text/javascript" src="script/jquery.js"></script>
<script type="text/javascript" src="script/jquery-ui.js"></script>
<script type="text/javascript" src="script/main.js"></script>
<script type="text/javascript" src="script/1.js"></script>
</head>
<body>
<div class="front">
<div class="lock intel">
<img src="img/lock_locked.jpg">
</div>
<table class="unlockpad intel">
<tr>
<td class='formInfo'>Username:</td>
<td><input type="text" name="user" id="inp_user"></td>
</tr>
<tr>
<td class='formInfo'>Password:</td>
<td><input type="password" name="passw" id="inp_passw"></td>
</tr>
<tr>
<td colspan='2'>
<button id='submit'>Give it a shot...</button>
</td>
</tr>
</table>
</div>
<div class="half left"></div>
<div class="half right"></div>
</body>
</html>

25
break_the_gate/README.md Normal file
View File

@ -0,0 +1,25 @@
# Break The Gate (1-5)
## Description
Different for each challenge
## Deployment
Place on server, write-protect `secret-database.db`
## Difficulty
*Easy*
## Solution
Per challenge, after a succesful login a cookie with the flag will apear.
1. Login details are as comment in the html
2. Login details are in a JavaScript dictionary calles `userDb`. In console you can print this variable, or you can open `script/ssdb.js`.
3. An sql-injection will get you in. Example: `" OR 1=1;` as password
4. As there are only 1000 possible combination, brute-force should go pretty fast. You can write a simple Pythin-program that sends request to [challenge-url]/4.php?try=[0->999] and compare results. (Correct code was 732)
5. The login details were send over http, meaning they were in plain text in the pcap file (open the pcap file and check the last packet)
## Flag
* IGCTF{ThatWasNotSoHard}
* IGCTF{StopHackingMySitePrettyPlease}
* IGCTF{AllHailOurLordAndSaviourPHP}
* IGCTF{I_may_have_made_this_challenge_last_night}
* IGCTF{KgonnaGoToSleepnow_Bye}

View File

@ -0,0 +1,97 @@
<?php
require('flags.php');
function authCred($u, $p) {
if (isset($_POST['user']) && isset($_POST['passw'])) {
if ($_POST['user'] === $u && $_POST['passw'] === $p) {
return True;
} else {
return False;
}
} else {
return False;
}
}
function checkInj() {
if (isset($_POST['user']) && isset($_POST['passw'])) {
if ($_POST['passw'][0] == '"' || $_POST['passw'][0] == "'") {
return True;
} else {
return False;
}
} else {
return False;
}
}
function checkInDatabase($query) {
$handle = new SQLite3('secretDataBase.db');
$array['dbhandle'] = $handle;
$array['query'] = $query;
$result = $handle->query($query);
$i = 0;
while ($result->columnName($i)) {
$columns[ ] = $result->columnName($i);
$i++;
}
$resx = $result->fetchArray(SQLITE3_ASSOC);
return $resx;
}
switch ($_COOKIE['currentLevel']) {
case $flag_1:
if (isset($_POST['thisUser'])) {
echo $flag_2;
} else {
echo '0';
}
break;
case $flag_2:
$badQuery = 'SELECT * FROM users WHERE username = "' . $_POST['user'] . '" and password = "' . $_POST['passw'] . '";';
if (strpos(strtoupper($_POST['passw']), 'UPDATE')) {
$_POST['passw'] = '';
}
if (strpos(strtoupper($_POST['passw']), 'DELETE')) {
$_POST['passw'] = '';
}
if (strpos(strtoupper($_POST['passw']), 'DROP')) {
$_POST['passw'] = '';
}
if (strpos(strtoupper($_POST['user']), 'UPDATE')) {
$_POST['user'] = '';
}
if (strpos(strtoupper($_POST['user']), 'DELETE')) {
$_POST['user'] = '';
}
if (strpos(strtoupper($_POST['user']), 'DROP')) {
$_POST['user'] = '';
}
if (checkInDatabase($badQuery)) {
echo $flag_3;
} else {
echo '0';
}
break;
case $flag_3:
break;
case $flag_4:
if (authCred('LarsIX', 'FXrm264!&Rdjka')) {
echo $flag_5;
} else {
echo '0';
}
break;
default:
if (authCred('admin', 'admin')) {
echo $flag_1;
} else {
echo '0';
}
}
?>

1312
break_the_gate/css/jquery-ui.css vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,74 @@
/* I really, really hate CSS... */
/* So don't bother finding flags here */
html, body {
height: 100%;
width: 100%;
font-family: sans-serif;
font-size: 2vw;
}
.half {
height: 100%;
width: 50%;
background-image: url("../img/barrier.jpg");
background-size: 25vw;
background-repeat: repeat;
background-color: grey;
z-index: 1;
}
.left {
float: left;
}
.right {
float: right;
}
.front {
width: 100%;
height: 100%;
position: absolute;
}
.intel {
border: 2px solid black;
background-color: #4D4A4E;
position: absolute;
}
.lock {
top: 30%;
left: 50%;
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
width: 10vw;
height: 10vw;
-moz-border-radius: 5vw;
-webkit-border-radius: 5vw;
border-radius: 5vw;
z-index: 3;
display: flex;
justify-content: center;
align-items: center;
}
.lock img {
height: 62%;
}
.unlockpad {
background-color: white;
top: 65%;
left: 50%;
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
/* width: 25vw;
height: 15vh;*/
padding: 5vh 3vw;
z-index: 4;
text-align: center;
}
.formInfo { padding-right: 2vw; }
#submit {
font-size: 1.5vw;
}

349
break_the_gate/css/normalize.css vendored Normal file
View File

@ -0,0 +1,349 @@
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
/* Document
========================================================================== */
/**
* 1. Correct the line height in all browsers.
* 2. Prevent adjustments of font size after orientation changes in iOS.
*/
html {
line-height: 1.15; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/* Sections
========================================================================== */
/**
* Remove the margin in all browsers.
*/
body {
margin: 0;
}
/**
* Render the `main` element consistently in IE.
*/
main {
display: block;
}
/**
* Correct the font size and margin on `h1` elements within `section` and
* `article` contexts in Chrome, Firefox, and Safari.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/* Grouping content
========================================================================== */
/**
* 1. Add the correct box sizing in Firefox.
* 2. Show the overflow in Edge and IE.
*/
hr {
box-sizing: content-box; /* 1 */
height: 0; /* 1 */
overflow: visible; /* 2 */
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
pre {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/* Text-level semantics
========================================================================== */
/**
* Remove the gray background on active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* 1. Remove the bottom border in Chrome 57-
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
*/
abbr[title] {
border-bottom: none; /* 1 */
text-decoration: underline; /* 2 */
text-decoration: underline dotted; /* 2 */
}
/**
* Add the correct font weight in Chrome, Edge, and Safari.
*/
b,
strong {
font-weight: bolder;
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/**
* Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` elements from affecting the line height in
* all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/* Embedded content
========================================================================== */
/**
* Remove the border on images inside links in IE 10.
*/
img {
border-style: none;
}
/* Forms
========================================================================== */
/**
* 1. Change the font styles in all browsers.
* 2. Remove the margin in Firefox and Safari.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 1 */
line-height: 1.15; /* 1 */
margin: 0; /* 2 */
}
/**
* Show the overflow in IE.
* 1. Show the overflow in Edge.
*/
button,
input { /* 1 */
overflow: visible;
}
/**
* Remove the inheritance of text transform in Edge, Firefox, and IE.
* 1. Remove the inheritance of text transform in Firefox.
*/
button,
select { /* 1 */
text-transform: none;
}
/**
* Correct the inability to style clickable types in iOS and Safari.
*/
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
/**
* Remove the inner border and padding in Firefox.
*/
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
/**
* Restore the focus styles unset by the previous rule.
*/
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
/**
* Correct the padding in Firefox.
*/
fieldset {
padding: 0.35em 0.75em 0.625em;
}
/**
* 1. Correct the text wrapping in Edge and IE.
* 2. Correct the color inheritance from `fieldset` elements in IE.
* 3. Remove the padding so developers are not caught out when they zero out
* `fieldset` elements in all browsers.
*/
legend {
box-sizing: border-box; /* 1 */
color: inherit; /* 2 */
display: table; /* 1 */
max-width: 100%; /* 1 */
padding: 0; /* 3 */
white-space: normal; /* 1 */
}
/**
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
*/
progress {
vertical-align: baseline;
}
/**
* Remove the default vertical scrollbar in IE 10+.
*/
textarea {
overflow: auto;
}
/**
* 1. Add the correct box sizing in IE 10.
* 2. Remove the padding in IE 10.
*/
[type="checkbox"],
[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Correct the cursor style of increment and decrement buttons in Chrome.
*/
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Correct the odd appearance in Chrome and Safari.
* 2. Correct the outline style in Safari.
*/
[type="search"] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/**
* Remove the inner padding in Chrome and Safari on macOS.
*/
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* 1. Correct the inability to style clickable types in iOS and Safari.
* 2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/* Interactive
========================================================================== */
/*
* Add the correct display in Edge, IE 10+, and Firefox.
*/
details {
display: block;
}
/*
* Add the correct display in all browsers.
*/
summary {
display: list-item;
}
/* Misc
========================================================================== */
/**
* Add the correct display in IE 10+.
*/
template {
display: none;
}
/**
* Add the correct display in IE 10.
*/
[hidden] {
display: none;
}

64
break_the_gate/css/pl.css Normal file
View File

@ -0,0 +1,64 @@
html {
font-family: roboto;
}
.unlockpad {
padding: 2.5vh 3vw;
}
table {
margin: 1vh, 1vw;
}
.full {
text-align: center;
margin: auto;
display: grid;
grid-template-columns: 1fr;
}
td {
padding: 5px 25px;
text-align: center;
}
tr td img {
margin-top: 20px;
width: 5%;
}
.lock:hover {
cursor: pointer;
}
.triangle {
margin: auto;
width: 0;
height: 0;
border-left: 25px solid transparent;
border-right: 25px solid transparent;
}
.triangle:hover {
cursor: pointer;
}
.up { border-bottom: 50px solid #555; }
.down { border-top: 50px solid #555; }
.digit {
text-align: center;
font-size: 5vw;
/*border: 1px solid black;*/
}
#solution, #nosolution {
margin: auto;
position: relative;
text-align: center;
font-size: 5vw;
font-weight: bold;
}
#nosolution img {
margin-top: 5vw;
width: 20%;
}

72
break_the_gate/final.php Normal file
View File

@ -0,0 +1,72 @@
<?php
require('flags.php');
if(!isset($_COOKIE['currentLevel'])) {
setcookie("currentLevel", "Flags_will_appear_here_when_you_complete_a_level...", time()+24*60*60);
}
switch ($_COOKIE['currentLevel']) {
case $flag_1:
header('Location: 2.php');
break;
case $flag_2:
header('Location: 3.php');
break;
case $flag_3:
header('Location: 4.php');
break;
case $flag_4:
header('Location: 5.php');
break;
case $flag_5:
break;
default:
header('Location: 1.php');
break;
}
?>
<!DOCTYPE html>
<html>
<head>
<title>All done</title>
<meta charset="UTF-8">
<meta name="author" content="Benjamin Ver">
<link rel="stylesheet" type="text/css" href="css/jquery-ui.css">
<link rel="stylesheet" type="text/css" href="css/normalize.css">
<script type="text/javascript" src="script/jquery.js"></script>
<script type="text/javascript" src="script/jquery-ui.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$('div').hide("fade", 2000)
})
</script>
<style type="text/css">
body {
background-color: black;
background-image: url("img/thatsall.gif");
background-repeat: no-repeat;
background-size: contain;
background-position: center;
}
html, body {
width: 100%;
height: 100%;
}
body div {
width: 100%;
height: 100%;
background-color: black;
}
</style>
<body>
<div>
<!-- No challenges here anymore -->
</div>
</body>
</html>

9
break_the_gate/flags.php Normal file
View File

@ -0,0 +1,9 @@
<?php
$flag_1 = "IGCTF{ThatWasNotSoHard}";
$flag_2 = "IGCTF{StopHackingMySitePrettyPlease}";
$flag_3 = "IGCTF{AllHailOurLordAndSaviourPHP}";
$flag_4 = "IGCTF{I_may_have_made_this_challenge_last_night}";
$flag_5 = "IGCTF{KgonnaGoToSleepnow_Bye}";
?>

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

33
break_the_gate/index.php Normal file
View File

@ -0,0 +1,33 @@
<?php
require('flags.php');
if(!isset($_COOKIE['currentLevel'])) {
setcookie("currentLevel", "Flags_will_appear_here_when_you_complete_a_level...", time()+24*60*60);
}
switch ($_COOKIE['currentLevel']) {
case $flag_1:
header('Location: 2.php');
break;
case $flag_2:
header('Location: 3.php');
break;
case $flag_3:
header('Location: 4.php');
break;
case $flag_4:
header('Location: 5.php');
break;
case $flag_5:
header('Location: final.php');
break;
default:
header('Location: 1.php');
break;
}
exit()
?>

View File

@ -0,0 +1,15 @@
function auth1() {
var inp = { user: $('#inp_user').val(), passw: $('#inp_passw').val() }
sendAuth(inp, goNext, errorAnimation)
}
$(document).ready(function(){
$('#submit').click(function(){
auth1();
})
$(document).on('keypress',function(e) {
if(e.which == 13) {
auth1();
}
});
})

View File

@ -0,0 +1,19 @@
function authenticate() {
if (userDb[$('#inp_user').val()] == $('#inp_passw').val()) {
sendAuth({thisUser: userDb[$('#inp_user').val()]}, goNext, errorAnimation);
} else {
errorAnimation();
}
}
$(document).ready(function(){
$('#submit').click(function(){
authenticate();
})
$(document).on('keypress',function(e) {
if(e.which == 13) {
authenticate();
}
});
})

18706
break_the_gate/script/jquery-ui.js vendored Normal file

File diff suppressed because it is too large Load Diff

2
break_the_gate/script/jquery.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,35 @@
function openAnimation() {
$('.lock img').attr('src', 'img/lock_unlocked.gif')
$('.front').delay(1000).fadeOut('slow')
$('.left').delay(1300).hide("slide", {direction: "left" }, 1000)
$('.right').delay(1300).hide("slide", {direction: "right" }, 1000)
}
function errorAnimation() {
$('body').css('background-color', 'red');
for (var i = 0; i <= 3; i++) {
$('.half').delay(500).hide(1)
$('.half').delay(500).show(1)
}
}
function goNext() {
$('body').css('background-color', 'black');
openAnimation();
setTimeout(function(){ window.location = "index.php"; }, 2900);
}
function sendAuth(thisData, ok, nok) {
$.ajax('authenticateLevel.php', {
type: 'POST',
data: thisData,
success: function (data) {
if (data.substr(0, 6) == 'IGCTF{') {
document.cookie = "currentLevel=" + data;
ok()
} else {
nok()
}
}
});
}

View File

@ -0,0 +1,44 @@
var cn = true;
function resetColor() {
cn = false;
$('.digit').removeClass('w');
}
function setUp(numId) {
if (cn) { resetColor(); }
numId.html((parseInt(numId.html()) + 1) % 10);
}
function setDown(numId) {
if (cn) { resetColor(); }
if (numId.html() == "0") {
numId.html(9)
} else {
numId.html(parseInt(numId.html()) - 1);
}
}
function send() {
var tryVal = parseInt($('#num1').html())
tryVal += 10 * parseInt($('#num10').html())
tryVal += 100 * parseInt($('#num100').html())
$('#try').val(tryVal);
$('form').submit()
}
$(document).ready(function(){
$("#1000up").click(function(){ setUp($('#num1000')); })
$("#100up").click(function(){ setUp($('#num100')); })
$("#10up").click(function(){ setUp($('#num10')); })
$("#1up").click(function(){ setUp($('#num1')); })
$("#1000down").click(function(){ setDown($('#num1000')); })
$("#100down").click(function(){ setDown($('#num100')); })
$("#10down").click(function(){ setDown($('#num10')); })
$("#1down").click(function(){ setDown($('#num1')); })
$('img').click(function(){
send();
});
})

View File

@ -0,0 +1,6 @@
userDb['peter'] = 'roadHouse';
userDb['lois'] = 'lois123';
userDb['brian'] = 'd0gbackwards';
userDb['chirs'] = 'password';
userDb['meg'] = 'megatron';
userDb['stewie'] = '<3RUPERT';

Binary file not shown.

View File

@ -0,0 +1,38 @@
{ ... }: {
imports = [
./hardware-configuration.nix
];
boot.cleanTmpDir = true;
networking.hostName = "igctf-test3";
networking.firewall.allowPing = true;
services.openssh.enable = true;
users.users.root.openssh.authorizedKeys.keys = [
"#"
"# WARNING: Automatically generated file"
"# This file will be erased at every boot"
"# This file was generated with '/usr/sbin/scw-fetch-ssh-keys'"
"#"
"# To add a new key, you can:"
"# -- Add keys on your Scaleway account https://cloud.scaleway.com/#/credentials"
"# -- Add keys using server tags - https://cloud.scaleway.com/#/servers/ce59daa2-b92d-4c9b-a595-f904099d4d6b"
"ssh-rsa_XXXXXXXXXXX AUTHORIZED_KEY=ssh-rsa_YYYYYYYYYYYYYYY""
"# - Be sure to replace all spaces with underscores"
"# - $> sed 's/ /_/g' ~/.ssh/id_rsa.pub"
"# -- Add the keys to '/root/.ssh/instance_keys' which will be imported"
"#"
"# And recreate your 'authorized_keys' file with the new keys:"
"ssh-keys --upgrade'"
"#"
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+55wyXDs3Bmb1SZajBs9Uhazw/XWSu91iYSQo4dyDd5CLqfAaLrRKIc5SbdAucCWO0/atorjxAocdxey+O/mY8kLM1DnooPL75ckEWgu3s+v2pAtZYXIN8mDzOOB+pWW2caWWg0BZXL5KITWyKbXK9EnoDYisT/uevoKSMBPYodyrIaKZ7fT099VOZHzYiowcS8h0/ereLtr6PjjTZdkaqDKcVw+MJceSc9+g2kW1CGCHkf08zeYUteoYuf8vH/o1YNTnCNu/RROxfvVTGHrgM1ERg6bm0Eeu28yrj2HF7K1rg4CKLapsDMqCd1+dnCvaX9TVpRWNi3J8UInBOTPr bram@localhost.localdomain"
"ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBH7DEXBvwCshz+Ga3oxZhjwqJl3wjJgq7dJCDkUrbIQhw7qH7uHPmGuCRezcvr4OWUavXXklsVypmDB4L7715MaW1BasGXp3soP+ip9Jp6Rca6S3oYfDNYqp9E4wSXE46g== JuiceSSH"
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDfAjwk4jY0BXRSrGIeyuOzmKPQjjHPnwGLKdcJK/c473oKHNwBbie2Wr0HuIjlGIUvob/QZq8L8vGQwkb4TUJfVWWP2rvwYOg5OsVkjoOmDThBykfJ/9la/rVFNlBKBCXAGmB106oDK2+7RTsB+DDC4Eb01GkTPfLh7fvv1d1MGLYO86z1gC1bDSqw1nWrZRMVf8fzOzM5807SThTa7LoHP/CmvGkUfL6dv661VnldQgqNj+2ULKt1GgMP7c0Csi8F48yBcQAiCZpz3J+oILDNoEp/ZN6EtwB7PxcBKWRgO4pCfc9hjtKWCIz+aC8dxyHDXWmycYGLnI9Eo2kX8jsB JuiceSSH"
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDqzW3TxIL28oUZ3EZXIPsGdB5SOlBrIVvS2NSJUaSNhInR2dUw3/W8nRsm92j5pqJaA1q0N1GOo1wTHd9n8OcDlU/hK7Iih7OPEWkfHYDGYkHs0DxUcgWdC4xJJg2S89rb1Wtr9ygpeAU+pgu0NWJTUFOqZeiagpECanEt1XJ+psChYbeHF61J6S5+LVGiUhoctLHjR1Hi1u8caAlNgtDYmYifCcpebJfCkzLsvFPMZCC1uzg6djGsaP9vkAEQ7VCnrNR6VYJFZTffIHcGfa4GHTzZzbigeyK5fa5f+YwX0/8XmpJsf6z4xHanekORAElYAfrn5N95o3czrETwvPnf bram@bramvaoi"
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDEDuKmIktfHOlI9poqfStDPL02Ilu8QXCLe1nrEfyXa7lG8VkrCx8B86IBbYC+CD3MHdQ5IH2GaG5sRY63VnxlIjM0tE8PVxxguBoh3tHrkssJ68SZerU2Aqxk9DAyu8e9h4jYk131LwbDiAIb+1U4DIc9aF4mPmNjvAFa7pkrYu6NAVB6Pme5AL1/qYj2D9h0HjwcVr4Tjvshk9dlBkt4yXMO8jUp6uou6WoCCKqVZstBJMc7e2NKAp1vbh7KENGeFZNooi65P7UdGGRYdbgeQPTKp/8aS5txvIV7X33FBHxs2o9xqFPqyoGDiCO9ZaoAqlEi3DqMUy5OJCItC3Q/ bramvandenbogaerde@bramweb-retina.local"
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDH6rScSr37gXv/dVxDRn54sNiq2dV0c9m6u1Ks2ZJFtz6/Kwn7rRq+3OSiccT46sllSZ01Jf7MjigQ/Er3QgJxxyQ6dDEJs8IUTz9Js3NHKdSh6/w3ROIjy71oYmN5/7WJRjOfGtXcVAnTd5qOGh5zlMtyKCkVQqtGtVcwptPi4a+lwPXy8M8ov8K2oics3EDjqei7yJZ8dzho4vHj5mg7Yd5z4d9EUU1Hi+MPLmf1loJD2l+dNhC3EpKZ1wsb5gsxFKqLPBaySMWhyK55Eeo4WEYHZIlKETRkW2sLx9SLIZ2L/e2qYJHU3Qm8hBvx9ccekggdVTos9uuxqoddZI9j bram@debianserv"
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC9Lgo2qydGu5zThFX7xv3dav2kN7TuiNoAqPUa5anvy29dSBPOlj94aE2Snw7tnNh9l7SGD/0iyDLXaRqYxzsbUOqPh3nG/w+NI5kH7RvR2nCDvKjdna6FALgctqWNsuDZ4nbdWEsLdiVKTMartiVUoTwmejko7H0yPf7VjX723pIEXtXMqjJT/e1lbJDvlRgP/QBoZtbmb3UvF7H4JtQFOXRais751HGbVUu1vhmqYF3TaUNOwMrwzKeTFBDOHw6FCb8R5SE+S2OPrfDVLywMEIhQhVfpSXMZt5Nm1nDDpJPm1z34+x6MaORIB4/9wi/YqWnru+XDefSfb8h2dC4QZzXyAxGqJ/cPtkseNH0vg7MytvajEMwf8v2tCguYy3xDKl7Rfyp9lXVXYxmPoEn+Fjj9tJ2t6Tm0qgarCAF726oXghHlY+2qh7S0/93LNymbSUTiegpX5Lp0h5emgDb/xe20htfI9RWh9zFqV2zD3K5icoaaOscAKf7Ctgm/Ff8= nibor@Rylia"
"# Below your custom ssh keys from '/root/.ssh/instance_keys'"
];
}

61
deployment/containers.nix Normal file
View File

@ -0,0 +1,61 @@
{ pkgs, ... }:
let
run = ({name, image, ports, environment ? {}, ... }@attrs:
let rest = builtins.removeAttrs attrs [ "name" "image" "ports" "environment" ]; in
{
image = name;
inherit ports;
imageFile = image;
inherit environment;
autoStart = true;
} // rest) ; in
{
options = {};
config = {
networking.firewall.allowedTCPPorts = [ 5000 8080 8081 9001 9002 9003 ];
virtualisation.oci-containers.containers = {
"schemingschemer1" = run {
name = "ss/1";
image = import ../scheming-schemer/first/nix/image.nix {};
ports = [ "9001:20000" ];
};
"schemingschemer2" = run {
name = "ss/2";
image = import ../scheming-schemer/second/nix/image.nix {};
ports = [ "9002:20000" ];
};
"schemingschemer3" = run {
name = "ss/3";
image = import ../scheming-schemer/third/nix/image.nix {};
ports = [ "9003:20000" ];
};
"fancy-text" = run {
name = "fancy-text";
image = import ../fancy_text/image.nix {};
ports = [ "9004:20000" ];
};
"gottacatchthemallfront" = run {
name = "frontend-gotta-catch-them-all";
image = import ../gotta_catch_em_all/nix/frontend.nix {};
ports = [ "8080:80" ];
};
"gottacatchthemallback" = run {
name = "gotta-catch-them-all-backend";
image = import ../gotta_catch_em_all/nix/backend.nix {};
ports = [ "5000:5000" ];
};
"lost-keys" = run {
name = "lost-keys";
image = import ../lost-keys/image.nix {};
ports = [ "2222:2222" ];
};
"ruby-challenge" = run {
name = "ruby-challenge";
image = import ../ruby_challenge/image.nix {};
ports = [ "8081:3000" ];
user = "joske:joske";
};
};
};
}

View File

@ -0,0 +1,6 @@
{ modulesPath, ... }:
{
imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
boot.loader.grub.device = "/dev/vda";
fileSystems."/" = { device = "/dev/vda1"; fsType = "ext4"; };
}

12
deployment/hosts.nix Normal file
View File

@ -0,0 +1,12 @@
let pkgs = import <nixpkgs> {}; in
{
"igctf-test3" = { config, pkgs, ... }: {
deployment.targetHost = "51.15.125.82";
deployment.targetUser = "root";
imports = [
./configuration.nix
./containers.nix
];
};
}

View File

@ -0,0 +1,3 @@
#cloud-config
runcmd:
- curl https://raw.githubusercontent.com/elitak/nixos-infect/master/nixos-infect | NIX_CHANNEL=nixos-20.09 bash 2>&1 | tee /tmp/infect.log

10
deployment/setup.sh Executable file
View File

@ -0,0 +1,10 @@
#!/usr/bin/env bash
echo "Provisioning instance"
SERVER_ID=$(scw create --commercial-type=STARDUST1-S --name=igctf-test3 449bdf2d)
scw _userdata $SERVER_ID cloud-init=@$PWD/nix-infect-init.yaml
scw start $SERVER_ID
IP=$(scw inspect $SERVER_ID -f '.server.public_ip.address')

5
deployment/shell.nix Normal file
View File

@ -0,0 +1,5 @@
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
nativeBuildInputs = with pkgs ; [ scaleway-cli morph ];
}

7
deployment/utils.nix Normal file
View File

@ -0,0 +1,7 @@
{ pkgs ? import <nixpkgs> {} }:
{
copy = (source: destination:
pkgs.writeTextDir destination (builtins.readFile source)
);
}

0
fancy_text/.gitkeep Normal file
View File

18
fancy_text/README.md Normal file
View File

@ -0,0 +1,18 @@
# Fancy Text
## Description
Found some fancy text, but my dumb computer can't read it... Can yours?
## Deployment
Netcat challenge
## Difficulty
*Easy*
## Solution
As you can try a string yourself, you can pass all printable characters and build a dictionary for them. Then you can decode any string with this dictionary.
A solution for the programming part of the challenge is provided in `solution.py`. You can use the python libraries `requests` and `nclib` or `pwntools` to communicate with the server.
## Flag
IGCTF{You_should_really_consider_buying_AMC_stocks.<3}

View File

@ -0,0 +1,3 @@
#!/bin/bash
python3 /home/ig/serverside.py

60
fancy_text/generic.nix Normal file
View File

@ -0,0 +1,60 @@
{ pkgs ? import <nixpkgs> {}, ... }:
with (import ../deployment/utils.nix {});
calculator-app: docker-entrypoint: name:
let
protocols = pkgs.writeTextDir "etc/protocols" ''
tcp 6 TCP # Transmission Control
'';
config = pkgs.writeTextDir "etc/xinetd.conf"
''
service ctf
{
disable = no
socket_type = stream
protocol = tcp
wait = no
user = ig
type = UNLISTED
port = 20000
bind = 0.0.0.0
server = /home/ig/docker-entrypoint.sh
# banner_fail = /etc/banner_fail
# safety options
# the maximum instances of this service per source IP address
per_source = 10
# the maximum number of CPU seconds that the service may use
rlimit_cpu = 20
# the Address Space resource limit for the service
rlimit_as = 512M
# kafel_rule = /etc/pwn.kafel
}
'';
add_files = [
(copy docker-entrypoint "home/ig/docker-entrypoint.sh")
(copy calculator-app "home/ig/serverside.py")
];
image = pkgs.dockerTools.buildImage {
name = name ;
tag = "latest";
runAsRoot = ''
#!${pkgs.stdenv.shell}
${pkgs.dockerTools.shadowSetup}
useradd -U -m ig && mkdir -p /home/ig
chown -R ig:ig /home/ig
mkdir -p /usr/local/bin
chmod -R -w /home/ig
chmod +x /home/ig/docker-entrypoint.sh
'';
contents = [ pkgs.xinetd pkgs.bash pkgs.python38Packages.pip pkgs.python3 config protocols ] ++ add_files;
config = {
ExposedPorts = {
"20000/tcp" = {};
};
Cmd = [ ./run.sh ];
};
}; in image

4
fancy_text/image.nix Normal file
View File

@ -0,0 +1,4 @@
{ pkgs ? import <nixpkgs> {}, ... }:
let build = import ./generic.nix ;
in build {} ./serverside.py ./docker-entrypoint.sh "fancy-text"

4
fancy_text/run.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
pip install art
xinetd -dontfork -stayalive

55
fancy_text/serverside.py Normal file
View File

@ -0,0 +1,55 @@
from art import text2art
from time import sleep
from random import randint
from datetime import datetime
FLAG = 'IGCTF{You_should_really_consider_buying_AMC_stocks.<3}'
print(text2art('Welcome!'))
def example():
exString = input('Provide a string: ')
exString = " ".join(exString[i:i+1] for i in range(0, len(exString), 1))
print(text2art(exString))
def forReal():
solution = ''
for i in range(0, randint(7,9)):
solution += chr(randint(33,125))
startTime = datetime.now()
print(text2art(" ".join(solution[i:i+1] for i in range(0, len(solution), 1))))
tried = input('What does it say? ')
totaltime = (datetime.now() - startTime).seconds
if (totaltime > 2):
print("Too late!")
elif (tried == solution):
print("Congratulations!")
print(FLAG)
return True
else:
print("Wrong! (correct: " + solution + ")")
while(True):
print()
print(" -- MENU --")
print("1. Give an example")
print("2. Try yourself")
print("3. Close connection")
choice = input('Choose a number: ')
if (choice == '1'):
example()
elif(choice == '2'):
if forReal():
break
elif(choice == '3'):
break
else:
print(choice, "not recognized...")
print()
print("Bye!")

31
fancy_text/skeleton.rkt Normal file
View File

@ -0,0 +1,31 @@
#lang racket
; You can use this skeleton to connect to the server
; but feel free to use any programming language to your
; liking
; connect to the server
(define-values (in out) (tcp-connect "51.15.125.82" 9004))
(file-stream-buffer-mode in 'none)
(file-stream-buffer-mode out 'none)
; Some commands you can use
; Read a line
(read-line in)
; Read a single character
(read-char in)
; Read 5 characters
(read-string 5 in)
; Write a string to the server
(write-char #\a out)
; Write a string to the server
(write-string "AMC to the moon" out)
; Write a newline to the server
(newline out)

64
fancy_text/solution.py Normal file
View File

@ -0,0 +1,64 @@
#
# SOLUTION: Fancy Letters
# by Benjamin Vermunicht
#
# Approach:
# We'll first try to build a dictionary mapping each letter
# in ascii-art to the real letter. Than we'll request a string
# and translate it with our dictionary.
#
# A dictionary with how each character looks
translation = {}
# Function to split a ascii-art string in ascii-art letters
# returns a list of srings, each string representing a letter
def readCharacters(asciiString):
characters = []
# splits each line of the ascii-art, lines will be
# iterated synchronously
asciiLines = asciiString.split('\n')[:-1]
thisChar = [''] * len(asciiLines)
for i in range(0, len(asciiLines[0])):
space = True
for j in range(0, len(asciiLines)):
# if all lines contain a space on the same index,
# we detect a new letter
if (asciiLines[j][i] != ' '):
space = False
thisChar[j] += asciiLines[j][i]
if space:
# if we detect a new letter, save the previou letter
# to our output
for j in range(0, len(asciiLines)):
thisChar[j] = thisChar[j][:-1]
# merge the characters of this character of each line
# to one string with newlines
characters.append('\n'.join(thisChar))
thisChar = [''] * len(asciiLines)
# save the last letter to the output
characters.append('\n'.join(thisChar))
return characters
# Iterates all characters of a known string to build
# a dictionary
def buildDictionary(asciiString, knownString):
i = 0
for c in readCharacters(asciiString):
translation[c] = knownString[i]
i += 1
# Translates an ascii-art string to regular text
# using the dictionary created with buildDictionary()
def translateString(asciiString):
resultString = ''
for c in readCharacters(asciiString):
resultString += translation[c]
return resultString

5
gotta_catch_em_all/.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/

View File

@ -0,0 +1 @@
gotta_catch_em_all

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$/../gotta_catch_em_all">
<excludeFolder url="file://$MODULE_DIR$/../gotta_catch_em_all/temp" />
<excludeFolder url="file://$MODULE_DIR$/../gotta_catch_em_all/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/../gotta_catch_em_all/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/../gotta_catch_em_all/.idea/gotta_catch_em_all.iml" filepath="$PROJECT_DIR$/../gotta_catch_em_all/.idea/gotta_catch_em_all.iml" />
</modules>
</component>
</project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

View File

@ -0,0 +1,20 @@
# Gotta Catch 'em All! (Really Fast)
## Text
I am an aspiring new Pokémon trainer that is ready to explore the world and catch many Pokémon. Unfortunately, due to the COVID pandemic, everything will be going digital now. Professor Oak made us a game to play instead, and developed this Pokédex website to register all the Pokémon we caught in the game.
Gary, my rival, bragged to me that he managed to complete the entire Pokédex in under a minute. He probably didn't play the game at all and just selected all the Pokémon on the Pokédex. Whatever the case may be, I intend to beat him, legitimately or not.
The website is connected to a NodeJS backend with a web socket that keeps track of the Pokédex and its completion. Somehow, I must fool the backend that I captured all Pokémon in an insanely fast time, without looking too suspicious. And knowing Professor Oak's programming skills and the fact that its written in JavaScript, there's probably some kind of vulnerability I can abuse.
## How To Solve
Difficulty: Advanced
There is a hint given when adding Poison-type Pokémon that there's a bug caused by the poison of the Pokémon that affects the shared prototype. You have to use prototype poisoning to inject the value `captured: true` into the shared prototype of all Pokémon (which is 2 levels up), or, alternatively, inject the property on all different Pokémon types (grass, water, fire, etc...):
```javascript
webSocket.send('{"msg": "updatePokedex", "data": {"pokemon": "Bulbasaur", "values": {"__proto__": {"__proto__": {"captured": true}}}}}')
```
## Flag
IGCTF{MissingNo}

View File

@ -0,0 +1,11 @@
FROM node
WORKDIR /usr/src/app
COPY . /usr/src/app
RUN npm install
#EXPOSE 5000
CMD ["node", "index.js"]

View File

@ -0,0 +1,17 @@
# This file has been generated by node2nix 1.8.0. Do not edit!
{pkgs ? import <nixpkgs> {
inherit system;
}, system ? builtins.currentSystem, nodejs ? pkgs."nodejs-12_x"}:
let
nodeEnv = import ./node-env.nix {
inherit (pkgs) stdenv python2 utillinux runCommand writeTextFile;
inherit nodejs;
libtool = if pkgs.stdenv.isDarwin then pkgs.darwin.cctools else null;
};
in
import ./node-packages.nix {
inherit (pkgs) fetchurl fetchgit;
inherit nodeEnv;
}

View File

@ -0,0 +1,129 @@
const WebSocket = require('ws');
const pokemon = require('pokemon')
const pokeTypes = require('./poketypes.json')
const wss = new WebSocket.Server({
port: 5000
})
function flatten(obj) {
if(obj !== null && obj !== undefined) {
let ret = {};
for (let i in obj) {
ret[i] = obj[i];
}
return ret;
} else {
return obj
}
}
function badObjectCopy(values, object) {
if(values !== undefined && object !== undefined && values !== null && object !== null) {
for(let i in values) {
if(typeof values[i] === "object") {
badObjectCopy(values[i], object[i])
} else {
object[i] = values[i]
}
}
}
}
function flattenObject(obj) {
return Object.fromEntries(Object.entries(obj).map(([key, val]) => [key, flatten(val)]))
}
wss.on('connection', ws => {
try {
const timeStarted = new Date();
const Pokemon = {}
const types = {
grass: {type: 'grass' , __proto__: Pokemon},
fire: {type: 'fire' , __proto__: Pokemon},
water: {type: 'water' , __proto__: Pokemon},
poison: {type: 'poison' , __proto__: Pokemon},
flying: {type: 'flying' , __proto__: Pokemon},
bug: {type: 'bug' , __proto__: Pokemon},
normal: {type: 'normal' , __proto__: Pokemon},
electric: {type: 'electric', __proto__: Pokemon},
ground: {type: 'ground' , __proto__: Pokemon},
fairy: {type: 'fairy' , __proto__: Pokemon},
fighting: {type: 'fighting', __proto__: Pokemon},
psychic: {type: 'psychic' , __proto__: Pokemon},
rock: {type: 'rock' , __proto__: Pokemon},
steel: {type: 'steel' , __proto__: Pokemon},
ice: {type: 'ice' , __proto__: Pokemon},
ghost: {type: 'ghost' , __proto__: Pokemon},
dragon: {type: 'dragon' , __proto__: Pokemon}
}
const pokedex = Object.fromEntries(pokemon.all().slice(0, 151).map(poke => {
const type = types[pokeTypes[poke]]
return [poke, {__proto__: type}]
}))
const send = async(msg, data) => await ws.send(JSON.stringify({msg, data}))
const checkIfAllCaptured = async () => {
if(Object.values(pokedex).every(poke => poke["captured"])) {
const diff = new Date() - timeStarted;
if(diff < 60000) {
send("pokedexCompleted", {
msg: "I can't believe you beat my near impossible 60 second speedrun! It's impossible! I am the best trainer to have ever lived! Urgh... I guess I don't have a choice but to give you this item...\n\n*You obtained the key IGCTF{MissingNo}!*\n\nHave fun with it... I guess.\n\n-Gary"
})
} else {
send("pokedexCompleted", {
msg: "Hah, you did good, but not nearly as good as I did. You still got a long way to beat my 1 minute run, loser.\n\n-Gary"
})
}
ws.close()
}
}
let messagesReceived = 0;
let timeOfLastMessage = 0;
let poisonMessageSent = false;
ws.on('message', evt => {
messagesReceived++;
const currentTime = new Date()
console.log(currentTime - timeOfLastMessage)
if(currentTime - timeOfLastMessage < 500) {
send("error", {msg: "You are sending messages too fast to the backend. Please slow down."})
timeOfLastMessage = currentTime
return
} else {
timeOfLastMessage = currentTime
}
const {msg, data} = JSON.parse(evt)
switch (msg) {
case "initializePokedex": send('pokedexInitialized', flattenObject(pokedex)); break;
case "updatePokedex": {
const {pokemon, values} = data;
if(pokemon !== '__proto__') {
if(pokeTypes[pokemon] === 'poison') {
badObjectCopy(values, pokedex[pokemon].__proto__);
if(!poisonMessageSent) {
send("error", {msg: "Dear Pokémon trainer,\n\n There seems to be a bug when adding a Poison type Pokémon: it automatically registers all Poison type Pokémon in the Pokédex as captured! Somehow the poison seems to affect the shared prototype...\n\nYours truly,\nProfessor Oak"})
poisonMessageSent = true
}
} else {
badObjectCopy(values, pokedex[pokemon]);
}
} else {
send("error", {msg: "I read somewhere that letting the client change the __proto__ property isn't such a good idea, so I'll just add this check here. I sure hope that I didn't forget to check this anywhere else... \n\n -Professor Oak"})
}
send('pokedexUpdated', flattenObject(pokedex))
checkIfAllCaptured()
break;
}
}
});
} catch(e) {
console.error(e)
}
})

View File

@ -0,0 +1,542 @@
# This file originates from node2nix
{stdenv, nodejs, python2, utillinux, libtool, runCommand, writeTextFile}:
let
python = if nodejs ? python then nodejs.python else python2;
# Create a tar wrapper that filters all the 'Ignoring unknown extended header keyword' noise
tarWrapper = runCommand "tarWrapper" {} ''
mkdir -p $out/bin
cat > $out/bin/tar <<EOF
#! ${stdenv.shell} -e
$(type -p tar) "\$@" --warning=no-unknown-keyword --delay-directory-restore
EOF
chmod +x $out/bin/tar
'';
# Function that generates a TGZ file from a NPM project
buildNodeSourceDist =
{ name, version, src, ... }:
stdenv.mkDerivation {
name = "node-tarball-${name}-${version}";
inherit src;
buildInputs = [ nodejs ];
buildPhase = ''
export HOME=$TMPDIR
tgzFile=$(npm pack | tail -n 1) # Hooks to the pack command will add output (https://docs.npmjs.com/misc/scripts)
'';
installPhase = ''
mkdir -p $out/tarballs
mv $tgzFile $out/tarballs
mkdir -p $out/nix-support
echo "file source-dist $out/tarballs/$tgzFile" >> $out/nix-support/hydra-build-products
'';
};
includeDependencies = {dependencies}:
stdenv.lib.optionalString (dependencies != [])
(stdenv.lib.concatMapStrings (dependency:
''
# Bundle the dependencies of the package
mkdir -p node_modules
cd node_modules
# Only include dependencies if they don't exist. They may also be bundled in the package.
if [ ! -e "${dependency.name}" ]
then
${composePackage dependency}
fi
cd ..
''
) dependencies);
# Recursively composes the dependencies of a package
composePackage = { name, packageName, src, dependencies ? [], ... }@args:
builtins.addErrorContext "while evaluating node package '${packageName}'" ''
DIR=$(pwd)
cd $TMPDIR
unpackFile ${src}
# Make the base dir in which the target dependency resides first
mkdir -p "$(dirname "$DIR/${packageName}")"
if [ -f "${src}" ]
then
# Figure out what directory has been unpacked
packageDir="$(find . -maxdepth 1 -type d | tail -1)"
# Restore write permissions to make building work
find "$packageDir" -type d -exec chmod u+x {} \;
chmod -R u+w "$packageDir"
# Move the extracted tarball into the output folder
mv "$packageDir" "$DIR/${packageName}"
elif [ -d "${src}" ]
then
# Get a stripped name (without hash) of the source directory.
# On old nixpkgs it's already set internally.
if [ -z "$strippedName" ]
then
strippedName="$(stripHash ${src})"
fi
# Restore write permissions to make building work
chmod -R u+w "$strippedName"
# Move the extracted directory into the output folder
mv "$strippedName" "$DIR/${packageName}"
fi
# Unset the stripped name to not confuse the next unpack step
unset strippedName
# Include the dependencies of the package
cd "$DIR/${packageName}"
${includeDependencies { inherit dependencies; }}
cd ..
${stdenv.lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
'';
pinpointDependencies = {dependencies, production}:
let
pinpointDependenciesFromPackageJSON = writeTextFile {
name = "pinpointDependencies.js";
text = ''
var fs = require('fs');
var path = require('path');
function resolveDependencyVersion(location, name) {
if(location == process.env['NIX_STORE']) {
return null;
} else {
var dependencyPackageJSON = path.join(location, "node_modules", name, "package.json");
if(fs.existsSync(dependencyPackageJSON)) {
var dependencyPackageObj = JSON.parse(fs.readFileSync(dependencyPackageJSON));
if(dependencyPackageObj.name == name) {
return dependencyPackageObj.version;
}
} else {
return resolveDependencyVersion(path.resolve(location, ".."), name);
}
}
}
function replaceDependencies(dependencies) {
if(typeof dependencies == "object" && dependencies !== null) {
for(var dependency in dependencies) {
var resolvedVersion = resolveDependencyVersion(process.cwd(), dependency);
if(resolvedVersion === null) {
process.stderr.write("WARNING: cannot pinpoint dependency: "+dependency+", context: "+process.cwd()+"\n");
} else {
dependencies[dependency] = resolvedVersion;
}
}
}
}
/* Read the package.json configuration */
var packageObj = JSON.parse(fs.readFileSync('./package.json'));
/* Pinpoint all dependencies */
replaceDependencies(packageObj.dependencies);
if(process.argv[2] == "development") {
replaceDependencies(packageObj.devDependencies);
}
replaceDependencies(packageObj.optionalDependencies);
/* Write the fixed package.json file */
fs.writeFileSync("package.json", JSON.stringify(packageObj, null, 2));
'';
};
in
''
node ${pinpointDependenciesFromPackageJSON} ${if production then "production" else "development"}
${stdenv.lib.optionalString (dependencies != [])
''
if [ -d node_modules ]
then
cd node_modules
${stdenv.lib.concatMapStrings (dependency: pinpointDependenciesOfPackage dependency) dependencies}
cd ..
fi
''}
'';
# Recursively traverses all dependencies of a package and pinpoints all
# dependencies in the package.json file to the versions that are actually
# being used.
pinpointDependenciesOfPackage = { packageName, dependencies ? [], production ? true, ... }@args:
''
if [ -d "${packageName}" ]
then
cd "${packageName}"
${pinpointDependencies { inherit dependencies production; }}
cd ..
${stdenv.lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
fi
'';
# Extract the Node.js source code which is used to compile packages with
# native bindings
nodeSources = runCommand "node-sources" {} ''
tar --no-same-owner --no-same-permissions -xf ${nodejs.src}
mv node-* $out
'';
# Script that adds _integrity fields to all package.json files to prevent NPM from consulting the cache (that is empty)
addIntegrityFieldsScript = writeTextFile {
name = "addintegrityfields.js";
text = ''
var fs = require('fs');
var path = require('path');
function augmentDependencies(baseDir, dependencies) {
for(var dependencyName in dependencies) {
var dependency = dependencies[dependencyName];
// Open package.json and augment metadata fields
var packageJSONDir = path.join(baseDir, "node_modules", dependencyName);
var packageJSONPath = path.join(packageJSONDir, "package.json");
if(fs.existsSync(packageJSONPath)) { // Only augment packages that exist. Sometimes we may have production installs in which development dependencies can be ignored
console.log("Adding metadata fields to: "+packageJSONPath);
var packageObj = JSON.parse(fs.readFileSync(packageJSONPath));
if(dependency.integrity) {
packageObj["_integrity"] = dependency.integrity;
} else {
packageObj["_integrity"] = "sha1-000000000000000000000000000="; // When no _integrity string has been provided (e.g. by Git dependencies), add a dummy one. It does not seem to harm and it bypasses downloads.
}
if(dependency.resolved) {
packageObj["_resolved"] = dependency.resolved; // Adopt the resolved property if one has been provided
} else {
packageObj["_resolved"] = dependency.version; // Set the resolved version to the version identifier. This prevents NPM from cloning Git repositories.
}
if(dependency.from !== undefined) { // Adopt from property if one has been provided
packageObj["_from"] = dependency.from;
}
fs.writeFileSync(packageJSONPath, JSON.stringify(packageObj, null, 2));
}
// Augment transitive dependencies
if(dependency.dependencies !== undefined) {
augmentDependencies(packageJSONDir, dependency.dependencies);
}
}
}
if(fs.existsSync("./package-lock.json")) {
var packageLock = JSON.parse(fs.readFileSync("./package-lock.json"));
if(packageLock.lockfileVersion !== 1) {
process.stderr.write("Sorry, I only understand lock file version 1!\n");
process.exit(1);
}
if(packageLock.dependencies !== undefined) {
augmentDependencies(".", packageLock.dependencies);
}
}
'';
};
# Reconstructs a package-lock file from the node_modules/ folder structure and package.json files with dummy sha1 hashes
reconstructPackageLock = writeTextFile {
name = "addintegrityfields.js";
text = ''
var fs = require('fs');
var path = require('path');
var packageObj = JSON.parse(fs.readFileSync("package.json"));
var lockObj = {
name: packageObj.name,
version: packageObj.version,
lockfileVersion: 1,
requires: true,
dependencies: {}
};
function augmentPackageJSON(filePath, dependencies) {
var packageJSON = path.join(filePath, "package.json");
if(fs.existsSync(packageJSON)) {
var packageObj = JSON.parse(fs.readFileSync(packageJSON));
dependencies[packageObj.name] = {
version: packageObj.version,
integrity: "sha1-000000000000000000000000000=",
dependencies: {}
};
processDependencies(path.join(filePath, "node_modules"), dependencies[packageObj.name].dependencies);
}
}
function processDependencies(dir, dependencies) {
if(fs.existsSync(dir)) {
var files = fs.readdirSync(dir);
files.forEach(function(entry) {
var filePath = path.join(dir, entry);
var stats = fs.statSync(filePath);
if(stats.isDirectory()) {
if(entry.substr(0, 1) == "@") {
// When we encounter a namespace folder, augment all packages belonging to the scope
var pkgFiles = fs.readdirSync(filePath);
pkgFiles.forEach(function(entry) {
if(stats.isDirectory()) {
var pkgFilePath = path.join(filePath, entry);
augmentPackageJSON(pkgFilePath, dependencies);
}
});
} else {
augmentPackageJSON(filePath, dependencies);
}
}
});
}
}
processDependencies("node_modules", lockObj.dependencies);
fs.writeFileSync("package-lock.json", JSON.stringify(lockObj, null, 2));
'';
};
prepareAndInvokeNPM = {packageName, bypassCache, reconstructLock, npmFlags, production}:
let
forceOfflineFlag = if bypassCache then "--offline" else "--registry http://www.example.com";
in
''
# Pinpoint the versions of all dependencies to the ones that are actually being used
echo "pinpointing versions of dependencies..."
source $pinpointDependenciesScriptPath
# Patch the shebangs of the bundled modules to prevent them from
# calling executables outside the Nix store as much as possible
patchShebangs .
# Deploy the Node.js package by running npm install. Since the
# dependencies have been provided already by ourselves, it should not
# attempt to install them again, which is good, because we want to make
# it Nix's responsibility. If it needs to install any dependencies
# anyway (e.g. because the dependency parameters are
# incomplete/incorrect), it fails.
#
# The other responsibilities of NPM are kept -- version checks, build
# steps, postprocessing etc.
export HOME=$TMPDIR
cd "${packageName}"
runHook preRebuild
${stdenv.lib.optionalString bypassCache ''
${stdenv.lib.optionalString reconstructLock ''
if [ -f package-lock.json ]
then
echo "WARNING: Reconstruct lock option enabled, but a lock file already exists!"
echo "This will most likely result in version mismatches! We will remove the lock file and regenerate it!"
rm package-lock.json
else
echo "No package-lock.json file found, reconstructing..."
fi
node ${reconstructPackageLock}
''}
node ${addIntegrityFieldsScript}
''}
npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${stdenv.lib.optionalString production "--production"} rebuild
if [ "''${dontNpmInstall-}" != "1" ]
then
# NPM tries to download packages even when they already exist if npm-shrinkwrap is used.
rm -f npm-shrinkwrap.json
npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${stdenv.lib.optionalString production "--production"} install
fi
'';
# Builds and composes an NPM package including all its dependencies
buildNodePackage =
{ name
, packageName
, version
, dependencies ? []
, buildInputs ? []
, production ? true
, npmFlags ? ""
, dontNpmInstall ? false
, bypassCache ? false
, reconstructLock ? false
, preRebuild ? ""
, dontStrip ? true
, unpackPhase ? "true"
, buildPhase ? "true"
, ... }@args:
let
extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" "dontStrip" "dontNpmInstall" "preRebuild" "unpackPhase" "buildPhase" ];
in
stdenv.mkDerivation ({
name = "node_${name}-${version}";
buildInputs = [ tarWrapper python nodejs ]
++ stdenv.lib.optional (stdenv.isLinux) utillinux
++ stdenv.lib.optional (stdenv.isDarwin) libtool
++ buildInputs;
inherit nodejs;
inherit dontStrip; # Stripping may fail a build for some package deployments
inherit dontNpmInstall preRebuild unpackPhase buildPhase;
compositionScript = composePackage args;
pinpointDependenciesScript = pinpointDependenciesOfPackage args;
passAsFile = [ "compositionScript" "pinpointDependenciesScript" ];
installPhase = ''
# Create and enter a root node_modules/ folder
mkdir -p $out/lib/node_modules
cd $out/lib/node_modules
# Compose the package and all its dependencies
source $compositionScriptPath
${prepareAndInvokeNPM { inherit packageName bypassCache reconstructLock npmFlags production; }}
# Create symlink to the deployed executable folder, if applicable
if [ -d "$out/lib/node_modules/.bin" ]
then
ln -s $out/lib/node_modules/.bin $out/bin
fi
# Create symlinks to the deployed manual page folders, if applicable
if [ -d "$out/lib/node_modules/${packageName}/man" ]
then
mkdir -p $out/share
for dir in "$out/lib/node_modules/${packageName}/man/"*
do
mkdir -p $out/share/man/$(basename "$dir")
for page in "$dir"/*
do
ln -s $page $out/share/man/$(basename "$dir")
done
done
fi
# Run post install hook, if provided
runHook postInstall
'';
} // extraArgs);
# Builds a development shell
buildNodeShell =
{ name
, packageName
, version
, src
, dependencies ? []
, buildInputs ? []
, production ? true
, npmFlags ? ""
, dontNpmInstall ? false
, bypassCache ? false
, reconstructLock ? false
, dontStrip ? true
, unpackPhase ? "true"
, buildPhase ? "true"
, ... }@args:
let
extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" ];
nodeDependencies = stdenv.mkDerivation ({
name = "node-dependencies-${name}-${version}";
buildInputs = [ tarWrapper python nodejs ]
++ stdenv.lib.optional (stdenv.isLinux) utillinux
++ stdenv.lib.optional (stdenv.isDarwin) libtool
++ buildInputs;
inherit dontStrip; # Stripping may fail a build for some package deployments
inherit dontNpmInstall unpackPhase buildPhase;
includeScript = includeDependencies { inherit dependencies; };
pinpointDependenciesScript = pinpointDependenciesOfPackage args;
passAsFile = [ "includeScript" "pinpointDependenciesScript" ];
installPhase = ''
mkdir -p $out/${packageName}
cd $out/${packageName}
source $includeScriptPath
# Create fake package.json to make the npm commands work properly
cp ${src}/package.json .
chmod 644 package.json
${stdenv.lib.optionalString bypassCache ''
if [ -f ${src}/package-lock.json ]
then
cp ${src}/package-lock.json .
fi
''}
# Go to the parent folder to make sure that all packages are pinpointed
cd ..
${stdenv.lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
${prepareAndInvokeNPM { inherit packageName bypassCache reconstructLock npmFlags production; }}
# Expose the executables that were installed
cd ..
${stdenv.lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
mv ${packageName} lib
ln -s $out/lib/node_modules/.bin $out/bin
'';
} // extraArgs);
in
stdenv.mkDerivation {
name = "node-shell-${name}-${version}";
buildInputs = [ python nodejs ] ++ stdenv.lib.optional (stdenv.isLinux) utillinux ++ buildInputs;
buildCommand = ''
mkdir -p $out/bin
cat > $out/bin/shell <<EOF
#! ${stdenv.shell} -e
$shellHook
exec ${stdenv.shell}
EOF
chmod +x $out/bin/shell
'';
# Provide the dependencies in a development shell through the NODE_PATH environment variable
inherit nodeDependencies;
shellHook = stdenv.lib.optionalString (dependencies != []) ''
export NODE_PATH=${nodeDependencies}/lib/node_modules
export PATH="${nodeDependencies}/bin:$PATH"
'';
};
in
{
buildNodeSourceDist = stdenv.lib.makeOverridable buildNodeSourceDist;
buildNodePackage = stdenv.lib.makeOverridable buildNodePackage;
buildNodeShell = stdenv.lib.makeOverridable buildNodeShell;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,980 @@
{
"name": "backend",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"acorn": {
"version": "5.7.4",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz",
"integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg=="
},
"acorn-jsx": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
"integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=",
"requires": {
"acorn": "^3.0.4"
},
"dependencies": {
"acorn": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
"integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo="
}
}
},
"ajv": {
"version": "5.5.2",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
"requires": {
"co": "^4.6.0",
"fast-deep-equal": "^1.0.0",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.3.0"
}
},
"ajv-keywords": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz",
"integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I="
},
"ansi-escapes": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
"integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ=="
},
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
},
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
},
"argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"requires": {
"sprintf-js": "~1.0.2"
}
},
"babel-code-frame": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
"integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
"requires": {
"chalk": "^1.1.3",
"esutils": "^2.0.2",
"js-tokens": "^3.0.2"
},
"dependencies": {
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
"has-ansi": "^2.0.0",
"strip-ansi": "^3.0.0",
"supports-color": "^2.0.0"
}
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"requires": {
"ansi-regex": "^2.0.0"
}
}
}
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
},
"caller-path": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz",
"integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=",
"requires": {
"callsites": "^0.2.0"
}
},
"callsites": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz",
"integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo="
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
},
"dependencies": {
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"requires": {
"color-convert": "^1.9.0"
}
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"chardet": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I="
},
"circular-json": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
"integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A=="
},
"cli-cursor": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
"integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
"requires": {
"restore-cursor": "^2.0.0"
}
},
"cli-width": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz",
"integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw=="
},
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"requires": {
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"concat-stream": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
"requires": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^2.2.2",
"typedarray": "^0.0.6"
}
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"cross-spawn": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
"integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
"requires": {
"lru-cache": "^4.0.1",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
}
},
"debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"requires": {
"ms": "^2.1.1"
}
},
"deep-is": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
"integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
},
"doctrine": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
"requires": {
"esutils": "^2.0.2"
}
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"eslint": {
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz",
"integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==",
"requires": {
"ajv": "^5.3.0",
"babel-code-frame": "^6.22.0",
"chalk": "^2.1.0",
"concat-stream": "^1.6.0",
"cross-spawn": "^5.1.0",
"debug": "^3.1.0",
"doctrine": "^2.1.0",
"eslint-scope": "^3.7.1",
"eslint-visitor-keys": "^1.0.0",
"espree": "^3.5.4",
"esquery": "^1.0.0",
"esutils": "^2.0.2",
"file-entry-cache": "^2.0.0",
"functional-red-black-tree": "^1.0.1",
"glob": "^7.1.2",
"globals": "^11.0.1",
"ignore": "^3.3.3",
"imurmurhash": "^0.1.4",
"inquirer": "^3.0.6",
"is-resolvable": "^1.0.0",
"js-yaml": "^3.9.1",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.3.0",
"lodash": "^4.17.4",
"minimatch": "^3.0.2",
"mkdirp": "^0.5.1",
"natural-compare": "^1.4.0",
"optionator": "^0.8.2",
"path-is-inside": "^1.0.2",
"pluralize": "^7.0.0",
"progress": "^2.0.0",
"regexpp": "^1.0.1",
"require-uncached": "^1.0.3",
"semver": "^5.3.0",
"strip-ansi": "^4.0.0",
"strip-json-comments": "~2.0.1",
"table": "4.0.2",
"text-table": "~0.2.0"
}
},
"eslint-scope": {
"version": "3.7.3",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz",
"integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==",
"requires": {
"esrecurse": "^4.1.0",
"estraverse": "^4.1.1"
}
},
"eslint-visitor-keys": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
"integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ=="
},
"espree": {
"version": "3.5.4",
"resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz",
"integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==",
"requires": {
"acorn": "^5.5.0",
"acorn-jsx": "^3.0.0"
}
},
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
},
"esquery": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
"integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
"requires": {
"estraverse": "^5.1.0"
},
"dependencies": {
"estraverse": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
"integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ=="
}
}
},
"esrecurse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"requires": {
"estraverse": "^5.2.0"
},
"dependencies": {
"estraverse": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
"integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ=="
}
}
},
"estraverse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="
},
"esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
},
"external-editor": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
"integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
"requires": {
"chardet": "^0.4.0",
"iconv-lite": "^0.4.17",
"tmp": "^0.0.33"
}
},
"fast-deep-equal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
},
"fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"fast-levenshtein": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
},
"figures": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
"integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
"requires": {
"escape-string-regexp": "^1.0.5"
}
},
"file-entry-cache": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
"integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
"requires": {
"flat-cache": "^1.2.1",
"object-assign": "^4.0.1"
}
},
"flat-cache": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz",
"integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==",
"requires": {
"circular-json": "^0.3.1",
"graceful-fs": "^4.1.2",
"rimraf": "~2.6.2",
"write": "^0.2.1"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"functional-red-black-tree": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc="
},
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"globals": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
},
"graceful-fs": {
"version": "4.2.6",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
"integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ=="
},
"has-ansi": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
"requires": {
"ansi-regex": "^2.0.0"
}
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
},
"ignore": {
"version": "3.3.10",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz",
"integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug=="
},
"imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"inquirer": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz",
"integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==",
"requires": {
"ansi-escapes": "^3.0.0",
"chalk": "^2.0.0",
"cli-cursor": "^2.1.0",
"cli-width": "^2.0.0",
"external-editor": "^2.0.4",
"figures": "^2.0.0",
"lodash": "^4.3.0",
"mute-stream": "0.0.7",
"run-async": "^2.2.0",
"rx-lite": "^4.0.8",
"rx-lite-aggregates": "^4.0.8",
"string-width": "^2.1.0",
"strip-ansi": "^4.0.0",
"through": "^2.3.6"
}
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
},
"is-resolvable": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
"integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg=="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
},
"js-tokens": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
},
"js-yaml": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
}
},
"json-schema-traverse": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
},
"json-stable-stringify-without-jsonify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
"integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE="
},
"levn": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
"integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
"requires": {
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2"
}
},
"lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
},
"lru-cache": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
"integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
"requires": {
"pseudomap": "^1.0.2",
"yallist": "^2.1.2"
}
},
"mimic-fn": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
},
"mkdirp": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
"requires": {
"minimist": "^1.2.5"
}
},
"ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"mute-stream": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
},
"natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc="
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1"
}
},
"onetime": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
"integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
"requires": {
"mimic-fn": "^1.0.0"
}
},
"optionator": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
"integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
"requires": {
"deep-is": "~0.1.3",
"fast-levenshtein": "~2.0.6",
"levn": "~0.3.0",
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2",
"word-wrap": "~1.2.3"
}
},
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"path-is-inside": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
"integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM="
},
"pluralize": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
"integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow=="
},
"pokemon": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/pokemon/-/pokemon-2.0.2.tgz",
"integrity": "sha512-lKfv+uUYOut9gO2w21/Nau+aIFF8JIUiuLXAymr09j+ie8oiUOoV2rqX8LhLFWppcz4lEnPNPV5wGPWla0x0wQ==",
"requires": {
"unique-random-array": "^2.0.0"
}
},
"pokemon-node": {
"version": "1.0.0-fix2",
"resolved": "https://registry.npmjs.org/pokemon-node/-/pokemon-node-1.0.0-fix2.tgz",
"integrity": "sha512-0BcJBhbLppCj8JQgmGNSwW458Xh61fXASmY0oCxXm96KbK/ZBKwjBlYwSfB6CsTE1dUpObgYVtAbp8RGY62WFQ==",
"requires": {
"eslint": "^4.19.1",
"snekfetch": "^3.6.4"
}
},
"prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
},
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
},
"pseudomap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
},
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"regexpp": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz",
"integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw=="
},
"require-uncached": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz",
"integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=",
"requires": {
"caller-path": "^0.1.0",
"resolve-from": "^1.0.0"
}
},
"resolve-from": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz",
"integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY="
},
"restore-cursor": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
"integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
"requires": {
"onetime": "^2.0.0",
"signal-exit": "^3.0.2"
}
},
"rimraf": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
"requires": {
"glob": "^7.1.3"
}
},
"run-async": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
"integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ=="
},
"rx-lite": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz",
"integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ="
},
"rx-lite-aggregates": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz",
"integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=",
"requires": {
"rx-lite": "*"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
},
"shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
"integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
"requires": {
"shebang-regex": "^1.0.0"
}
},
"shebang-regex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
},
"signal-exit": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
"integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA=="
},
"slice-ansi": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz",
"integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==",
"requires": {
"is-fullwidth-code-point": "^2.0.0"
}
},
"snekfetch": {
"version": "3.6.4",
"resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz",
"integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw=="
},
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
},
"string-width": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
"requires": {
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^4.0.0"
}
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
},
"strip-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
"requires": {
"ansi-regex": "^3.0.0"
},
"dependencies": {
"ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
}
}
},
"strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
},
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
},
"table": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz",
"integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==",
"requires": {
"ajv": "^5.2.3",
"ajv-keywords": "^2.1.0",
"chalk": "^2.1.0",
"lodash": "^4.17.4",
"slice-ansi": "1.0.0",
"string-width": "^2.1.1"
}
},
"text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ="
},
"through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
},
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
"requires": {
"os-tmpdir": "~1.0.2"
}
},
"type-check": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
"integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
"requires": {
"prelude-ls": "~1.1.2"
}
},
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
},
"unique-random": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/unique-random/-/unique-random-2.1.0.tgz",
"integrity": "sha512-iQ1ZgWac3b8YxGThecQFRQiqgk6xFERRwHZIWeVVsqlbmgCRl0PY13R4mUkodNgctmg5b5odG1nyW/IbOxQTqg=="
},
"unique-random-array": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/unique-random-array/-/unique-random-array-2.0.0.tgz",
"integrity": "sha512-xR87O95fZ7hljw84J8r1YDXrvffPLWN513BNOP4Bv0KcgG5dyEUrHwsvP7mVAOKg4Y80uqRbpUk0GKr8il70qg==",
"requires": {
"unique-random": "^2.1.0"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"requires": {
"isexe": "^2.0.0"
}
},
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"write": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz",
"integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=",
"requires": {
"mkdirp": "^0.5.1"
}
},
"ws": {
"version": "7.4.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.2.tgz",
"integrity": "sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA=="
},
"yallist": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
}
}
}

View File

@ -0,0 +1,16 @@
{
"name": "backend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"bin": {
"gotta-catch-them-all": "./index.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"pokemon": "^2.0.2",
"pokemon-node": "^1.0.0-fix2",
"ws": "^7.4.2"
}
}

View File

@ -0,0 +1,153 @@
{
"Bulbasaur": "grass",
"Ivysaur": "grass",
"Venusaur": "grass",
"Charmander": "fire",
"Charmeleon": "fire",
"Charizard": "fire",
"Squirtle": "water",
"Wartortle": "water",
"Blastoise": "water",
"Caterpie": "bug",
"Metapod": "bug",
"Butterfree": "bug",
"Weedle": "bug",
"Kakuna": "bug",
"Beedrill": "bug",
"Pidgey": "normal",
"Pidgeotto": "normal",
"Pidgeot": "normal",
"Rattata": "normal",
"Raticate": "normal",
"Spearow": "normal",
"Fearow": "normal",
"Ekans": "poison",
"Arbok": "poison",
"Pikachu": "electric",
"Raichu": "electric",
"Sandshrew": "ground",
"Sandslash": "ground",
"Nidoran♀": "poison",
"Nidorina": "poison",
"Nidoqueen": "poison",
"Nidoran♂": "poison",
"Nidorino": "poison",
"Nidoking": "poison",
"Clefairy": "fairy",
"Clefable": "fairy",
"Vulpix": "fire",
"Ninetales": "fire",
"Jigglypuff": "fairy",
"Wigglytuff": "fairy",
"Zubat": "poison",
"Golbat": "poison",
"Oddish": "grass",
"Gloom": "grass",
"Vileplume": "grass",
"Paras": "bug",
"Parasect": "bug",
"Venonat": "bug",
"Venomoth": "bug",
"Diglett": "ground",
"Dugtrio": "ground",
"Meowth": "normal",
"Persian": "normal",
"Psyduck": "water",
"Golduck": "water",
"Mankey": "fighting",
"Primeape": "fighting",
"Growlithe": "fire",
"Arcanine": "fire",
"Poliwag": "water",
"Poliwhirl": "water",
"Poliwrath": "water",
"Abra": "psychic",
"Kadabra": "psychic",
"Alakazam": "psychic",
"Machop": "fighting",
"Machoke": "fighting",
"Machamp": "fighting",
"Bellsprout": "grass",
"Weepinbell": "grass",
"Victreebel": "grass",
"Tentacool": "water",
"Tentacruel": "water",
"Geodude": "rock",
"Graveler": "rock",
"Golem": "rock",
"Ponyta": "fire",
"Rapidash": "fire",
"Slowpoke": "water",
"Slowbro": "water",
"Magnemite": "electric",
"Magneton": "electric",
"Farfetchd": "normal",
"Doduo": "normal",
"Dodrio": "normal",
"Seel": "water",
"Dewgong": "water",
"Grimer": "poison",
"Muk": "poison",
"Shellder": "water",
"Cloyster": "water",
"Gastly": "ghost",
"Haunter": "ghost",
"Gengar": "ghost",
"Onix": "rock",
"Drowzee": "psychic",
"Hypno": "psychic",
"Krabby": "water",
"Kingler": "water",
"Voltorb": "electric",
"Electrode": "electric",
"Exeggcute": "grass",
"Exeggutor": "grass",
"Cubone": "ground",
"Marowak": "ground",
"Hitmonlee": "fighting",
"Hitmonchan": "fighting",
"Lickitung": "normal",
"Koffing": "poison",
"Weezing": "poison",
"Rhyhorn": "ground",
"Rhydon": "ground",
"Chansey": "normal",
"Tangela": "grass",
"Kangaskhan": "normal",
"Horsea": "water",
"Seadra": "water",
"Goldeen": "water",
"Seaking": "water",
"Staryu": "water",
"Starmie": "water",
"Mr. Mime": "psychic",
"Scyther": "bug",
"Jynx": "ice",
"Electabuzz": "electric",
"Magmar": "fire",
"Pinsir": "bug",
"Tauros": "normal",
"Magikarp": "water",
"Gyarados": "water",
"Lapras": "water",
"Ditto": "normal",
"Eevee": "normal",
"Vaporeon": "water",
"Jolteon": "electric",
"Flareon": "fire",
"Porygon": "normal",
"Omanyte": "rock",
"Omastar": "rock",
"Kabuto": "rock",
"Kabutops": "rock",
"Aerodactyl": "rock",
"Snorlax": "normal",
"Articuno": "ice",
"Zapdos": "electric",
"Moltres": "fire",
"Dratini": "dragon",
"Dragonair": "dragon",
"Dragonite": "dragon",
"Mewtwo": "psychic",
"Mew": "psychic"
}

View File

@ -0,0 +1,12 @@
# Gotta Catch 'em All! (Really Fast)
## Text
I am an aspiring new Pokémon trainer that is ready to explore the world and catch many Pokémon. Unfortunately, due to the COVID pandemic, everything will be going digital now. Professor Oak made us a game to play instead, and developed this Pokédex website to register all the Pokémon we caught in the game.
Gary, my rival, bragged to me that he managed to complete the entire Pokédex in under a minute. He probably didn't play the game at all and just selected all the Pokémon on the Pokédex. Whatever the case may be, I intend to beat him, legitimately or not.
The website is connected to a NodeJS backend with a web socket that keeps track of the Pokédex and its completion. Somehow, I must fool the backend that I captured all Pokémon in an insanely fast time, without looking too suspicious. And knowing Professor Oak's programming skills and the fact that its written in JavaScript, there's probably some kind of vulnerability I can abuse.
## Deployment
For the backend: node index.js
For the frontend: Just run it in a http server, for example using http-server (https://www.npmjs.com/package/http-server) which deploys all files in the directory it is called

View File

@ -0,0 +1,13 @@
version: '3.1'
services:
backend:
build: backend
restart: always
ports:
- "5000:5000"
frontend:
build: frontend
restart: always
ports:
- "4000:80"

View File

@ -0,0 +1,3 @@
FROM nginx
COPY . /usr/share/nginx/html

View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script src="index.js"></script>
<link rel="stylesheet" href="styles.css" />
<meta charset="UTF-8">
<title>Pokédex</title>
</head>
<body>
<form>
<label for="pokeselect">Add captured Pokémon</label>
<select id="pokeselect" onchange="catchPokemon()">
<option>Select your Pokémon</option>
</select>
</form>
<h1 id="pokedexTitle">Kanto Pokédex</h1>
<table id="capturedPokemon">
</table>
</body>
</html>

View File

@ -0,0 +1,111 @@
const webSocket = new WebSocket('ws://51.15.125.82:5000')
const waitForOpenConnection = () => {
return new Promise((resolve, reject) => {
const maxNumberOfAttempts = 10
const intervalTime = 200 //ms
let currentAttempt = 0
const interval = setInterval(() => {
if (currentAttempt > maxNumberOfAttempts - 1) {
clearInterval(interval)
reject(new Error('Maximum number of attempts exceeded'))
} else if (webSocket.readyState === webSocket.OPEN) {
clearInterval(interval)
resolve()
}
currentAttempt++
}, intervalTime)
})
}
async function send(msg, data) {
await waitForOpenConnection();
webSocket.send(JSON.stringify({msg, data}))
}
let pokedex = {}
webSocket.onmessage = evt => {
const {msg, data} = JSON.parse(evt.data);
switch (msg) {
case 'pokedexUpdated': pokedex = data; showPokedex(); break;
case 'pokedexInitialized': pokedex = data; initGUI(); break;
case 'pokedexCompleted': window.alert(data.msg); break;
case 'error': window.alert(data.msg); break;
}
}
function fillInPokémons(pkdx) {
window.setTimeout(() => {
send('updatePokedex', {pokemon: pkdx[0], values: {captured: true}})
fillInPokémons(pkdx.slice(1))
}, 200)
}
function initializePokedex() {
send('initializePokedex')
}
initializePokedex()
function initGUI() {
const selection = document.getElementById("pokeselect");
const options = Object.entries(pokedex).map(([pokemon, properties]) => {
const option = document.createElement("option")
option.setAttribute("value", pokemon)
option.append(pokemon)
return option
})
selection.append(...options);
showPokedex();
}
function catchPokemon() {
const selection = document.getElementById("pokeselect").value;
send('updatePokedex', {pokemon: selection, values: {captured: true}})
}
function showPokedex() {
const container = document.getElementById("capturedPokemon");
container.textContent = '';
const pokedexTable = Object.entries(pokedex)
.reduce((acc, val) =>
(acc[acc.length - 1].length === 5)
? [...acc, [val]]
: [...acc.slice(0, acc.length - 1), [...acc[acc.length - 1], val]],
[[]]
)
const pokedexGUI = pokedexTable.map((pokeRow, colNum) => {
const ths = pokeRow.map(([pokemon, properties], rowNum) => {
const th = document.createElement("th");
th.setAttribute("class", "pokecell")
if(properties.captured) {
const img = document.createElement("img");
const htmlFriendlyPokeName = pokemon
.toLowerCase()
.replace("♀", "-f")
.replace("♂", "-m")
.replace("", "")
.replace(". ", "-")
img.setAttribute("src", `https://img.pokemondb.net/artwork/${htmlFriendlyPokeName}.jpg`);
img.setAttribute("height", "100");
img.setAttribute("width", "100");
const name = document.createElement("h2")
name.innerText = pokemon
th.append(img, name)
} else {
const name = document.createElement("h1")
name.innerText = `${colNum * 5 + rowNum + 1}`
th.append(name)
}
return th
})
const tr = document.createElement("tr");
tr.append(...ths)
return tr
})
container.append(...pokedexGUI)
}

View File

@ -0,0 +1,3 @@
{
"lockfileVersion": 1
}

Binary file not shown.

View File

@ -0,0 +1,44 @@
@font-face {
font-family: pokefont;
src: url(./pokefont.ttf);
}
.pokecell {
text-align: center;
min-width: 200px;
width: 200px;
max-width: 200px;
min-height: 200px;
height: 200px;
max-height: 200px;
border: 3px solid black;
}
#capturedPokemon {
/*display: flex;
justify-content: center;
align-items: center;*/
margin-left: auto;
margin-right: auto;
}
h1 {
text-align: center;
}
form {
text-align: center;
border: 2px solid black;
padding: 1rem;
margin-left: 40%;
margin-right: 40%;
}
#pokedexTitle {
font-family: pokefont;
letter-spacing: 7px;
color: yellow;
font-size: 5rem;
-webkit-text-stroke-width: 3px;
-webkit-text-stroke-color: blue;
}

View File

@ -0,0 +1,15 @@
{ pkgs ? import <nixpkgs> {} }:
let app = (pkgs.callPackage ../backend/default.nix {}).package ;
in
pkgs.dockerTools.buildImage {
name = "gotta-catch-them-all-backend";
tag = "latest";
contents = [ pkgs.nodejs app ];
config = {
ExposedPorts = {
"5000/tcp" = {};
};
Cmd = [ "${pkgs.nodejs}/bin/node" "${app}/bin/gotta-catch-them-all" ];
};
}

View File

@ -0,0 +1,38 @@
{ pkgs ? import <nixpkgs> {} }:
let utils = import ../../../deployment/utils.nix ;
nginx_conf = pkgs.writeTextFile {
name = "nginx.conf";
text= ''
user root;
daemon off;
error_log /dev/stdout info;
pid /dev/null;
events {}
http {
access_log /dev/stdout;
server {
listen 80;
index index.html;
root ${../frontend};
}
}
'';
};
in
pkgs.dockerTools.buildImage {
name = "frontend-gotta-catch-them-all";
tag = "latest";
contents = [ pkgs.nginx ] ;
runAsRoot = ''
${pkgs.dockerTools.shadowSetup}
mkdir -p var/log/nginx
mkdir -p var/cache/nginx
'';
config = {
ExposedPorts = {
"80/tcp" = {};
};
Cmd = [ "${pkgs.nginx}/bin/nginx" "-c" "${nginx_conf}" ];
} ;
}

View File

@ -0,0 +1,16 @@
# I am from ancient Greece
## Text
A group of archeologists managed to find some notes of an ancient Greek philosopher. Unfortunately, because his philosophy is so complex, it cannot simply be put into plain mortal words. Thus, he encrypted it using a Polybius square (see attached file)! Can you unravel his wise words? This is what was written on the scroll:
24-13-43-44-51-{-44-15-44-42-11-22-15-14-42-35-33-}
## Files
- polybius.png
## How To Solve
Difficulty: Easy
Every pair of numbers corresponds to a greek letter in the polybius square. Translate the letters (https://en.wikipedia.org/wiki/Greek_alphabet) and you get the key in Latin alphabet
## Flag
IGCTF{TETRAHEDRON}

View File

@ -0,0 +1,8 @@
# I am from ancient Greece
## Text
A group of archeologists managed to find some notes of an ancient Greek philosopher. Unfortunately, because his philosophy is so complex, it cannot simply be put into plain mortal words. Thus, he encrypted it using a Polybius square (see attached file)! Can you unravel his wise words? This is what was written on the scroll:
24-13-43-44-51-{-44-15-44-42-11-22-15-14-42-35-33-}
## Files
- polybius.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

3
lost-keys/Dockerfile Normal file
View File

@ -0,0 +1,3 @@
FROM linuxserver/openssh-server:latest
COPY ./flag.txt /home/joske/

78
lost-keys/README.md Normal file
View File

@ -0,0 +1,78 @@
== Title ==
Lost My Keys
== Description ==
There's this old server which I haven't accessed in years. It seems that I have forgotten the password...
I left some important files on that server. Can you help me get access again and recover my files?
There should still be an ssh server running on port 2222.
I made a disk image of the computer that I used to have access with a long time ago, maybe you can figure something out?
IP address of the server:
Hint: Don't bother trying to brute-force the password.
== Flag ==
IGCTF{TheyWereInMyJacket!}
== Files ==
Participants should receive the disk.zip file.
== Deployment ==
The docker container providing an ssh server with a flag in it needs to be deployed.
== Solution/Writeup ==
<---- Filler ---->
Unzip the disk.zip file to find the ISO of an ext4 file system.
Mount the iso using mount:
mount disk.iso /mnt
Navigate to the only home directory. Its name is joske.
This will also be the username used to login to the ssh server.
You should now notice that there is an empty .ssh directory.
The title "lost my keys" hints at a possibility for using ssh keys.
The ssh private key is deleted but not lost. You should be able to recover it using standard recovery tools. An easier way is to simply grep for the string "OPENSSH" on the entire iso and add enough context to read the full key.
strings disk.iso | grep -A 50 "OPENSSH" | less
The private key should be present in the output, copy it into a file (e.g., called key).
Next, simply login to the ssh server using the private key.
ssh -p 2222 -i key joske@<IP> (TODO fill in IP)
Finally, go to the home directory of joske and read the flag file:
cd /home/joske
cat flag.txt

25
lost-keys/bliep.md Normal file
View File

@ -0,0 +1,25 @@
== Title ==
Lost My Keys
== Description ==
There's this old server which I haven't accessed in years. It seems that I have forgotten the password...
I left some important files on that server. Can you help me get access again and recover my files?
There should still be an ssh server running on port 2222.
I made a disk image of the computer that I used to have access with a long time ago, maybe you can figure something out?
IP address of the server:
Hint: Don't bother trying to brute-force the password.
== Files ==
Participants should receive the disk.zip file.
== Deployment ==
The docker container providing an ssh server with a flag in it needs to be deployed.
Run ./docker_run.sh voor de ssh server, dan bolt em op localhost:2222 (docker moet geinstalleerd zijn).
@Benjamin Niet lui zijn en dit skippen, gewoon docker installeren gij patattenzak.
Forensics challenge
70 punten

BIN
lost-keys/disk.zip Normal file

Binary file not shown.

27
lost-keys/docker_run.sh Executable file
View File

@ -0,0 +1,27 @@
#!/bin/sh
docker kill lost-keys
docker rm lost-keys
docker build -t lost-keys .
docker run -d \
--name=lost-keys \
-e PUID=1000 \
-e PGID=1000 \
-e TZ=Europe/Brussels \
-e USER_NAME=joske \
-e SUDO_ACCESS=false \
-e PASSWORD_ACCESS=true \
-e USER_PASSWORD="hvfu7s7xBNGe6Rxa" \
-e PUBLIC_KEY="ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDO2F8WY5XTTcCapt0QhOOAetHTkdBJo+mc/bJ6oRg/0FJ9Ro74yZxcqOTbyEPf/khg9qY9TKf121CaXvJJSLmv3U20X15UlHnDPrh+EsRiCMaiMGd/N+l1ZQ+grj1klcblYxSt7nKtLhh36JaC9A6olFF8ahzcm1Rl69tE4bLdKqALpAbhbTmTlofIH1dzGDF31EfJeLZnuV5XRLq9XCF2YJkbyUJjeBs+4iHQFWxZFfYZJBMAYFLkNrmYvsKjwgwHBEC/g2nCRvW/0KhkXl/N8NU5jXw67Snf/unqD8JmC7Or3GgKT6+sdthbi2dWO4beSEnVoijmvFt+2uwSwU97tij7a7j6Z+J7ekkDDbt8Due1CxNL7sBcIbB22ELC0WwpEijzYC+RaCtiRegzEuGJui9wdjX7kOKxEobSVfSHgzzrT6FJWdThnQ4SZ2vsF6Yt5OjyXNI5TRiNv9DZAYdK6KNyxsxjEmkVZc1JGAsWzdq/GcBH1MilrK5w97JYat8= nibor@Rylia" \
-p 2222:2222 \
--restart unless-stopped \
lost-keys
# Permissions set in Dockerfile are overwritten
# For some reason, it doesn't work immediately
sleep 3s
docker exec lost-keys chmod -R -w /config
docker exec lost-keys chmod -R +w /config/logs

1
lost-keys/flag.txt Normal file
View File

@ -0,0 +1 @@
IGCTF{TheyWereInMyJacket!}

33
lost-keys/image.nix Normal file
View File

@ -0,0 +1,33 @@
{ pkgs ? import <nixpkgs> {} }:
let utils = import ../deployment/utils.nix {} ;
files = [
(utils.copy ./flag.txt "home/joske/flag.txt")
(pkgs.writeTextDir "home/joske/.ssh/authorized_keys" ''
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDO2F8WY5XTTcCapt0QhOOAetHTkdBJo+mc/bJ6oRg/0FJ9Ro74yZxcqOTbyEPf/khg9qY9TKf121CaXvJJSLmv3U20X15UlHnDPrh+EsRiCMaiMGd/N+l1ZQ+grj1klcblYxSt7nKtLhh36JaC9A6olFF8ahzcm1Rl69tE4bLdKqALpAbhbTmTlofIH1dzGDF31EfJeLZnuV5XRLq9XCF2YJkbyUJjeBs+4iHQFWxZFfYZJBMAYFLkNrmYvsKjwgwHBEC/g2nCRvW/0KhkXl/N8NU5jXw67Snf/unqD8JmC7Or3GgKT6+sdthbi2dWO4beSEnVoijmvFt+2uwSwU97tij7a7j6Z+J7ekkDDbt8Due1CxNL7sBcIbB22ELC0WwpEijzYC+RaCtiRegzEuGJui9wdjX7kOKxEobSVfSHgzzrT6FJWdThnQ4SZ2vsF6Yt5OjyXNI5TRiNv9DZAYdK6KNyxsxjEmkVZc1JGAsWzdq/GcBH1MilrK5w97JYat8= nibor@Rylia
'')
] ;
in
pkgs.dockerTools.buildImage {
name = "lost-keys";
tag = "latest";
contents = files ++ [ pkgs.busybox ];
runAsRoot = ''
${pkgs.dockerTools.shadowSetup}
useradd -U -m joske
mkdir -p /home/joske/
chown -R joske:joske /home/joske/
echo "joske:hvfu7s7xBNGe6Rxa" | chpasswd
mkdir -p /root
${pkgs.dropbear}/bin/dropbearkey -t rsa -f /root/hostkey
chmod o-r /root/hostkey
chmod -R -w /home/joske/
'';
config = {
ExposedPorts = {
"2222/tcp" = {};
};
Cmd = [ "${pkgs.dropbear}/bin/dropbear" "-r" "/root/hostkey" "-F" "-g" "-j" "-k" "-p" "2222" ];
};
}

View File

@ -0,0 +1,39 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAzthfFmOV003AmqbdEITjgHrR05HQSaPpnP2yeqEYP9BSfUaO+Mmc
XKjk28hD3/5IYPamPUyn9dtQml7ySUi5r91NtF9eVJR5wz64fhLEYgjGojBnfzfpdWUPoK
49ZJXG5WMUre5yrS4Yd+iWgvQOqJRRfGoc3JtUZevbROGy3SqgC6QG4W05k5aHyB9Xcxgx
d9RHyXi2Z7leV0S6vVwhdmCZG8lCY3gbPuIh0BVsWRX2GSQTAGBS5Da5mL7Co8IMBwRAv4
Npwkb1v9CoZF5fzfDVOY18Ou0p3/7p6g/CZguzq9xoCk+vrHbYW4tnVjuG3khJ1aIo5rxb
ftrsEsFPe7Yo+2u4+mfie3pJAw27fA7ntQsTS+7AXCGwdthCwtFsKRIo82AvkWgrYkXoMx
LhibovcHY1+5DisRKG0lX0h4M860+hSVnU4Z0OEmdr7BemLeTo8lzSOU0Yjb/Q2QGHSuij
csbMYxJpFWXNSRgLFs3avxnAR9TIpayucPeyWGrfAAAFgCbLOeAmyzngAAAAB3NzaC1yc2
EAAAGBAM7YXxZjldNNwJqm3RCE44B60dOR0Emj6Zz9snqhGD/QUn1GjvjJnFyo5NvIQ9/+
SGD2pj1Mp/XbUJpe8klIua/dTbRfXlSUecM+uH4SxGIIxqIwZ3836XVlD6CuPWSVxuVjFK
3ucq0uGHfoloL0DqiUUXxqHNybVGXr20Thst0qoAukBuFtOZOWh8gfV3MYMXfUR8l4tme5
XldEur1cIXZgmRvJQmN4Gz7iIdAVbFkV9hkkEwBgUuQ2uZi+wqPCDAcEQL+DacJG9b/QqG
ReX83w1TmNfDrtKd/+6eoPwmYLs6vcaApPr6x22FuLZ1Y7ht5ISdWiKOa8W37a7BLBT3u2
KPtruPpn4nt6SQMNu3wO57ULE0vuwFwhsHbYQsLRbCkSKPNgL5FoK2JF6DMS4Ym6L3B2Nf
uQ4rEShtJV9IeDPOtPoUlZ1OGdDhJna+wXpi3k6PJc0jlNGI2/0NkBh0roo3LGzGMSaRVl
zUkYCxbN2r8ZwEfUyKWsrnD3slhq3wAAAAMBAAEAAAGAUh6/KaFh42FUHVIwJBXOSLz6Px
f97K6h2g0y5dK9UOCBT3FK4+UPKg53xfYtVGmdDLn/6AheCpMG3jLh2EyCRBsFdZ4DUmsc
KHLnRk5nH1DCo7O5810cV9pGqRFkGGIKdBmxJRis+Kp7VmfGEbmZdD5mV5G9YaxdhpVsGV
3N6Fa68cQuYyM9H6Y8xCwFSRGK2jsyQP+m02lZ1iXYScOhGWFiiBCQRfNyRbX7nKRUvs2k
Rfj3fke/wRElAEqD9gXcj9cjy3DHCZMuTw7RFaUbL69Wsffw3A3bakeiQd0vW3AChx23+j
FY50NODnpAfQp4seEPZMeyGpIaXDB2bvd3uG6T4jsGK5eY9A4WDOgybTQU+kg2hxQWXp8t
5O/ayDlu0IFGiOWt8CQu8LabVJDmDWsGvZS8gLpOljEKo7eUCPYXVGTghg1MfZZXbRFDaG
2AV13PX5aecnL2av5mmpl4/+yGN/iut+mdsh3w7HNcuNGAbgZ85Na8WYCY1fYCjRBhAAAA
wF7vcDZOHz+upLdM+4R4J85SS5K0MavYU+waCem0G+p1YpU/jWdyOG73dfpu2FVJEN1gtQ
WZkpmPVdaUmkj7mpmq1eIHO31mT2Yoww4duLpR1Za1lOcZmVsBOu0mp1kOr8UPS9M2vrVz
ENJscsY6IRBvbeqUg3te3GdneRoC1SiZCzG48FRcA5VJ+TM427A8RpOL/jTDA13Pnooxo0
jBgcflcmID+Id5qhfg5XsAogrmq3iv+ETVGc8UxD6FeMTQNQAAAMEA5+lN+eDVQNA/tPWO
RC3ZHDkR9diL1c5/aQl+XPmZiiaIQW6HsajACn+1pPoJlEe1QMEfRr9CBOsHbf9nLa9GV+
Q6H1tgUjOPClInm4Sg1RLDs05DvKnXYzYgpIvGj0sJf/A6sBXSaf+THBDTrM5mgGTWbygW
uB26MUggcKG4DlL70+LeZyEDBkCq6ViiGU8Jd8Ei3UkIuDKtyToRI1GxN68vTVPtAYde5B
h+n6Vjjiitk12HFE/1+/WQ02t3U3dxAAAAwQDkVIoUaPfgM3F46czRA3chitWU5EQibJsE
IzIOocCtikwZe0u4Q5JIz/44+vLQpvghpeQBJ7oBA9ehLVp+lrofywDY3foKHT0FvpE0Y+
POU3Cjjp5kN7ivgZnWHmb3z2Zj55rduINAjkb51PkF21/tT63Kk37u2LF2ZegKubgOKLR1
WvuqP/Ue78FVvVOwoixwu/SgZagjxEm/n9sIUtUbYreHSdFQtxe7zwORLB4AwdCy9niNFi
mHYLnr6qjt/08AAAALbmlib3JAUnlsaWE=
-----END OPENSSH PRIVATE KEY-----

View File

@ -0,0 +1,13 @@
#!/bin/bash
# $1: IP, $2: Port
RES=$(ssh -p $2 -i id_rsa joske@$1 "cat flag.txt")
echo $RES
if [[ "$RES" == *"IGCTF"* ]]; then
exit 0
else
exit 1
fi

0
mad_cows/.gitkeep Normal file
View File

15
mad_cows/bliep.md Normal file
View File

@ -0,0 +1,15 @@
# Title
Mad cows
# Description
Because of corona there are no standup comedy acts no more, to flower up your day I have provided you with an audio element of Geert Hoste a belgian comedian.
Corona is said to be started by eating bats, we'll the mad cow disease has presumable started after Belgian prime minister Jean-Luc Dehaene sat on a pneumatic bull shouting the phrase "let the beast go" in 1995.
# files
mad_cows_geert_hoste.mp3
# deployment
n/a
# type
Steganography

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More