From 3d6faeacd52ce0909b884e7bb612762040577672 Mon Sep 17 00:00:00 2001 From: Lorin Werthen Date: Sun, 25 Feb 2018 20:29:35 +0100 Subject: [PATCH 01/25] Reports --- Gemfile | 3 + Gemfile.lock | 18 ++-- Rules | 17 +++- content/about/verslagen.erb | 8 +- content/about/verslagen/17-18/2018-02-12.md | 103 ++++++++++++++++++++ lib/filters/pandoc_pdf.rb | 18 ++++ lib/helpers/preprocess.rb | 7 ++ lib/helpers/reports.rb | 5 + lib/helpers_.rb | 1 + 9 files changed, 169 insertions(+), 11 deletions(-) create mode 100644 content/about/verslagen/17-18/2018-02-12.md create mode 100644 lib/filters/pandoc_pdf.rb create mode 100644 lib/helpers/reports.rb diff --git a/Gemfile b/Gemfile index feb18d3..df22901 100644 --- a/Gemfile +++ b/Gemfile @@ -19,6 +19,9 @@ gem 'therubyracer' # for reading time gem 'words_counted' +# Compiling reports from .md to .pdf +gem 'pandoc-ruby' + group :development do gem 'adsf' gem 'highline' diff --git a/Gemfile.lock b/Gemfile.lock index db36c53..157a130 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -21,11 +21,11 @@ GEM csspool-st (= 3.1.2) json csspool-st (3.1.2) - ddmemoize (1.0.0a3) - ddtelemetry (= 1.0.0a2) + ddmemoize (1.0.0) + ddmetrics (~> 1.0) ref (~> 2.0) + ddmetrics (1.0.0) ddplugin (1.0.1) - ddtelemetry (1.0.0a2) execjs (2.7.0) ffi (1.9.18) formatador (0.2.5) @@ -66,13 +66,14 @@ GEM css_press multi_js (0.1.0) uglifier (~> 2) - nanoc (4.8.19) + nanoc (4.9.1) addressable (~> 2.5) cri (~> 2.8) - ddmemoize (= 1.0.0a3) + ddmemoize (~> 1.0) + ddmetrics (~> 1.0) ddplugin (~> 1.0) - ddtelemetry (= 1.0.0a2) hamster (~> 3.0) + parallel (~> 1.12) ref (~> 2.0) slow_enumerator_tools (~> 1.0) nenv (0.3.0) @@ -81,10 +82,12 @@ GEM notiffany (0.1.1) nenv (~> 0.1) shellany (~> 0.0) + pandoc-ruby (2.0.2) + parallel (1.12.1) pry (0.11.3) coderay (~> 1.1.0) method_source (~> 0.9.0) - public_suffix (3.0.1) + public_suffix (3.0.2) rack (2.0.3) rb-fsevent (0.10.2) rb-inotify (0.9.10) @@ -126,6 +129,7 @@ DEPENDENCIES icalendar kramdown nanoc + pandoc-ruby sass terminal-notifier terminal-notifier-guard diff --git a/Rules b/Rules index 13f885b..9b74250 100644 --- a/Rules +++ b/Rules @@ -19,6 +19,7 @@ preprocess do create_yearly_items('Blog') create_yearly_items('Events') convert_event_time_to_timestamps + add_report_metadata end # @@ -99,11 +100,11 @@ end # compile '/projects/*' do filter :kramdown + + # Don't write out the projects themselves for now + write nil end -# Don't create specific project pages for now -route '/projects/*' do; end - compile '/*_search.json' do filter :erb end @@ -112,6 +113,16 @@ compile '/**/*.ics' do filter :erb end +# +# REPORTS +# + +compile '/about/verslagen/*/*.md', rep: :pdf do + filter :pandoc_pdf, args: { f: :markdown } + + write ext: 'pdf' +end + # # GENERIC ERB PAGES # diff --git a/content/about/verslagen.erb b/content/about/verslagen.erb index d1a9b10..c765ea1 100644 --- a/content/about/verslagen.erb +++ b/content/about/verslagen.erb @@ -1,3 +1,9 @@
-

Verslagen

+

Reports

+ <% reports.group_by {|r| r[:academic_year]}.each do |year, y_reports| %> +

<%= year %>

+ <% y_reports.each do |report| %> + Report <%= report[:date].strftime('%d %B %Y') %>
+ <% end %> + <% end %>
diff --git a/content/about/verslagen/17-18/2018-02-12.md b/content/about/verslagen/17-18/2018-02-12.md new file mode 100644 index 0000000..82a93e7 --- /dev/null +++ b/content/about/verslagen/17-18/2018-02-12.md @@ -0,0 +1,103 @@ +% Bestuursvergadering 3 +% Isaura Claeys +% 21/02/2018 - 17:25 + +# Verslag vorige vergadering + Check + +# Financiën +* WVK Subsidies + * Goedgekeurd: +50 euro extra tov AJ 2016-2017 (1100 in totaal) +* Overzicht + * 650 op de bank + * 220 in de kassa + * Hydra: 1029 terugkrijgen voor Hydra + * Stuw moeten we ook terugkrijgen + * 1800 hebben we atm in totaal + * 839 tab schulden atm +* TV + * Mailen als subsidies bij DSA verwerkt zijn +* Partnerships + * Aparte mailinglijst waar leden zich op kunnen uitschrijven als nodig + * Pakketten aanbieden + 1. Evenement (50) + 2. Vacature mailinglijst/site + 3. Logo op poster/site (enkel bij sponsoring event) + 4. Codenights sponsoren + 5. Prijzen sponsoren + 6. 1 pakket met combinatie van alles + * Wie? Timo + * Ocean Garden en Ocean Garden codenight? + * Timo organiseert aparte vergadering hiervoor +* Lorin is een tomaat, want hij heeft voor de eerste keer in 10 jaar 100 meter gefietst. +* Ereleden + * Kandidaten: pietervdv + * Minimum 50 euro: poster + site (optioneel) + * Dino doet dingen + +# Sysadmin +* Deployen MOZAIC + * Met Wout afspreken +* Dingen mogen gebeuren + * Asana + +# Activiteiten +* Hashcode + * Delhaizerun vrijdag + * Extra locatie + * 300 euro aan pizza’s: Lorin en Rien +* VPW + * We zijn ervoorbij + * In orde! + * Bus zit vol! + * Je bent goed bezig! + * Behalve Lorin en zijn potentieel team van Wout zijn lief +* Ceneka Talks + * 18 april + * Delaware komt + * Maar wie weet waar het over gaat + * Camera bij DICT regelen + * Eten regelen avond zelf + * Barmensen regelen +* Lightning talks + * Komt in orde +* 12Urenloop + * Jeroen wordt teamlead IT + * Volgende vrijdag 12UL codenight + * Tent: Feliciaan vragen hoe subsidieren? +* HTTPizza + * Momenteel afgelast + +# Projecten updates + * MOZAIC + * Intel AI ding van maken if need be + * Meer bestuur rond krijgen nu + 1. Organiseren + inplannen + promo + * Inplannen introductie (presentatie etc.) + * Rien gaat helpen! + * Volgende donderdagmiddag: 11.30u + * Hydra + * Dingen gaan vooruit + * Feli gaat traag + * Lekker + * G2 + * Verschil met gamification: stats zijn een bijzaak, doel is participatie verhogen + +# Discussiepunten +* Rien zegt iets: Ik stel voor dat we eventueel toekomstige bestuursleden bij het bestuur beginnen betrekken. + - Niet bij vergaderingen betrekken + +# Trivia +* Cegeka antwoorden + * Timo + die andere partnership mail +* VEK antwoorden + * wout +* Wina Antwoorden + * Infodinges voor de master informatica + * Rien + +# Vrij moment +Ilion doet een bekentenis: Ik lees mijn mails nooit. + + +# Todo's: diff --git a/lib/filters/pandoc_pdf.rb b/lib/filters/pandoc_pdf.rb new file mode 100644 index 0000000..f66613e --- /dev/null +++ b/lib/filters/pandoc_pdf.rb @@ -0,0 +1,18 @@ +require 'pandoc-ruby' +require 'fileutils' + +class PandocPDF < Nanoc::Filter + identifier :pandoc_pdf + type text: :binary + + def run(content, params = {}) + # https://github.com/nanoc/nanoc/blob/master/nanoc/lib/nanoc/filters/pandoc.rb + args = params.key?(:args) ? params[:args] : params + + args[:o] = output_filename + '.pdf' + + PandocRuby.convert(content, *args) + + FileUtils.mv(output_filename + '.pdf', output_filename) + end +end diff --git a/lib/helpers/preprocess.rb b/lib/helpers/preprocess.rb index a8e5c96..7e4bd46 100644 --- a/lib/helpers/preprocess.rb +++ b/lib/helpers/preprocess.rb @@ -50,4 +50,11 @@ module PreprocessHelper event[:end] = DateTime.parse(event[:end]) if event[:end] end end + + def add_report_metadata + @items.find_all('/about/verslagen/*/*').each do |report| + report[:academic_year] = report.identifier.to_s.split('/')[-2] + report[:date] = Date.strptime(report.identifier.without_ext.split('/').last) + end + end end diff --git a/lib/helpers/reports.rb b/lib/helpers/reports.rb new file mode 100644 index 0000000..3e952af --- /dev/null +++ b/lib/helpers/reports.rb @@ -0,0 +1,5 @@ +module ReportsHelper + def reports + @items.find_all('/about/verslagen/*/*').sort_by(&:identifier).reverse + end +end diff --git a/lib/helpers_.rb b/lib/helpers_.rb index 180a4c1..065cccd 100644 --- a/lib/helpers_.rb +++ b/lib/helpers_.rb @@ -21,3 +21,4 @@ include PreprocessHelper include TimeHelper include TileHelper include AboutHelper +include ReportsHelper From 2697778ec7b4f2c831999431591afe52306c28b5 Mon Sep 17 00:00:00 2001 From: Lorin Werthen Date: Sun, 25 Feb 2018 20:36:13 +0100 Subject: [PATCH 02/25] let's try this, also fixes #99 --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2896159..5a6bdd2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,10 @@ before_install: -in id_rsa.enc -out deploy_key -d - echo -e "Host zeus.ugent.be\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config - npm install +- sudo apt-get update -qq +- sudo apt-get install -y pandoc +- sudo apt-get install -y texlive-full +- sudo apt-get install -y texlive-xetex script: - bundle exec nanoc --env=prod - bundle exec nanoc --env=prod check --deploy From 58a05622902a960fe1429b8ef33bc839d5b1fedf Mon Sep 17 00:00:00 2001 From: Lorin Werthen Date: Sun, 25 Feb 2018 22:57:56 +0100 Subject: [PATCH 03/25] speedup maybe? --- .travis.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5a6bdd2..8860300 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,19 @@ language: ruby cache: + apt: true bundler: true # Cache nanoc directories directories: - output - tmp +addons: + apt: + packages: + - pandoc + - texlive-full + branches: only: - master @@ -21,10 +28,6 @@ before_install: -in id_rsa.enc -out deploy_key -d - echo -e "Host zeus.ugent.be\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config - npm install -- sudo apt-get update -qq -- sudo apt-get install -y pandoc -- sudo apt-get install -y texlive-full -- sudo apt-get install -y texlive-xetex script: - bundle exec nanoc --env=prod - bundle exec nanoc --env=prod check --deploy From 35ce5519295b7f1e78b52d60d26277ac7158c032 Mon Sep 17 00:00:00 2001 From: Lorin Werthen Date: Thu, 1 Mar 2018 14:42:53 +0100 Subject: [PATCH 04/25] more report and navbar --- content/about/verslagen/17-18/2017-11-20.md | 94 +++++++++++++++++++++ layouts/partials/_about_sub_navbar.erb | 2 +- 2 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 content/about/verslagen/17-18/2017-11-20.md diff --git a/content/about/verslagen/17-18/2017-11-20.md b/content/about/verslagen/17-18/2017-11-20.md new file mode 100644 index 0000000..2763a35 --- /dev/null +++ b/content/about/verslagen/17-18/2017-11-20.md @@ -0,0 +1,94 @@ +% Bestuursvergadering 2 +% Isaura Claeys +% Datum: 20/11/2017 - 13:00 + +Status: Gesloten + +# Verslag vorige vergadering +* https://docs.google.com/document/d/1JTZ3PmzZfooRkfUjZCoBqdfzMDKA31XdfpiwaR1qPWE/edit + + +# Financiën +* Afronden subsidies dit jaar + * Deadline 1 december + * 130 euro aan subsidies + * 381 euro op rekening + 600 in de kassa + * Verhoging prijzen drank publieke events (bvb Hashcode) voor niet-leden (afronden naar boven) + * Tab + 1. fixen codenight + overleggen met benji + 2. Mails sturen + * Hydra + 1. Veel te veel geld over + 2. IPad gekocht (voorgeschoten door timo) + 3. T-Shirts +* Terugbetaling Giant Progressbar destro +* Terugbetaling MOZAIC codenight drinks destro + + +# Sysadmin +* Sysadmini’s + * Lorin kuist asana op + voegt nieuwe sysadmini’s toe + + +# Activiteiten +* Lan: Alles in orde? (competities ed.) + * Sigasi contacteren met winnaars + * Jeroen moet stoppen met tam zijn +* Internet freedom + * https://docs.google.com/document/d/1zgM6jF2mmNyfXKi_SHFMZYLywnJvLPDq0sLxAxb9Bps/edit# + * Mensen fixen +* Talk Delaware + * Datum 18/04 + * Verantwoordelijke: Laurens, Wout en elo helpen +* Ricing-avond 04/12 + * Tiles & Terminals 2 + * Ideeën? + 1. Blogpost met links + 2. Korte demo’s met workflow tips + 3. Oproep om mensen te vinden die hun setup willen showen + 4. Felix, Detlev, Ketnet, Rien + * Brainstormavond met Detlev: DOODLE + * Workflow stresstesting + * Contest: om ter snelst typen op een mechanisch toetsenbord +* Feli talk (GDPR) + * Europees dataprotocol + * Via GSR? +* E&F avond + * FP progtalen gebruiken? + * Uitstellen naar 2de semester: 2de week + * Eerstejaars optrommelen + * DOODLE voor brainstorm +* Pannenkoeken en Jenever Codenight-Avond + * HELL YEAH + * 30 november TBD +* Blogposts/Eventposts schrijven voor vastgepinde events! + * Tiles & terminals + * Delaware talk: + 1. Poster + 2. Blogpost +* Vlaamse Programmeerwedstrijd! + * Jonathan + isaura + * Poke andy + +# Projecten updates +* 12Urenloop + * Crew: Ziggy + Jonathan + Tibo +* G2 + * Gamification 2 + * Project en event management tool +* MOZAIC + * 2de grote mozaic-codenight + * React rewrite gaat vooruit + +# Discussiepunten + +# Trivia +* Slotmachien was kapot: Jeroen merkt op dat als ge gewoon regelmatig es moet aanduwen, dan kan hij er niet van vallen. +* Heeft Ilion de sleutel van Stijn? -> Neen. +* Wanneer zeuswpi.org gebruiken? + * Komt bij asana taakjes + * Certificaten aanvragen + +# Vrij moment + +# Todo's diff --git a/layouts/partials/_about_sub_navbar.erb b/layouts/partials/_about_sub_navbar.erb index 5dcbe8c..0c4872d 100644 --- a/layouts/partials/_about_sub_navbar.erb +++ b/layouts/partials/_about_sub_navbar.erb @@ -4,6 +4,6 @@
  • Contact
  • Statuten
  • Historiek
  • -
  • Verslagen (soon)
  • +
  • Verslagen
  • From 5bd9087282bdada0ae4d814ca49871c81193c27f Mon Sep 17 00:00:00 2001 From: Wout Schellaert Date: Thu, 1 Mar 2018 16:50:07 +0100 Subject: [PATCH 05/25] Add pandoc and tex requirements to readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 285d4a4..39342dd 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,8 @@ bundle install npm install ``` +You will (momentarily) also need `pandoc` and `latex` to compile the reports from the board meetings. Refer to your OS package manager to install these things. + These will pull in all Ruby and Node.js dependencies. If everything goes well, you should be able to execute the following. ```bash From cde10fd3d112f3329be0dca6dd8c3ac1001220b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elo=C3=AFse=20Piret?= Date: Thu, 1 Mar 2018 16:44:28 +0100 Subject: [PATCH 06/25] add mozaic and site, remove bottle bats --- content/assets/images/mozaic.png | Bin 0 -> 57588 bytes content/projects/badass_bottle_bats.md | 8 -------- content/projects/mozaic.md | 8 ++++++++ content/projects/site.md | 8 ++++++++ 4 files changed, 16 insertions(+), 8 deletions(-) create mode 100644 content/assets/images/mozaic.png delete mode 100644 content/projects/badass_bottle_bats.md create mode 100644 content/projects/mozaic.md create mode 100644 content/projects/site.md diff --git a/content/assets/images/mozaic.png b/content/assets/images/mozaic.png new file mode 100644 index 0000000000000000000000000000000000000000..e453967f7ef04d84419d95754d4b23c2c54322a3 GIT binary patch literal 57588 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≫9s8)baT1(`qAXe>$+Kjhv!qPMRY__QO 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 b;r1W;{?T|X%d{lr69C{aBdv<-4pILFoi*s@ literal 0 HcmV?d00001 diff --git a/content/projects/badass_bottle_bats.md b/content/projects/badass_bottle_bats.md deleted file mode 100644 index e47a20e..0000000 --- a/content/projects/badass_bottle_bats.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: Badass Bottle Bats -github: https://github.com/ZeusWPI/aichallenge -site: https://zeus.ugent.be/bottlebats/ -logo_letter: B -logo_color: "#FFD062" ---- -A bot writing contest. [https://zeus.ugent.be/bottlebats](https://zeus.ugent.be/bottlebats) diff --git a/content/projects/mozaic.md b/content/projects/mozaic.md new file mode 100644 index 0000000..ffd20bf --- /dev/null +++ b/content/projects/mozaic.md @@ -0,0 +1,8 @@ +--- +title: Mozaic +github: https://github.com/ZeusWPI/mozaic +site: https://zeus.ugent.be/bottlebats/ +logo_letter: M +logo_color: "#FFD062" +--- +MOZAIC is the Massive Online Zeus Artificial Intelligence Competition platform. It aims to provide a flexible platform to host your very own AI competition. diff --git a/content/projects/site.md b/content/projects/site.md new file mode 100644 index 0000000..a213ba4 --- /dev/null +++ b/content/projects/site.md @@ -0,0 +1,8 @@ +--- +title: zeus.ugent.be +github: https://github.com/ZeusWPI/zeus.ugent.be +site: https://zeus.ugent.be +logo_letter: Z +logo_color: "#FF7F00" +--- +Even this site is a Zeus project! From 6cbd22edc85cec16c263bc04efc97e1ff921baa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elo=C3=AFse=20Piret?= Date: Sat, 3 Mar 2018 11:02:42 +0100 Subject: [PATCH 07/25] add lasershoot --- content/events/17-18/lasershoot.md | 49 ++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 content/events/17-18/lasershoot.md diff --git a/content/events/17-18/lasershoot.md b/content/events/17-18/lasershoot.md new file mode 100644 index 0000000..dea7288 --- /dev/null +++ b/content/events/17-18/lasershoot.md @@ -0,0 +1,49 @@ +--- +title: Lasershoot +description: Programmeer +created_at: 03-03-2018 +time: '21-03-2018 18:00' +end: '21-03-2018 23:00' +location: 'Kantoor Delaware: Blue Tower 1 (4th floor)' +locationlink: 'Sluisweg 1, 9000 Ghent Belgium' +color: "#ef463c" +header_text_background: true +--- + +**Oproep aan alle Zeus'ers: Onze hulp is nodig!** +Wij kregen laatst volgende oproep binnen van delaware: + + +*** +Dag Zeus, + +Delaware organiseert voor het eerste zijn eigen lasershoot! Op basis van enkele sessies met onze collega’s hebben we reeds een prototype gebouwd maar zijn op zoek naar versterking om tot een finaal product te komen. Daarom nodigen we Zeus WPI uit voor een avondje programmeren (en pizza) gevolgd door het spelen van de zelf gebouwde lasershoot. + +De basics tot nu toe zijn 2 raspberry pi’s met infrarood sensoren die als ‘base’ fungeren & een webapp die verbonden is met een database om zo weer te geven welke base beschoten is. Hieronder de volgende pistes die wij zien als ‘improvements’ waar jullie doorheen de avond aan kunnen werken: + +Basics: + +* Het creëren & testen van fysieke afbakeningen voor de sensoren +* Scorebord maken voor het spel +* Pi’s connecteren met een scherm waarom data zal bijgehouden worden +* Dit scherm zo visueel aantrekkelijk mogelijk maken +* Programmeren van een ‘shield’ voor de bases zodat hij onraakbaar is +* Connecteren van de Pi’s aan de hand van een database +* Misschien een derde raspBerry gebruiken als centrale database +* Connecteren van laptop met de pi’s om te gebruiken als controller van de games + +Advanced: + +Game mode uitbouwen +Centrale pi die passwoorden genereert die de andere ‘unlockt’ om zo punten te scoren +Andere game modes +Get creative 😊 + +Wij verwachten jullie op 21/3 om 18! Een laptop meebrengen lijkt ons logisch maar als jullie andere materialen (pi’s, arduinos, sensoren, …) willen meenemen; feel free! + +*** + +Dus aan allen die zich geroepen voelen om ons te vergezellen richting Delaware om hun te helpen deze lasershoot op punt te zetten, +schrijf jullie hier in: +Haast je! Want de plaatsen zijn beperkt. + From ec79eeddfb189ee76b3cc83f05b0ef6dcf05c689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elo=C3=AFse=20Piret?= Date: Sat, 3 Mar 2018 11:19:33 +0100 Subject: [PATCH 08/25] gandalf link --- content/events/17-18/lasershoot.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/content/events/17-18/lasershoot.md b/content/events/17-18/lasershoot.md index dea7288..55c2823 100644 --- a/content/events/17-18/lasershoot.md +++ b/content/events/17-18/lasershoot.md @@ -1,13 +1,13 @@ --- title: Lasershoot -description: Programmeer +description: Programmeer en speel je eigen lasershoot! created_at: 03-03-2018 time: '21-03-2018 18:00' end: '21-03-2018 23:00' location: 'Kantoor Delaware: Blue Tower 1 (4th floor)' locationlink: 'Sluisweg 1, 9000 Ghent Belgium' -color: "#ef463c" -header_text_background: true +color: "#f44336" +header_text_background: false --- **Oproep aan alle Zeus'ers: Onze hulp is nodig!** @@ -44,6 +44,6 @@ Wij verwachten jullie op 21/3 om 18! Een laptop meebrengen lijkt ons logisch maa *** Dus aan allen die zich geroepen voelen om ons te vergezellen richting Delaware om hun te helpen deze lasershoot op punt te zetten, -schrijf jullie hier in: +schrijf jullie hier in: https://event.fkgent.be/events/187 Haast je! Want de plaatsen zijn beperkt. From 6260b68453518f31b470710ccf9097dae9c68501 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elo=C3=AFse=20Piret?= Date: Sat, 3 Mar 2018 11:24:26 +0100 Subject: [PATCH 09/25] link --- content/events/17-18/lasershoot.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/events/17-18/lasershoot.md b/content/events/17-18/lasershoot.md index 55c2823..73e494d 100644 --- a/content/events/17-18/lasershoot.md +++ b/content/events/17-18/lasershoot.md @@ -44,6 +44,6 @@ Wij verwachten jullie op 21/3 om 18! Een laptop meebrengen lijkt ons logisch maa *** Dus aan allen die zich geroepen voelen om ons te vergezellen richting Delaware om hun te helpen deze lasershoot op punt te zetten, -schrijf jullie hier in: https://event.fkgent.be/events/187 +schrijf jullie hier in: [https://event.fkgent.be/events/187](https://event.fkgent.be/events/187) Haast je! Want de plaatsen zijn beperkt. From dec41eb12bd0db7d83a470d12edc63c8124a90da Mon Sep 17 00:00:00 2001 From: Rien Maertens Date: Sat, 3 Mar 2018 14:48:36 +0100 Subject: [PATCH 10/25] Use quite, fix some spelling stuff, slightly different wording --- content/events/17-18/lasershoot.md | 58 ++++++++++++++---------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/content/events/17-18/lasershoot.md b/content/events/17-18/lasershoot.md index 73e494d..c79c05f 100644 --- a/content/events/17-18/lasershoot.md +++ b/content/events/17-18/lasershoot.md @@ -10,40 +10,36 @@ color: "#f44336" header_text_background: false --- -**Oproep aan alle Zeus'ers: Onze hulp is nodig!** -Wij kregen laatst volgende oproep binnen van delaware: +**Oproep aan iedereen: jullie hulp is nodig!** +Wij kregen volgende oproep binnen van Delaware: -*** -Dag Zeus, +> Dag Zeus, +> +> Delaware organiseert voor het eerste zijn eigen lasershoot! Op basis van enkele sessies met onze collega’s hebben we reeds een prototype gebouwd maar zijn op zoek naar versterking om tot een finaal product te komen. Daarom nodigen we Zeus WPI uit voor een avondje programmeren (en pizza) gevolgd door het spelen van de zelf gebouwde lasershoot. +> +> De basics tot nu toe zijn 2 Raspberry Pi’s met infrarood sensoren die als ‘base’ fungeren & een webapp die verbonden is met een database om zo weer te geven welke base beschoten is. Hieronder de volgende pistes die wij zien als ‘improvements’ waar jullie doorheen de avond aan kunnen werken: +> +> **Basics:** +> +> * Het creëren & testen van fysieke afbakeningen voor de sensoren +> * Scorebord maken voor het spel +> * Pi’s connecteren met een scherm waarop data zal bijgehouden worden +> * Dit scherm zo visueel aantrekkelijk mogelijk maken +> * Programmeren van een ‘shield’ voor de bases zodat hij onraakbaar is +> * Connecteren van de Pi’s aan de hand van een database +> * Misschien een derde Raspberry Pi gebruiken als centrale database +> * Connecteren van laptop met de Pi’s om te gebruiken als controller van de games +> +> **Advanced:** +> +> - Game mode uitbouwen met een centrale pi die paswoorden genereert die de andere ‘unlockt’ om zo punten te scoren +> - Andere game modes +> - Get creative 😊 +> +> Wij verwachten jullie op 21/3 om 18u! Een laptop meebrengen lijkt ons logisch maar als jullie andere materialen (Pi’s, Arduino's, sensoren, …) willen meenemen; feel free! -Delaware organiseert voor het eerste zijn eigen lasershoot! Op basis van enkele sessies met onze collega’s hebben we reeds een prototype gebouwd maar zijn op zoek naar versterking om tot een finaal product te komen. Daarom nodigen we Zeus WPI uit voor een avondje programmeren (en pizza) gevolgd door het spelen van de zelf gebouwde lasershoot. +Dus aan allen die zich geroepen voelen om ons te vergezellen richting Delaware om hun te helpen deze lasershoot op punt te zetten, schrijf jullie hier in: [https://event.fkgent.be/events/187](https://event.fkgent.be/events/187). -De basics tot nu toe zijn 2 raspberry pi’s met infrarood sensoren die als ‘base’ fungeren & een webapp die verbonden is met een database om zo weer te geven welke base beschoten is. Hieronder de volgende pistes die wij zien als ‘improvements’ waar jullie doorheen de avond aan kunnen werken: - -Basics: - -* Het creëren & testen van fysieke afbakeningen voor de sensoren -* Scorebord maken voor het spel -* Pi’s connecteren met een scherm waarom data zal bijgehouden worden -* Dit scherm zo visueel aantrekkelijk mogelijk maken -* Programmeren van een ‘shield’ voor de bases zodat hij onraakbaar is -* Connecteren van de Pi’s aan de hand van een database -* Misschien een derde raspBerry gebruiken als centrale database -* Connecteren van laptop met de pi’s om te gebruiken als controller van de games - -Advanced: - -Game mode uitbouwen -Centrale pi die passwoorden genereert die de andere ‘unlockt’ om zo punten te scoren -Andere game modes -Get creative 😊 - -Wij verwachten jullie op 21/3 om 18! Een laptop meebrengen lijkt ons logisch maar als jullie andere materialen (pi’s, arduinos, sensoren, …) willen meenemen; feel free! - -*** - -Dus aan allen die zich geroepen voelen om ons te vergezellen richting Delaware om hun te helpen deze lasershoot op punt te zetten, -schrijf jullie hier in: [https://event.fkgent.be/events/187](https://event.fkgent.be/events/187) Haast je! Want de plaatsen zijn beperkt. From 1c5030519a697a604430e00b91f443f150ce1801 Mon Sep 17 00:00:00 2001 From: Lorin Werthen Date: Sat, 3 Mar 2018 14:55:37 +0100 Subject: [PATCH 11/25] don't use texlive full, shouldn't be necessary --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8860300..46faaa3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ addons: apt: packages: - pandoc - - texlive-full + - texlive branches: only: From 6a227639bf813cba65f999aa9def9859817c4377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elo=C3=AFse=20Piret?= Date: Sat, 3 Mar 2018 14:58:29 +0100 Subject: [PATCH 12/25] advanced list --- content/events/17-18/lasershoot.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/events/17-18/lasershoot.md b/content/events/17-18/lasershoot.md index c79c05f..da1567f 100644 --- a/content/events/17-18/lasershoot.md +++ b/content/events/17-18/lasershoot.md @@ -33,9 +33,9 @@ Wij kregen volgende oproep binnen van Delaware: > > **Advanced:** > -> - Game mode uitbouwen met een centrale pi die paswoorden genereert die de andere ‘unlockt’ om zo punten te scoren -> - Andere game modes -> - Get creative 😊 +> * Game mode uitbouwen met een centrale pi die paswoorden genereert die de andere ‘unlockt’ om zo punten te scoren +> * Andere game modes +> * Get creative 😊 > > Wij verwachten jullie op 21/3 om 18u! Een laptop meebrengen lijkt ons logisch maar als jullie andere materialen (Pi’s, Arduino's, sensoren, …) willen meenemen; feel free! From 14a81b0d3db1971b7d91d52974229afb1cfd66bd Mon Sep 17 00:00:00 2001 From: Lorin Werthen Date: Sat, 3 Mar 2018 15:02:40 +0100 Subject: [PATCH 13/25] going down the rabbit hole --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 46faaa3..8c03ef9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,7 @@ addons: packages: - pandoc - texlive + - lmodern branches: only: From 4fb8ca95022deba302893d125c91f8da38eb5199 Mon Sep 17 00:00:00 2001 From: Lorin Werthen Date: Sat, 3 Mar 2018 16:27:51 +0100 Subject: [PATCH 14/25] hyphenate all the things --- content/assets/stylesheets/main.scss | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/content/assets/stylesheets/main.scss b/content/assets/stylesheets/main.scss index 65d6947..6e97591 100644 --- a/content/assets/stylesheets/main.scss +++ b/content/assets/stylesheets/main.scss @@ -9,14 +9,22 @@ flex: none; } +body { + +} + // Sticky footer -body.site { - overflow-x: hidden; +body { + hyphens: auto; - display: flex; - min-height: 100vh; - flex-direction: column; + &.site { + overflow-x: hidden; + + display: flex; + min-height: 100vh; + flex-direction: column; + } .wrapper { flex: 1; From 9d90d27a9890e63507e156cc698893fdee93cbe7 Mon Sep 17 00:00:00 2001 From: David Vandorpe Date: Thu, 8 Mar 2018 20:28:27 +0100 Subject: [PATCH 15/25] CSC Radium writeup --- content/blog/17-18/cscbe.md | 97 +++++++++++++++++++++++++++++++++ content/blog/17-18/radium.zip | Bin 0 -> 11276 bytes content/blog/17-18/solution.py | 37 +++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 content/blog/17-18/cscbe.md create mode 100644 content/blog/17-18/radium.zip create mode 100644 content/blog/17-18/solution.py diff --git a/content/blog/17-18/cscbe.md b/content/blog/17-18/cscbe.md new file mode 100644 index 0000000..b75024d --- /dev/null +++ b/content/blog/17-18/cscbe.md @@ -0,0 +1,97 @@ +--- +author: David Vandorpe +title: Cyber Security Challenge 2018: Radium +created_at: 08/03/2018 +--- + +# Cyber Security Challenge 2018: Radium + +**Category:** Network Security +**Points:** 150 + +**Description:** + +Someone implemented a protocol to execute (privileged) commands on a server. After months of analysis, our word-class TAO team didn't find a single buffer overflow.. However, they were able to compromise a router between a communicating client and server. + +To perform a man-in-the-middle attack through this router, forward data between 52.210.242.66:8023 (this represents the server) and 52.210.242.66:8024 (this represents the client). + +See client.c for an example command to do this. Abuse the resulting man-in-the-middle position to somehow obtain the ability to execute privileged commands! + +*Hint*: When is the authenticity of a packet verified? When is the data payload of a packet decrypted? + +[Source code](./radium.zip) + +## Introduction + +This challenge proved to be possibly the hardest challenge, going unsolved until the organisers decided to reveal a hint near the end of the competition. Even then, our team was the only one to solve it. + +## Write-up + +The zip file contains the code run on the server and the client. The client and server share a secret password and a secret key. The flow to request is key is as follow: + +* Client sends the randomly generated client nonce to the server +* Server replies with a randomly generated server nonce. + - The session key (all following communications will use this key) is now HMAC_SHA256(secret_key, "CSCBE18 Session Key Generation" || client_nonce || server_nonce) +* The client sends a flag request to the server, which requires a password. Unfortunately this password is encrypted. +* The server responds with the (encrypted) flag + +The same routine was also available without encryption if the client didn't pass a NONCE in it's handshake. + +So, how do we get our flag? Let's list some ideas: + +* Find an attack on the encryption algorithm (AES in OFB mode) +* Try to trick client and server to use the flow without encryption +* Try to set the key to a known value +* Try to trick the server into dumping the flag without a password +* Try to trick the server into using a known encryption key +* Try to generate an error message on the server that includes (a part of) the flag or encryption key +* Try to generate an error message on the client that includes (a part of) the flag or encryption key + +Let's see what these ideas lead to. + +We found a [writeup](https://github.com/Alpackers/CTF-Writeups/tree/master/2016/BostonKeyParty/Crypto/des-ofb) from another CTF that cracks DES encryption in OFB mode. The key weakness here is using a weak DES key (making encryption symmetric), in combination with OFB. But wait a second, isn't AES a symmetric algorithm? So basically we would expect the second block of ciphertext to just be the plaintext XOR'd with the IV. However, for reasons unknown to me this turned out not to be the case. + +Setting the encryption key to NULL on the server seemed easy enough, but sadly this would also mean that the server couldn't decrypt the messages from the client (as this key was used for both encryption and decryption by both sides). + +To understand the next step, let's see how the plaintext is formatted. It consists of some header bytes (including IV and HMAC sign) followed by data. The data is the only part that gets encrypted if encryption is used. This data is essentially an array of different data blocks. The first two bytes of each block are the "TlvType" (an enum in `packets.h`) and the length of the data block (excluding these two bytes). The rest of the bytes are then followed by the actual data. It is also essential to understand that AES+OFB generates a bytestream which only depends on the IV and the encryption key. This stream does then get XOR'd with the plaintext. Changing a byte in the plain/ciphertext only changes the corresponding byte in the cipher/plaintext. If we know a byte P from the plaintext, it is easy to substitute it with another byte P': simply change C to C'=C XOR P XOR P'. + +Let's dive back into the code. When trying to dump the flag through an error message (which never gets encrypted) on the client side, we stumbled across some interesting code. + +``` + size_t pos = 0; + while (pos < len && len - pos >= 2) + { + // Assure there is enough length for the element + if (data[pos + 1] > len - pos - 2) { + send_error(session, "%s: not enough data left for element type %d (need %d bytes but only %d left)\n", + __FUNCTION__, data[pos], data[pos + 1], len - pos - 2); + return -1; + } +``` +This is were our attack will happen. We let the flow described earlier proceed as normal, except we intercept the final message returning the flag to the client. Assume we want to decrypt the fifth byte of the flag. If we manage to set the length of the first datablock to 3, the fifth byte of the flag will be interpreted as the length of the second data block. If this length is greater than the amount of remaining bytes, then our byte will get sent back to the server unencrypted! To do this, we need to know the original length of the flag, which is hardcoded and 39. So we replace the second byte with `C' = C XOR 0x27 XOR 0x3` and this should print the correct byte and the preceding byte. + +However, we're not there yet. All ciphertexts get signed with HMAC_SHA256. At this point, we got stuck for a bit. Around 2.5 hours before the competition ended a hint was posted (see challenge description) which allowed us to finish this challenge in time. + + +``` +static int radium_check_authenticity(struct radium_session *session, struct pkt_header *hdr) +{ + // Nothing to do if no encryption is used, or if it's not an authenticated message + if (!session->using_encryption || hdr->msgtype < Packet_Command) + return 0; + // We need a session key to verify all the other packets + else if (!session->using_encryption || !session->handshake_done) { + fprintf(stderr, "%s: no session key available to check authenticity\n", __FUNCTION__); + return -1; + } + +static int radium_decrypt_data(struct radium_session *session, struct pkt_header *hdr) +{ + // Nothing to do if not encrypted + if (!hdr->encrypted) + return 0; +``` + +Basically, the solution was to set the msgtype byte to 0x1 (ServerHello). This wasn't according to our protocol flow, but that didn't matter as we intended to already produce an error during the parsing of the message. Throwing this together revealed that the fifth byte was 'E', which matched our expectation of flag format "CSCBE{.................................}". Jackpot! Now we just had to repeat for all other bytes. A simple [python script](./solution.py) solved this. + +Flag: CSCBE{1FFCD19C964D3E5DF5B4CFF490583AC1} diff --git a/content/blog/17-18/radium.zip b/content/blog/17-18/radium.zip new file mode 100644 index 0000000000000000000000000000000000000000..f8f49da66400d83a8d91c85a2c91d6753d38c564 GIT binary patch literal 11276 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 EKcRZO!T Date: Thu, 8 Mar 2018 20:33:11 +0100 Subject: [PATCH 16/25] Reread first sentence --- content/blog/17-18/cscbe.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/blog/17-18/cscbe.md b/content/blog/17-18/cscbe.md index b75024d..4258ab9 100644 --- a/content/blog/17-18/cscbe.md +++ b/content/blog/17-18/cscbe.md @@ -27,7 +27,7 @@ This challenge proved to be possibly the hardest challenge, going unsolved until ## Write-up -The zip file contains the code run on the server and the client. The client and server share a secret password and a secret key. The flow to request is key is as follow: +The zip file contains the code ran on the server and the client. The client and server share a secret password and a secret key. The flow to request the flag is key is as follow: * Client sends the randomly generated client nonce to the server * Server replies with a randomly generated server nonce. @@ -70,7 +70,7 @@ Let's dive back into the code. When trying to dump the flag through an error mes ``` This is were our attack will happen. We let the flow described earlier proceed as normal, except we intercept the final message returning the flag to the client. Assume we want to decrypt the fifth byte of the flag. If we manage to set the length of the first datablock to 3, the fifth byte of the flag will be interpreted as the length of the second data block. If this length is greater than the amount of remaining bytes, then our byte will get sent back to the server unencrypted! To do this, we need to know the original length of the flag, which is hardcoded and 39. So we replace the second byte with `C' = C XOR 0x27 XOR 0x3` and this should print the correct byte and the preceding byte. -However, we're not there yet. All ciphertexts get signed with HMAC_SHA256. At this point, we got stuck for a bit. Around 2.5 hours before the competition ended a hint was posted (see challenge description) which allowed us to finish this challenge in time. +However, we're not there yet. All ciphertexts get signed with HMAC_SHA256. At this point, we got stuck for a bit. Around 2.5 hours before the competition ended a hint was posted (see challenge description) which led to the solution. ``` From 51fdf5f002d71a51789c5f5ec4635813ba37e1df Mon Sep 17 00:00:00 2001 From: David Vandorpe Date: Thu, 8 Mar 2018 20:37:58 +0100 Subject: [PATCH 17/25] Fixed issues --- content/blog/17-18/cscbe.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/blog/17-18/cscbe.md b/content/blog/17-18/cscbe.md index 4258ab9..6024981 100644 --- a/content/blog/17-18/cscbe.md +++ b/content/blog/17-18/cscbe.md @@ -1,6 +1,6 @@ --- author: David Vandorpe -title: Cyber Security Challenge 2018: Radium +title: 'Cyber Security Challenge 2018: Radium' created_at: 08/03/2018 --- @@ -27,7 +27,7 @@ This challenge proved to be possibly the hardest challenge, going unsolved until ## Write-up -The zip file contains the code ran on the server and the client. The client and server share a secret password and a secret key. The flow to request the flag is key is as follow: +The zip file contains the code ran on the server and the client. The client and server share a secret password and a secret key. The flow to request the flag is as follow: * Client sends the randomly generated client nonce to the server * Server replies with a randomly generated server nonce. From 09e8f3d656439b0b275af2589d4a3cf22bbf463c Mon Sep 17 00:00:00 2001 From: David Vandorpe Date: Thu, 8 Mar 2018 20:52:21 +0100 Subject: [PATCH 18/25] Fixed weird sentence --- content/blog/17-18/cscbe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/blog/17-18/cscbe.md b/content/blog/17-18/cscbe.md index 6024981..993e292 100644 --- a/content/blog/17-18/cscbe.md +++ b/content/blog/17-18/cscbe.md @@ -53,7 +53,7 @@ We found a [writeup](https://github.com/Alpackers/CTF-Writeups/tree/master/2016/ Setting the encryption key to NULL on the server seemed easy enough, but sadly this would also mean that the server couldn't decrypt the messages from the client (as this key was used for both encryption and decryption by both sides). -To understand the next step, let's see how the plaintext is formatted. It consists of some header bytes (including IV and HMAC sign) followed by data. The data is the only part that gets encrypted if encryption is used. This data is essentially an array of different data blocks. The first two bytes of each block are the "TlvType" (an enum in `packets.h`) and the length of the data block (excluding these two bytes). The rest of the bytes are then followed by the actual data. It is also essential to understand that AES+OFB generates a bytestream which only depends on the IV and the encryption key. This stream does then get XOR'd with the plaintext. Changing a byte in the plain/ciphertext only changes the corresponding byte in the cipher/plaintext. If we know a byte P from the plaintext, it is easy to substitute it with another byte P': simply change C to C'=C XOR P XOR P'. +To understand the next step, let's see how the plaintext is formatted. It consists of some header bytes (including IV and HMAC sign) followed by data. The data is the only part that gets encrypted if encryption is used. This data is essentially an array of different data blocks. The first two bytes of each block are the "TlvType" (an enum in `packets.h`) and the length of the data block (excluding these two bytes). The rest of block is the actual data. It is also essential to understand that AES+OFB generates a bytestream which only depends on the IV and the encryption key. This stream does then get XOR'd with the plaintext. Changing a byte in the plain/ciphertext only changes the corresponding byte in the cipher/plaintext. If we know a byte P from the plaintext, it is easy to substitute it with another byte P': simply change C to C'=C XOR P XOR P'. Let's dive back into the code. When trying to dump the flag through an error message (which never gets encrypted) on the client side, we stumbled across some interesting code. From 1a7de28ca9b67a49bc0643ae1b7fe984d5e668cd Mon Sep 17 00:00:00 2001 From: Lorin Werthen Date: Thu, 8 Mar 2018 22:19:52 +0100 Subject: [PATCH 19/25] Fixes --- .../assets/stylesheets/includes/general.scss | 5 +++ content/blog/17-18/cscbe.md | 39 +++++++++--------- content/blog/17-18/radium.zip | Bin 11276 -> 0 bytes content/blog/17-18/solution.py | 37 ----------------- 4 files changed, 24 insertions(+), 57 deletions(-) delete mode 100644 content/blog/17-18/radium.zip delete mode 100644 content/blog/17-18/solution.py diff --git a/content/assets/stylesheets/includes/general.scss b/content/assets/stylesheets/includes/general.scss index ef0d02e..b3c8a4d 100644 --- a/content/assets/stylesheets/includes/general.scss +++ b/content/assets/stylesheets/includes/general.scss @@ -3,6 +3,11 @@ text-align: justify; } +pre .line-numbers { + margin-right: 10px; + margin-left: -10px; +} + // Override box styling without round corners .box { margin-bottom:10px; diff --git a/content/blog/17-18/cscbe.md b/content/blog/17-18/cscbe.md index 993e292..14f1ebe 100644 --- a/content/blog/17-18/cscbe.md +++ b/content/blog/17-18/cscbe.md @@ -2,12 +2,11 @@ author: David Vandorpe title: 'Cyber Security Challenge 2018: Radium' created_at: 08/03/2018 +toc: true --- -# Cyber Security Challenge 2018: Radium - -**Category:** Network Security -**Points:** 150 +**Category:** Network Security +**Points:** 150 **Description:** @@ -19,7 +18,7 @@ See client.c for an example command to do this. Abuse the resulting man-in-the-m *Hint*: When is the authenticity of a packet verified? When is the data payload of a packet decrypted? -[Source code](./radium.zip) +[Source code](https://zeus.ugent.be/zeuswpi/jaWQQLqU.zip) ## Introduction @@ -57,23 +56,23 @@ To understand the next step, let's see how the plaintext is formatted. It consis Let's dive back into the code. When trying to dump the flag through an error message (which never gets encrypted) on the client side, we stumbled across some interesting code. -``` - size_t pos = 0; - while (pos < len && len - pos >= 2) - { - // Assure there is enough length for the element - if (data[pos + 1] > len - pos - 2) { - send_error(session, "%s: not enough data left for element type %d (need %d bytes but only %d left)\n", - __FUNCTION__, data[pos], data[pos + 1], len - pos - 2); - return -1; - } -``` +~~~ c +size_t pos = 0; +while (pos < len && len - pos >= 2) +{ + // Assure there is enough length for the element + if (data[pos + 1] > len - pos - 2) { + send_error(session, "%s: not enough data left for element type %d (need %d bytes but only %d left)\n", + __FUNCTION__, data[pos], data[pos + 1], len - pos - 2); + return -1; + } +~~~ + This is were our attack will happen. We let the flow described earlier proceed as normal, except we intercept the final message returning the flag to the client. Assume we want to decrypt the fifth byte of the flag. If we manage to set the length of the first datablock to 3, the fifth byte of the flag will be interpreted as the length of the second data block. If this length is greater than the amount of remaining bytes, then our byte will get sent back to the server unencrypted! To do this, we need to know the original length of the flag, which is hardcoded and 39. So we replace the second byte with `C' = C XOR 0x27 XOR 0x3` and this should print the correct byte and the preceding byte. However, we're not there yet. All ciphertexts get signed with HMAC_SHA256. At this point, we got stuck for a bit. Around 2.5 hours before the competition ended a hint was posted (see challenge description) which led to the solution. - -``` +~~~ c static int radium_check_authenticity(struct radium_session *session, struct pkt_header *hdr) { // Nothing to do if no encryption is used, or if it's not an authenticated message @@ -90,8 +89,8 @@ static int radium_decrypt_data(struct radium_session *session, struct pkt_header // Nothing to do if not encrypted if (!hdr->encrypted) return 0; -``` +~~~ -Basically, the solution was to set the msgtype byte to 0x1 (ServerHello). This wasn't according to our protocol flow, but that didn't matter as we intended to already produce an error during the parsing of the message. Throwing this together revealed that the fifth byte was 'E', which matched our expectation of flag format "CSCBE{.................................}". Jackpot! Now we just had to repeat for all other bytes. A simple [python script](./solution.py) solved this. +Basically, the solution was to set the msgtype byte to 0x1 (ServerHello). This wasn't according to our protocol flow, but that didn't matter as we intended to already produce an error during the parsing of the message. Throwing this together revealed that the fifth byte was 'E', which matched our expectation of flag format "CSCBE{.................................}". Jackpot! Now we just had to repeat for all other bytes. A simple [python script](https://zeus.ugent.be/zeuswpi/GotPD6yg.py) solved this. Flag: CSCBE{1FFCD19C964D3E5DF5B4CFF490583AC1} diff --git a/content/blog/17-18/radium.zip b/content/blog/17-18/radium.zip deleted file mode 100644 index f8f49da66400d83a8d91c85a2c91d6753d38c564..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11276 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 EKcRZO!T Date: Thu, 8 Mar 2018 22:44:19 +0100 Subject: [PATCH 20/25] Improve typography --- Gemfile | 1 + Gemfile.lock | 4 ++++ Rules | 2 ++ content/assets/stylesheets/includes/general.scss | 6 ++++++ content/blog/17-18/cscbe.md | 2 +- 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index df22901..ca9cbca 100644 --- a/Gemfile +++ b/Gemfile @@ -8,6 +8,7 @@ gem 'coffee-script' gem 'icalendar' # ical files gem 'kramdown' gem 'sass' +gem 'typogruby' # Needed for atom_feed in blogging helper gem 'builder' diff --git a/Gemfile.lock b/Gemfile.lock index 157a130..b5e2cf1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -94,6 +94,7 @@ GEM ffi (>= 0.5.0, < 2) ref (2.0.0) ruby_dep (1.5.0) + rubypants (0.7.0) sass (3.5.5) sass-listen (~> 4.0.0) sass-listen (4.0.0) @@ -107,6 +108,8 @@ GEM libv8 (~> 3.16.14.15) ref thor (0.20.0) + typogruby (1.0.18) + rubypants uglifier (2.7.2) execjs (>= 0.3.0) json (>= 1.8.0) @@ -134,6 +137,7 @@ DEPENDENCIES terminal-notifier terminal-notifier-guard therubyracer + typogruby w3c_validators words_counted diff --git a/Rules b/Rules index 9b74250..e39b722 100644 --- a/Rules +++ b/Rules @@ -84,6 +84,8 @@ compile '/blog/*/*' do layout '/generic.*' layout '/default.*' filter :erb + + filter :typogruby end compile '/blog/*/*', rep: :text do diff --git a/content/assets/stylesheets/includes/general.scss b/content/assets/stylesheets/includes/general.scss index b3c8a4d..13aed47 100644 --- a/content/assets/stylesheets/includes/general.scss +++ b/content/assets/stylesheets/includes/general.scss @@ -8,6 +8,12 @@ pre .line-numbers { margin-left: -10px; } +.caps { + text-transform: uppercase; + font-size: 85%; + letter-spacing: 1px; +} + // Override box styling without round corners .box { margin-bottom:10px; diff --git a/content/blog/17-18/cscbe.md b/content/blog/17-18/cscbe.md index 14f1ebe..04a0fa4 100644 --- a/content/blog/17-18/cscbe.md +++ b/content/blog/17-18/cscbe.md @@ -30,7 +30,7 @@ The zip file contains the code ran on the server and the client. The client and * Client sends the randomly generated client nonce to the server * Server replies with a randomly generated server nonce. - - The session key (all following communications will use this key) is now HMAC_SHA256(secret_key, "CSCBE18 Session Key Generation" || client_nonce || server_nonce) + - The session key (all following communications will use this key) is now `HMAC_SHA256(secret_key, "CSCBE18 Session Key Generation" || client_nonce || server_nonce)` * The client sends a flag request to the server, which requires a password. Unfortunately this password is encrypted. * The server responds with the (encrypted) flag From e6bf46d17cd07893eb0ec647d20e8d279b5cc41c Mon Sep 17 00:00:00 2001 From: David Vandorpe Date: Fri, 9 Mar 2018 09:37:09 +0100 Subject: [PATCH 21/25] Link to other writeup This one is a lot clearer --- content/blog/17-18/cscbe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/blog/17-18/cscbe.md b/content/blog/17-18/cscbe.md index 04a0fa4..e4ea346 100644 --- a/content/blog/17-18/cscbe.md +++ b/content/blog/17-18/cscbe.md @@ -48,7 +48,7 @@ So, how do we get our flag? Let's list some ideas: Let's see what these ideas lead to. -We found a [writeup](https://github.com/Alpackers/CTF-Writeups/tree/master/2016/BostonKeyParty/Crypto/des-ofb) from another CTF that cracks DES encryption in OFB mode. The key weakness here is using a weak DES key (making encryption symmetric), in combination with OFB. But wait a second, isn't AES a symmetric algorithm? So basically we would expect the second block of ciphertext to just be the plaintext XOR'd with the IV. However, for reasons unknown to me this turned out not to be the case. +We found a [writeup](https://shrikantadhikarla.wordpress.com/2016/03/08/des-ofb-writeup-boston-key-party-ctf/) from another CTF that cracks DES encryption in OFB mode. The key weakness here is using a weak DES key (making encryption symmetric), in combination with OFB. But wait a second, isn't AES a symmetric algorithm? So basically we would expect the second block of ciphertext to just be the plaintext XOR'd with the IV. However, for reasons unknown to me this turned out not to be the case. Setting the encryption key to NULL on the server seemed easy enough, but sadly this would also mean that the server couldn't decrypt the messages from the client (as this key was used for both encryption and decryption by both sides). From 0f62e9b62966f27d462aefd28e37ccb635a789f8 Mon Sep 17 00:00:00 2001 From: David Vandorpe Date: Fri, 9 Mar 2018 09:51:41 +0100 Subject: [PATCH 22/25] Added Toon's explanation about AES --- content/blog/17-18/cscbe.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/content/blog/17-18/cscbe.md b/content/blog/17-18/cscbe.md index e4ea346..9475894 100644 --- a/content/blog/17-18/cscbe.md +++ b/content/blog/17-18/cscbe.md @@ -48,7 +48,9 @@ So, how do we get our flag? Let's list some ideas: Let's see what these ideas lead to. -We found a [writeup](https://shrikantadhikarla.wordpress.com/2016/03/08/des-ofb-writeup-boston-key-party-ctf/) from another CTF that cracks DES encryption in OFB mode. The key weakness here is using a weak DES key (making encryption symmetric), in combination with OFB. But wait a second, isn't AES a symmetric algorithm? So basically we would expect the second block of ciphertext to just be the plaintext XOR'd with the IV. However, for reasons unknown to me this turned out not to be the case. +We found a [writeup](https://shrikantadhikarla.wordpress.com/2016/03/08/des-ofb-writeup-boston-key-party-ctf/) from another CTF that cracks DES encryption in OFB mode. The key weakness here is using a weak DES key (making encryption symmetric), in combination with OFB. But wait a second, isn't AES a symmetric algorithm? So basically we would expect the second block of ciphertext to just be the plaintext XOR'd with the IV. However, for reasons unknown to me this turned out not to be the case. **Update:** Thanks to Toon Willems for pointing out that AES modifies the key after every round. For those interested, see [act 3](http://www.moserware.com/2009/09/stick-figure-guide-to-advanced.html). + +![AES Key Expansion](http://www.moserware.com/assets/stick-figure-guide-to-advanced/aes_act_3_scene_06_key_expansion_part_1_1100.png) Setting the encryption key to NULL on the server seemed easy enough, but sadly this would also mean that the server couldn't decrypt the messages from the client (as this key was used for both encryption and decryption by both sides). From 91636b541691b85e8b24f41497db170800a2e1c7 Mon Sep 17 00:00:00 2001 From: lorin Date: Fri, 9 Mar 2018 10:37:45 +0100 Subject: [PATCH 23/25] http -> https --- content/blog/17-18/cscbe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/blog/17-18/cscbe.md b/content/blog/17-18/cscbe.md index 9475894..29087bf 100644 --- a/content/blog/17-18/cscbe.md +++ b/content/blog/17-18/cscbe.md @@ -48,7 +48,7 @@ So, how do we get our flag? Let's list some ideas: Let's see what these ideas lead to. -We found a [writeup](https://shrikantadhikarla.wordpress.com/2016/03/08/des-ofb-writeup-boston-key-party-ctf/) from another CTF that cracks DES encryption in OFB mode. The key weakness here is using a weak DES key (making encryption symmetric), in combination with OFB. But wait a second, isn't AES a symmetric algorithm? So basically we would expect the second block of ciphertext to just be the plaintext XOR'd with the IV. However, for reasons unknown to me this turned out not to be the case. **Update:** Thanks to Toon Willems for pointing out that AES modifies the key after every round. For those interested, see [act 3](http://www.moserware.com/2009/09/stick-figure-guide-to-advanced.html). +We found a [writeup](https://shrikantadhikarla.wordpress.com/2016/03/08/des-ofb-writeup-boston-key-party-ctf/) from another CTF that cracks DES encryption in OFB mode. The key weakness here is using a weak DES key (making encryption symmetric), in combination with OFB. But wait a second, isn't AES a symmetric algorithm? So basically we would expect the second block of ciphertext to just be the plaintext XOR'd with the IV. However, for reasons unknown to me this turned out not to be the case. **Update:** Thanks to Toon Willems for pointing out that AES modifies the key after every round. For those interested, see [act 3](https://www.moserware.com/2009/09/stick-figure-guide-to-advanced.html). ![AES Key Expansion](http://www.moserware.com/assets/stick-figure-guide-to-advanced/aes_act_3_scene_06_key_expansion_part_1_1100.png) From 2b605cd6774cd4325681f3f5d585efcd820c37b0 Mon Sep 17 00:00:00 2001 From: lorin Date: Fri, 9 Mar 2018 10:38:24 +0100 Subject: [PATCH 24/25] more http -> https --- content/blog/17-18/cscbe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/blog/17-18/cscbe.md b/content/blog/17-18/cscbe.md index 29087bf..06c096d 100644 --- a/content/blog/17-18/cscbe.md +++ b/content/blog/17-18/cscbe.md @@ -50,7 +50,7 @@ Let's see what these ideas lead to. We found a [writeup](https://shrikantadhikarla.wordpress.com/2016/03/08/des-ofb-writeup-boston-key-party-ctf/) from another CTF that cracks DES encryption in OFB mode. The key weakness here is using a weak DES key (making encryption symmetric), in combination with OFB. But wait a second, isn't AES a symmetric algorithm? So basically we would expect the second block of ciphertext to just be the plaintext XOR'd with the IV. However, for reasons unknown to me this turned out not to be the case. **Update:** Thanks to Toon Willems for pointing out that AES modifies the key after every round. For those interested, see [act 3](https://www.moserware.com/2009/09/stick-figure-guide-to-advanced.html). -![AES Key Expansion](http://www.moserware.com/assets/stick-figure-guide-to-advanced/aes_act_3_scene_06_key_expansion_part_1_1100.png) +![AES Key Expansion](https://www.moserware.com/assets/stick-figure-guide-to-advanced/aes_act_3_scene_06_key_expansion_part_1_1100.png) Setting the encryption key to NULL on the server seemed easy enough, but sadly this would also mean that the server couldn't decrypt the messages from the client (as this key was used for both encryption and decryption by both sides). From 1be9f68c1048b4a670332e5f7b8aedde49be19df Mon Sep 17 00:00:00 2001 From: David Vandorpe Date: Fri, 9 Mar 2018 11:59:02 +0100 Subject: [PATCH 25/25] Listed the actual reason our first attempt failed Brainfart --- content/blog/17-18/cscbe.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/content/blog/17-18/cscbe.md b/content/blog/17-18/cscbe.md index 9475894..f92e83c 100644 --- a/content/blog/17-18/cscbe.md +++ b/content/blog/17-18/cscbe.md @@ -48,9 +48,7 @@ So, how do we get our flag? Let's list some ideas: Let's see what these ideas lead to. -We found a [writeup](https://shrikantadhikarla.wordpress.com/2016/03/08/des-ofb-writeup-boston-key-party-ctf/) from another CTF that cracks DES encryption in OFB mode. The key weakness here is using a weak DES key (making encryption symmetric), in combination with OFB. But wait a second, isn't AES a symmetric algorithm? So basically we would expect the second block of ciphertext to just be the plaintext XOR'd with the IV. However, for reasons unknown to me this turned out not to be the case. **Update:** Thanks to Toon Willems for pointing out that AES modifies the key after every round. For those interested, see [act 3](http://www.moserware.com/2009/09/stick-figure-guide-to-advanced.html). - -![AES Key Expansion](http://www.moserware.com/assets/stick-figure-guide-to-advanced/aes_act_3_scene_06_key_expansion_part_1_1100.png) +We found a [writeup](https://shrikantadhikarla.wordpress.com/2016/03/08/des-ofb-writeup-boston-key-party-ctf/) from another CTF that cracks DES encryption in OFB mode. The key weakness here is using a weak DES key (making encryption symmetric), in combination with OFB. But wait a second, isn't AES a symmetric algorithm? And the program used the same function to encrypt and decrypt! So basically we would expect the second block of ciphertext to just be the plaintext XOR'd with the IV. Some testing proved that our logic was flawed: using the same function worked because of the symmetry of the XOR operation in OFB mode, and not because `IV == AES(AES(IV))` which would break AES OFB. Setting the encryption key to NULL on the server seemed easy enough, but sadly this would also mean that the server couldn't decrypt the messages from the client (as this key was used for both encryption and decryption by both sides).