{"id":587,"date":"2018-07-01T13:25:24","date_gmt":"2018-07-01T13:25:24","guid":{"rendered":"https:\/\/devel0pment.de\/?p=587"},"modified":"2018-07-01T13:25:24","modified_gmt":"2018-07-01T13:25:24","slug":"google-ctf-2018-quals-writeup-js-safe-2-0","status":"publish","type":"post","link":"https:\/\/devel0pment.de\/?p=587","title":{"rendered":"Google CTF 2018 (Quals) &#8211; writeup JS safe 2.0"},"content":{"rendered":"<style>\n  .spanFlag {\n    color:#008200;\n    font-weight:bold;\n  }\n<\/style>\n<p>The <a href=\"https:\/\/g.co\/ctf\" target=\"_blank\" rel=\"noopener\">qualifications for the Google Capture The Flag 2018<\/a> (<a href=\"https:\/\/ctftime.org\/event\/623\" target=\"_blank\" rel=\"noopener\">ctftime.org<\/a>) ran from 23\/06\/2018, 00:00 UTC to 24\/06\/2018 23:59 UTC.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/logo-1024x635.png\" alt=\"\" width=\"800\" class=\"alignnone size-large wp-image-589\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/logo-1024x635.png 1024w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/logo-300x186.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/logo-768x476.png 768w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/logo.png 1132w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p>The CTF was worked out very well. There have been plenty of interesting and creative challenges.<\/p>\n<p>This time I decided to focus on the category <i>web<\/i> and managed to solve the challenge <i>JS safe 2.0<\/i>, which was the easiest one of the web-challenges based on the amount of solves. Nevertheless it really took my some time to dodge all the pitfalls I stumbled upon while solving the challenge.<\/p>\n<p><!--more--><\/p>\n<hr \/>\n<h1>JS safe 2.0 (121 pts &#8211; 103 solves)<\/h1>\n<p>The writeup is divided into the following sections:<\/p>\n<p><a href=\"#h3_1\">1. Challenge description<\/a><br \/>\n<a href=\"#h3_2\">2. Source Code<\/a><br \/>\n<a href=\"#h3_3\">3. Obfuscation \/ Anti-Debugging<\/a><br \/>\n<a href=\"#h3_4\">4. Solution<\/a><\/p>\n<h3 id=\"h3_1\">1. Challenge description<\/h3>\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/descr.png\" alt=\"\" width=\"426\" class=\"alignnone size-full wp-image-661\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/descr.png 626w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/descr-243x300.png 243w\" sizes=\"(max-width: 626px) 100vw, 626px\" \/><\/p>\n<p>The challenge is an offline client-side challenge. The attached zip-file contains a single html-file called <code>js_safe_2.html<\/code>. The html-page displays an input field, in which a password should be entered:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/screen1-1024x753.png\" alt=\"\" width=\"525\" height=\"386\" class=\"alignnone size-large wp-image-590\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/screen1-1024x753.png 1024w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/screen1-300x220.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/screen1-768x564.png 768w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/screen1.png 1275w\" sizes=\"(max-width: 525px) 100vw, 525px\" \/><\/p>\n<p>When entering an incorrect password the message <code style=\"color:#ff0000;\">Access Denied<\/code> is displayed at the bottom of the page:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/screen2.png\" alt=\"\" width=\"525\" height=\"386\" class=\"alignnone size-large wp-image-591\" \/><\/p>\n<h3 id=\"h3_2\">2. Source Code<\/h3>\n<p>Let&#8217;s have a look at the source-code:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;!DOCTYPE html&gt;\r\n&lt;html&gt;\r\n&lt;head&gt;\r\n&lt;meta charset=&quot;utf-8&quot;&gt;\r\n&lt;title&gt;JS safe v2.0 - the leading localStorage based safe solution with military grade JS anti-debug technology&lt;\/title&gt;\r\n&lt;!--\r\nAdvertisement:\r\nLooking for a hand-crafted, browser based virtual safe to store your most\r\ninteresting secrets? Look no further, you have found it. You can order your own\r\nby sending a mail to js_safe@example.com. When ordering, please specify the\r\npassword you'd like to use to open and close the safe. We'll hand craft a\r\nunique safe just for you, that only works with your password of choice.\r\n--&gt;\r\n&lt;style&gt;\r\n... css ..\r\n&lt;\/style&gt;\r\n&lt;script&gt;\r\nfunction x(\u0445){ord=Function.prototype.call.bind(''.charCodeAt);chr=String.fromCharCode;str=String;function h(s){for(i=0;i!=s.length;i++){a=((typeof a=='undefined'?1:a)+ord(str(s&#x5B;i])))%65521;b=((typeof b=='undefined'?0:b)+a)%65521}return chr(b&gt;&gt;8)+chr(b&amp;0xFF)+chr(a&gt;&gt;8)+chr(a&amp;0xFF)}function c(a,b,c){for(i=0;i!=a.length;i++)c=(c||'')+chr(ord(str(a&#x5B;i]))^ord(str(b&#x5B;i%b.length])));return c}for(a=0;a!=1000;a++)debugger;x=h(str(x));source=\/\u04c7#7\u00f9\u00aa9\u00a8M\u00a4\u009f\u00c0.\u00e1\u00d4\u00a56\u00a6\u00a8\u00b9.\u00ff\u00d3\u00c2.\u00d6\u0089\u00a3J\u00ba\u00d3\u00b9W\u00fe\u00ca\u0096m\u00e3\u00d6\u00daG\u00a4\u0085\u00a2d\u00c89&amp;\u00f2\u00aa\u045b#\u00b3\u00ad1\u19e8\/;source.toString=function(){return c(source,x)};try{console.log('debug',source);with(source)return eval('eval(c(source,x))')}catch(e){}}\r\n&lt;\/script&gt;\r\n&lt;script&gt;\r\nfunction open_safe() {\r\n  keyhole.disabled = true;\r\n  password = \/^CTF{(&#x5B;0-9a-zA-Z_@!?-]+)}$\/.exec(keyhole.value);\r\n  if (!password || !x(password&#x5B;1])) return document.body.className = 'denied';\r\n  document.body.className = 'granted';\r\n  password = Array.from(password&#x5B;1]).map(c =&gt; c.charCodeAt());\r\n  encrypted = JSON.parse(localStorage.content || '');\r\n  content.value = encrypted.map((c,i) =&gt; c ^ password&#x5B;i % password.length]).map(String.fromCharCode).join('')\r\n}\r\nfunction save() {\r\n  plaintext = Array.from(content.value).map(c =&gt; c.charCodeAt());\r\n  localStorage.content = JSON.stringify(plaintext.map((c,i) =&gt; c ^ password&#x5B;i % password.length]));\r\n}\r\n&lt;\/script&gt;\r\n&lt;\/head&gt;\r\n&lt;body&gt;\r\n&lt;div&gt;\r\n  &lt;input id=&quot;keyhole&quot; autofocus onchange=&quot;open_safe()&quot; placeholder=&quot;&quot;&gt;\r\n&lt;\/div&gt;\r\n&lt;div class=&quot;wrap&quot;&gt;\r\n  &lt;div class=&quot;cube&quot;&gt;\r\n    ... cube ...\r\n  &lt;\/div&gt;\r\n&lt;\/div&gt;\r\n&lt;div id=&quot;result&quot;&gt;\r\n&lt;\/div&gt;\r\n&lt;div&gt;\r\n  &lt;input id=&quot;content&quot; onchange=&quot;save()&quot;&gt;\r\n&lt;\/div&gt;\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;\r\n<\/pre>\n<p>When the contents of the input fields are changed (<code>onchange<\/code> event), the function <code>open_safe()<\/code> is called:<\/p>\n<pre class=\"brush: jscript; first-line: 21; highlight: [3,4]; title: ; notranslate\" title=\"\">\r\nfunction open_safe() {\r\n  keyhole.disabled = true;\r\n  password = \/^CTF{(&#x5B;0-9a-zA-Z_@!?-]+)}$\/.exec(keyhole.value);\r\n  if (!password || !x(password&#x5B;1])) return document.body.className = 'denied';\r\n  document.body.className = 'granted';\r\n  password = Array.from(password&#x5B;1]).map(c =&gt; c.charCodeAt());\r\n  encrypted = JSON.parse(localStorage.content || '');\r\n  content.value = encrypted.map((c,i) =&gt; c ^ password&#x5B;i % password.length]).map(String.fromCharCode).join('')\r\n}\r\n<\/pre>\n<p>The following regular expression (<i>regexp<\/i>) is applied on the entered string: <code>\/^CTF{([0-9a-zA-Z_@!?-]+)}$\/<\/code>. This matches the usual flag-format: <code>CTF{flag}<\/code>. For the password only the characters within the curly brackets are used: <code>CTF{<b>PASSWORD<\/b>}<\/code>. After applying the regexp these characters are stored in <code>password[1]<\/code>, which is passed to the function <code>x<\/code>. If the content in the input field does not match the regexp (<code>!password<\/code>) or the function <code>x<\/code> returns false for the entered password (<code>!x(password[1])<\/code>), the <code style=\"color:#ff0000;\">Access Denied<\/code> message is displayed.<\/p>\n<p>If the correct password is entered, this password is used as a key to decrypt the contents of the local storage. As the challenge description states, we are not interested in any actual content for now since the provided local storage is empty and <i>the secrets are on the computer of the owner<\/i>. Nevertheless we are supposed to find the correct password in order to open the safe. Simply said: we need to find a password, which &#8211; when being passed to the function <code>x<\/code> &#8211; makes the function return true.<\/p>\n<p>Since the function <code>x<\/code> is placed in a single line, I started by indenting the code:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nfunction x(\u0445){\r\n  ord=Function.prototype.call.bind(''.charCodeAt);\r\n  chr=String.fromCharCode;\r\n  str=String;\r\n  \r\n  function h(s){\r\n    for(i=0;i!=s.length;i++){\r\n      a=((typeof a=='undefined'?1:a)+ord(str(s&#x5B;i])))%65521;\r\n      b=((typeof b=='undefined'?0:b)+a)%65521\r\n    }\r\n    return chr(b&gt;&gt;8)+chr(b&amp;0xFF)+chr(a&gt;&gt;8)+chr(a&amp;0xFF)\r\n  }\r\n  \r\n  function c(a,b,c){\r\n    for(i=0;i!=a.length;i++)c=(c||'')+chr(ord(str(a&#x5B;i]))^ord(str(b&#x5B;i%b.length])));\r\n    return c\r\n  }\r\n  \r\n  for(a=0;a!=1000;a++)debugger;\r\n  x=h(str(x));\r\n  source=\/\u04c7#7\u00f9\u00aa9\u00a8M\u00a4\u009f\u00c0.\u00e1\u00d4\u00a56\u00a6\u00a8\u00b9.\u00ff\u00d3\u00c2.\u00d6\u0089\u00a3J\u00ba\u00d3\u00b9W\u00fe\u00ca\u0096m\u00e3\u00d6\u00daG\u00a4\u0085\u00a2d\u00c89&amp;\u00f2\u00aa\u045b#\u00b3\u00ad1\u19e8\/;\r\n  source.toString=function(){return c(source,x)};\r\n  \r\n  try{\r\n    console.log('debug',source);\r\n    with(source)return eval('eval(c(source,x))')\r\n  }catch(e){}\r\n}\r\n<\/pre>\n<p>So what&#8217;s going on here?<\/p>\n<p>At the beginning three aliases are defined for ascii-, character- and string-conversation:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n  ord=Function.prototype.call.bind(''.charCodeAt);\r\n  chr=String.fromCharCode;\r\n  str=String;\r\n<\/pre>\n<p>Also a function called <code>h<\/code> is defined, which seems to calculate some kind of hash-value:<\/p>\n<pre class=\"brush: jscript; first-line: 6; title: ; notranslate\" title=\"\">\r\n  function h(s){\r\n    for(i=0;i!=s.length;i++){\r\n      a=((typeof a=='undefined'?1:a)+ord(str(s&#x5B;i])))%65521;\r\n      b=((typeof b=='undefined'?0:b)+a)%65521\r\n    }\r\n    return chr(b&gt;&gt;8)+chr(b&amp;0xFF)+chr(a&gt;&gt;8)+chr(a&amp;0xFF)\r\n  }\r\n<\/pre>\n<p>It is generally a good idea to google for the constants used in hash\/encryption-algorithms like this. I experienced that there is a good chance that this reveals the name of the algorithm in place, since the constants are oftentimes unique. In this case googling for <code>\"65521 hash\"<\/code> leads to the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Adler-32\" target=\"_blank\" rel=\"noopener\">Adler-32 algorithm<\/a>.<\/p>\n<p><i>Adler-32<\/i> is a 16-bit (4-byte) checksum, which is for example used by <code>zlib<\/code>. The low-order word (2 bytes: <code>a<\/code>) contains the sum of all ascii-values of the given input modulo 65521. This value is summed up in the high-order word (2 byte: <code>b<\/code>) in each iteration (also modulo 65521). The following picture illustrates the algorithm for the example <code>adler32('password') = 0x0f910374<\/code>:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/adler32_2.png\" alt=\"\" width=\"470\" class=\"alignnone size-full wp-image-675\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/adler32_2.png 770w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/adler32_2-291x300.png 291w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/adler32_2-768x792.png 768w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p>Notice that <code>b<\/code> is initialized by <code>0<\/code> and <code>a<\/code> by <code>1<\/code>.<\/p>\n<p>Further inspecting the code there is another function called <code>c<\/code>:<\/p>\n<pre class=\"brush: jscript; first-line: 14; title: ; notranslate\" title=\"\">\r\n  function c(a,b,c){\r\n    for(i=0;i!=a.length;i++)c=(c||'')+chr(ord(str(a&#x5B;i]))^ord(str(b&#x5B;i%b.length])));\r\n    return c\r\n  }\r\n<\/pre>\n<p>This functions simply encrypts\/decrypts a string (<code>a<\/code>) using a key (<code>b<\/code>) by XORing every byte of the string with the corresponding byte of the key.<\/p>\n<p>The outer function <code>x<\/code> ends with the following lines of code:<\/p>\n<pre class=\"brush: jscript; first-line: 19; title: ; notranslate\" title=\"\">\r\n  for(a=0;a!=1000;a++)debugger;\r\n  x=h(str(x));\r\n  source=\/\u04c7#7\u00f9\u00aa9\u00a8M\u00a4\u009f\u00c0.\u00e1\u00d4\u00a56\u00a6\u00a8\u00b9.\u00ff\u00d3\u00c2.\u00d6\u0089\u00a3J\u00ba\u00d3\u00b9W\u00fe\u00ca\u0096m\u00e3\u00d6\u00daG\u00a4\u0085\u00a2d\u00c89&amp;\u00f2\u00aa\u045b#\u00b3\u00ad1\u19e8\/;\r\n  source.toString=function(){return c(source,x)};\r\n  \r\n  try{\r\n    console.log('debug',source);\r\n    with(source)return eval('eval(c(source,x))')\r\n  }catch(e){}\r\n<\/pre>\n<p>The first line runs the command <code>debugger<\/code> 1000 times. This command stops the execution of the current code and runs the debugger if available (e.g. <code>F12-tools<\/code> are open). So it does basically the same as setting a breakpoint. When debugging the code we would have to step over the command 1000 times. Of course we can easily bypass this by commenting out the line or manually setting the variable <code>a<\/code> to 999 in a debugger.<\/p>\n<p>The second line assigns <code>x<\/code> the value of <code>h(str(x))<\/code>. Well, this is simply the adler32-checksum of the entered password. Isn&#8217;t it?<\/p>\n<p>On the next line a regexp called <code>source<\/code> is defined, which obviously contains encrypted data. The <code>toString<\/code> handler of the regexp is set to <code>function(){return c(source,x)}<\/code>. This means that whenever the regexp-object <code>source<\/code> is converted to a string, this function is called.<\/p>\n<p>At last, within a try\/catch-block, <code>console.log<\/code> is called to print <code>source<\/code> and <code>eval('eval(c(source,x))')<\/code> is returned. The <code>return<\/code> statement is proceeded by <code>with(source)<\/code>, which adds <code>source<\/code> to the scope chain when evaluating the <code>return<\/code> statement.<\/p>\n<p>We&#8217;ll get to the tricks behind all this in the next section.<\/p>\n<h3 id=\"h3_3\">3. Obfuscation \/ Anti-Debugging<\/h3>\n<p>While reading the source code for the first time, we have probably already seen some unusual statements. In this section I want to figure out, which obfuscation and anti-debugging techniques have been applied and how these can be tackled.<\/p>\n<h5>3.1. debugger<\/h5>\n<p>Well, this is the most obvious anti-debugging technique. The command <code>debugger<\/code> is called 1000 times:<\/p>\n<pre class=\"brush: jscript; first-line: 19; title: ; notranslate\" title=\"\">\r\n  for(a=0;a!=1000;a++)debugger;\r\n<\/pre>\n<p>As already stated, we can comment out the line or set the value of <code>a<\/code> to 999 manually in a debugger.<\/p>\n<p>Even though this line does not seem to be very tricky, it is not without other side-effects as we will see later!<\/p>\n<h5>3.2. source.toString \/ console.log<\/h5>\n<p>The <code>toString<\/code> handler of <code>source<\/code> is defined to call <code>c(source,x)<\/code>:<\/p>\n<pre class=\"brush: jscript; first-line: 22; title: ; notranslate\" title=\"\">\r\n  source.toString=function(){return c(source,x)};\r\n<\/pre>\n<p>This in combination with the following line &#8230;<\/p>\n<pre class=\"brush: jscript; first-line: 25; title: ; notranslate\" title=\"\">\r\n    console.log('debug',source);\r\n<\/pre>\n<p>&#8230; produces an infinite loop when a debugger\/console is present.<\/p>\n<p>Why is that? Consider the following code:<\/p>\n<pre class=\"brush: jscript; gutter: false; title: ; notranslate\" title=\"\">\r\nsource=\/\u04c7#7\u00f9\u00aa9\u00a8M\u00a4\u009f\u00c0.\u00e1\u00d4\u00a56\u00a6\u00a8\u00b9.\u00ff\u00d3\u00c2.\u00d6\u0089\u00a3J\u00ba\u00d3\u00b9W\u00fe\u00ca\u0096m\u00e3\u00d6\u00daG\u00a4\u0085\u00a2d\u00c89&amp;\u00f2\u00aa\u045b#\u00b3\u00ad1\u19e8\/;\r\nconsole.log(typeof(source));      \/\/ object\r\nconsole.log(source.constructor);  \/\/ \u0192 RegExp() { &#x5B;native code] }\r\n<\/pre>\n<p><code>source<\/code> is an object of type <code>RegExp<\/code>. When passing this object to <code>console.log<\/code> the regexp enclosed in slashes (<code>\/<\/code>) is printed:<\/p>\n<pre class=\"brush: jscript; gutter: false; title: ; notranslate\" title=\"\">\r\nconsole.log(source); \/\/ \/\u04c7#7\u00f9\u00aa9\u00a8M\u00a4\u009f\u00c0.\u00e1\u00d4\u00a56\u00a6\u00a8\u00b9.\u00ff\u00d3\u00c2.\u00d6\u0089\u00a3J\u00ba\u00d3\u00b9W\u00fe\u00ca\u0096m\u00e3\u00d6\u00daG\u00a4\u0085\u00a2d\u00c89&amp;\u00f2\u00aa\u045b#\u00b3\u00ad1\u19e8\/\r\n<\/pre>\n<p>When setting an own <code>toString<\/code> handler, this handler is called when the object is passed to <code>console.log<\/code>:<\/p>\n<pre class=\"brush: jscript; gutter: false; title: ; notranslate\" title=\"\">\r\nsource.toString = function() { return 'xxx'; }\r\nconsole.log(source);  \/\/ xxx\r\n<\/pre>\n<p>But why does <code>return c(source,x)<\/code> in the <code>toString<\/code> handler produce an infinite loop?<\/p>\n<p>Let&#8217;s have a look at the function <code>c<\/code> again:<\/p>\n<pre class=\"brush: jscript; first-line: 14; title: ; notranslate\" title=\"\">\r\n  function c(a,b,c){\r\n    for(i=0;i!=a.length;i++)c=(c||'')+chr(ord(str(a&#x5B;i]))^ord(str(b&#x5B;i%b.length])));\r\n    return c\r\n  }\r\n<\/pre>\n<p>The <code>for<\/code>-loop continues looping as long as <code>i!=a.length<\/code>. In this case <code>a<\/code> is our regexp object <code>source<\/code>. But wait.. What length does a regexp object have?<\/p>\n<pre class=\"brush: jscript; gutter: false; title: ; notranslate\" title=\"\">\r\nsource=\/\u04c7#7\u00f9\u00aa9\u00a8M\u00a4\u009f\u00c0.\u00e1\u00d4\u00a56\u00a6\u00a8\u00b9.\u00ff\u00d3\u00c2.\u00d6\u0089\u00a3J\u00ba\u00d3\u00b9W\u00fe\u00ca\u0096m\u00e3\u00d6\u00daG\u00a4\u0085\u00a2d\u00c89&amp;\u00f2\u00aa\u045b#\u00b3\u00ad1\u19e8\/;\r\nconsole.log(source.length);  \/\/ undefined\r\n<\/pre>\n<p><code>undefined<\/code>. This means the loop is never aborted.<\/p>\n<p>But why doesn&#8217;t the <code>eval<\/code> statement also calling <code>c<\/code> stuck in an infinte loop? &#8230;<\/p>\n<h5>3.3. with(source)<\/h5>\n<p>The <code>eval<\/code> statement is proceeded by <code>with(source)<\/code>:<\/p>\n<pre class=\"brush: jscript; first-line: 26; title: ; notranslate\" title=\"\">\r\n    with(source)return eval('eval(c(source,x))')\r\n<\/pre>\n<p>As can be read <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Statements\/with\" target=\"_blank\" rel=\"noopener\">here<\/a>: <i>The with statement extends the scope chain for a statement.<\/i>.<\/p>\n<p>Let&#8217;s have a look at a simple example:<\/p>\n<pre class=\"brush: jscript; gutter: false; title: ; notranslate\" title=\"\">\r\nvar sample = {'id': 1};\r\n\r\nconsole.log(sample.id);       \/\/ 1\r\nconsole.log(id);              \/\/ Uncaught ReferenceError: id is not defined\r\n\r\nwith(sample) console.log(id); \/\/1\r\n<\/pre>\n<p>The object <code>sample<\/code> contains an attribute <code>id<\/code>, which can be accessed by <code>sample.id<\/code>. When using <code>with(sample)<\/code> we can directly access <code>id<\/code> without prepending <code>sample<\/code>.<\/p>\n<p>This means that the statement above can also be read like this:<\/p>\n<pre class=\"brush: jscript; first-line: 26; title: ; notranslate\" title=\"\">\r\n    return eval('eval(c(source.source,x))')\r\n<\/pre>\n<p>The aroused confusion by the fact, that the object&#8217;s name is the same as the attribute&#8217;s name is probably not a coincidence \ud83d\ude09<\/p>\n<p>The <code>RegExp.source<\/code> attribute returns a string containing the source text of the regexp object (see <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/RegExp\/source\" target=\"_blank\" rel=\"noopener\">here<\/a>):<\/p>\n<pre class=\"brush: jscript; gutter: false; title: ; notranslate\" title=\"\">\r\nsource=\/\u04c7#7\u00f9\u00aa9\u00a8M\u00a4\u009f\u00c0.\u00e1\u00d4\u00a56\u00a6\u00a8\u00b9.\u00ff\u00d3\u00c2.\u00d6\u0089\u00a3J\u00ba\u00d3\u00b9W\u00fe\u00ca\u0096m\u00e3\u00d6\u00daG\u00a4\u0085\u00a2d\u00c89&amp;\u00f2\u00aa\u045b#\u00b3\u00ad1\u19e8\/;\r\nconsole.log(source.source);        \/\/ \u04c7#7\u00f9\u00aa9\u00a8M\u00a4\u009f\u00c0.\u00e1\u00d4\u00a56\u00a6\u00a8\u00b9.\u00ff\u00d3\u00c2.\u00d6\u0089\u00a3J\u00ba\u00d3\u00b9W\u00fe\u00ca\u0096m\u00e3\u00d6\u00daG\u00a4\u0085\u00a2d\u00c89&amp;\u00f2\u00aa\u045b#\u00b3\u00ad1\u19e8\r\nconsole.log(source.source.length); \/\/ 55\r\n<\/pre>\n<p>This way a string is being passed to <code>c<\/code> and thus the <code>for<\/code>-loop iterates over the string&#8217;s length appropriately.<\/p>\n<h5>3.4. encoding: x != x<\/h5>\n<p>While playing around with the source code, I added the following debug-message in the function <code>x<\/code>:<\/p>\n<pre class=\"brush: jscript; gutter: false; title: ; notranslate\" title=\"\">\r\nfunction x(\u0445){\r\n  console.log(x);\r\n  ...\r\n<\/pre>\n<p>I assumed that the passed argument (the password being entered) would be printed, but&#8230;<\/p>\n<pre class=\"brush: jscript; gutter: false; title: ; notranslate\" title=\"\">\r\n\u0192 x(\u0445){console.log(x);ord=Function.prototype.call.bind(''.charCodeAt);chr=String.fromCharCode;str=String;function h(s){for(i=0;i!=s.length;i++){a=((typeof a=='undefined'?1:a)+ord(str(s&#x5B;i])))%65521;b=((\u2026\r\n<\/pre>\n<p>&#8230; the function <code>x<\/code> is printed!? That should not be the case, since identifiers of passed arguments (local scope) should overwrite global scope identifiers (function <code>x<\/code>).<\/p>\n<p>Printing a function <code>foo<\/code>:<\/p>\n<pre class=\"brush: jscript; gutter: false; title: ; notranslate\" title=\"\">\r\nfunction foo(a) { console.log(foo); }\r\nfoo('qwerty');  \/\/ here foo is the function foo (global scope):\r\n                \/\/ \u0192 foo(a) { console.log(foo); }\r\n<\/pre>\n<p>Passed argument with the same name overwrites global scope:<\/p>\n<pre class=\"brush: jscript; gutter: false; title: ; notranslate\" title=\"\">\r\nfunction foo(foo) { console.log(foo); }\r\nfoo('qwerty');  \/\/ here foo is the passed argument (local scope):\r\n                \/\/ qwerty\r\n<\/pre>\n<p>After verifying this assumption, I came to the conclusion that something cannot be right with the <code>x<\/code> being passed and viewed the file with <code>hexdump<\/code>:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\nuser@host:~\/4dead099e841668a8d86e36fcde8099ce134c195da9863dfb9039043d366942d$ hexdump -C js_safe_2.html \r\n00000000  3c 21 44 4f 43 54 59 50  45 20 68 74 6d 6c 3e 0a  |&lt;!DOCTYPE html&gt;.|\r\n00000010  3c 68 74 6d 6c 3e 0a 3c  68 65 61 64 3e 0a 3c 6d  |&lt;html&gt;.&lt;head&gt;.&lt;m|\r\n00000020  65 74 61 20 63 68 61 72  73 65 74 3d 22 75 74 66  |eta charset=&quot;utf|\r\n00000030  2d 38 22 3e 0a 3c 74 69  74 6c 65 3e 4a 53 20 73  |-8&quot;&gt;.&lt;title&gt;JS s|\r\n...\r\n00000840  65 3e 0a 3c 73 63 72 69  70 74 3e 0a 0a 66 75 6e  |e&gt;.&lt;script&gt;..fun|\r\n00000850  63 74 69 6f 6e 20 78 28  d1 85 29 7b 6f 72 64 3d  |ction x(..){ord=|   &lt;----\r\n00000860  46 75 6e 63 74 69 6f 6e  2e 70 72 6f 74 6f 74 79  |Function.prototy|\r\n...\r\n<\/pre>\n<p>The argument identifier <code>d1 85<\/code> is the UTF-8 representation of the cyrillic small letter ha, which looks like an <code>x<\/code> (<code>78<\/code>).<\/p>\n<p>Also notice that <code>charCodeAt<\/code> returns <code>0x445<\/code>, not <code>0xd185<\/code> (see <a href=\"http:\/\/www.fileformat.info\/info\/unicode\/char\/445\/index.htm\" target=\"_blank\" rel=\"noopener\">here<\/a>):<\/p>\n<pre class=\"brush: jscript; gutter: false; title: ; notranslate\" title=\"\">\r\nvar cyrillic_x = '\u0445';\r\nconsole.log(cyrillic_x.charCodeAt(0).toString(16)); \/\/ 445\r\n<\/pre>\n<p>The <code>x<\/code> which is being used with the checksum-function <code>h<\/code> is actually an <code>x<\/code> (<code>78<\/code>) and thus identifies the <code>function x<\/code>:<\/p>\n<pre class=\"brush: jscript; first-line: 20; title: ; notranslate\" title=\"\">\r\n  x=h(str(x));\r\n<\/pre>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\n...\r\n000009e0  2b 2b 29 64 65 62 75 67  67 65 72 3b 78 3d 68 28  |++)debugger;x=h(|\r\n000009f0  73 74 72 28 78 29 29 3b  73 6f 75 72 63 65 3d 2f  |str(x));source=\/|\r\n...\r\n<\/pre>\n<p>This means, that the key to decrypt the string stored in <code>source<\/code> is not the checksum of the entered password, but the checksum of the stringified function <code>x<\/code>!<\/p>\n<p>So it should actually be easy to decrypt the string:<br \/>\n&#8211;&gt; calculate the checksum of the stringified function <code>x<\/code><br \/>\n&#8211;&gt; call the decrypt function <code>c<\/code> with <code>source.source<\/code> and the calculated checksum<\/p>\n<pre class=\"brush: jscript; gutter: false; title: ; notranslate\" title=\"\">\r\n\/\/ original function x\r\n\r\nfunction x(\u0445){ord=Function.prototype.call.bind(''.charCodeAt);chr=String.fromCharCode;str=String;function h(s){for(i=0;i!=s.length;i++){a=((typeof a=='undefined'?1:a)+ord(str(s&#x5B;i])))%65521;b=((typeof b=='undefined'?0:b)+a)%65521}return chr(b&gt;&gt;8)+chr(b&amp;0xFF)+chr(a&gt;&gt;8)+chr(a&amp;0xFF)}function c(a,b,c){for(i=0;i!=a.length;i++)c=(c||'')+chr(ord(str(a&#x5B;i]))^ord(str(b&#x5B;i%b.length])));return c}for(a=0;a!=1000;a++)debugger;x=h(str(x));source=\/\u04c7#7\u00f9\u00aa9\u00a8M\u00a4\u009f\u00c0.\u00e1\u00d4\u00a56\u00a6\u00a8\u00b9.\u00ff\u00d3\u00c2.\u00d6\u0089\u00a3J\u00ba\u00d3\u00b9W\u00fe\u00ca\u0096m\u00e3\u00d6\u00daG\u00a4\u0085\u00a2d\u00c89&amp;\u00f2\u00aa\u045b#\u00b3\u00ad1\u19e8\/;source.toString=function(){return c(source,x)};try{console.log('debug',source);with(source)return eval('eval(c(source,x))')}catch(e){}}\r\n\r\n\r\n\/\/ extracted helper-functions (ord, char, str), h and c\r\n\r\nord=Function.prototype.call.bind(''.charCodeAt);chr=String.fromCharCode;str=String;\r\n\r\nfunction h(s){for(i=0;i!=s.length;i++){a=((typeof a=='undefined'?1:a)+ord(str(s&#x5B;i])))%65521;b=((typeof b=='undefined'?0:b)+a)%65521}return chr(b&gt;&gt;8)+chr(b&amp;0xFF)+chr(a&gt;&gt;8)+chr(a&amp;0xFF)}\r\n\r\nfunction c(a,b,c){for(i=0;i!=a.length;i++)c=(c||'')+chr(ord(str(a&#x5B;i]))^ord(str(b&#x5B;i%b.length])));return c}\r\n\r\n\/\/ calculate checksum of x and decrypt source string (source.source)\r\n\r\nvar source = \/\u04c7#7\u00f9\u00aa9\u00a8M\u00a4\u009f\u00c0.\u00e1\u00d4\u00a56\u00a6\u00a8\u00b9.\u00ff\u00d3\u00c2.\u00d6\u0089\u00a3J\u00ba\u00d3\u00b9W\u00fe\u00ca\u0096m\u00e3\u00d6\u00daG\u00a4\u0085\u00a2d\u00c89&amp;\u00f2\u00aa\u045b#\u00b3\u00ad1\u19e8\/;\r\nvar checksum = h(str(x));\r\n\r\nconsole.log(c(source.source, checksum));\r\n<\/pre>\n<p>And the output is ..<\/p>\n<pre class=\"brush: jscript; gutter: false; title: ; notranslate\" title=\"\">\r\n\u0472\u00fe6\u00b0\u001f\u00e4\u00a9\u0004\u0011B\u00c1gT\t\u00a4\u0013u\u00b8gJ\u000e\u00c3gcT\u00a2\u0003\u000f\u000e\u00b8\u001eK\u0017\u0097$V\u000b\u00db\u000e\u0011X\u00a3-}\u00e4'\u00bb\u001f\u0486&quot;\u00fa\u0018\u00ec\u19e9\r\n<\/pre>\n<p>? That does not seem right. The decrypted string should be passed to <code>eval<\/code> once again, but this does not look like valid javascript-code. This probably means, that the checksum is not correct. So I decided to use a debugger to see how the original function <code>h<\/code> calculates the checksum.<\/p>\n<h5>3.5. variable initialization: a<\/h5>\n<p>In order to debug the function <code>h<\/code>, we can simply enter a password, which matches the regexp format (e.g. <code>CTF{test}<\/code>) and wait for the <code>debugger<\/code> instruction to be reached:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/debug_2.png\" alt=\"\" width=\"800\" class=\"alignnone size-full wp-image-656\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/debug_2.png 1279w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/debug_2-300x221.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/debug_2-768x565.png 768w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/debug_2-1024x753.png 1024w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p>Since we are stuck in the for-loop now, we can adjust the variable <code>a<\/code> to <code>999<\/code> so that the loop terminates on the next iteration:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_1.png\" alt=\"\" width=\"800\" class=\"alignnone size-full wp-image-657\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_1.png 1153w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_1-300x84.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_1-768x215.png 768w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_1-1024x287.png 1024w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_2.png\" alt=\"\" width=\"800\" class=\"alignnone size-full wp-image-647\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_2.png 1153w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_2-300x84.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_2-768x215.png 768w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_2-1024x287.png 1024w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_3.png\" alt=\"\" width=\"800\"  class=\"alignnone size-full wp-image-648\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_3.png 1153w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_3-300x84.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_3-768x215.png 768w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_3-1024x287.png 1024w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_4.png\" alt=\"\" width=\"800\" class=\"alignnone size-full wp-image-649\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_4.png 1153w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_4-300x84.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_4-768x215.png 768w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_4-1024x287.png 1024w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p>We then single-step into the function <code>h<\/code>:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_5.png\" alt=\"\" width=\"800\" class=\"alignnone size-full wp-image-651\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_5.png 1153w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_5-300x84.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_5-768x215.png 768w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_5-1024x287.png 1024w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_6.png\" alt=\"\" width=\"800\" class=\"alignnone size-full wp-image-652\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_6.png 1153w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_6-300x84.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_6-768x215.png 768w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_6-1024x287.png 1024w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p>Here <code>a<\/code> is incremented the first time:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_7.png\" alt=\"\" width=\"800\" class=\"alignnone size-full wp-image-653\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_7.png 1153w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_7-300x84.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_7-768x215.png 768w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_7-1024x287.png 1024w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_8.png\" alt=\"\" width=\"800\" class=\"alignnone size-full wp-image-658\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_8.png 1153w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_8-300x84.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_8-768x215.png 768w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/0_debug_8-1024x287.png 1024w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p>What&#8217;s this? <code>a<\/code> is <code>1102<\/code> now!? Of course! <code>a<\/code> was already defined. Thus it hasn&#8217;t been initialized by <code>1<\/code>. <code>a<\/code> was defined within the <code>debugger<\/code>-loop and has the value <code>1000<\/code> when the function <code>h<\/code> is called. After the first ascii-value (<code>f = 102<\/code>) has been added, it&#8217;s value is <code>1102<\/code>.<\/p>\n<p>Thus we only need to initialize <code>a<\/code> to <code>1000<\/code> in the above code:<\/p>\n<pre class=\"brush: jscript; gutter: false; highlight: [5]; title: ; notranslate\" title=\"\">\r\n...\r\n\/\/ calculate checksum of x and decrypt source\r\n\r\nvar source = \/\u04c7#7\u00f9\u00aa9\u00a8M\u00a4\u009f\u00c0.\u00e1\u00d4\u00a56\u00a6\u00a8\u00b9.\u00ff\u00d3\u00c2.\u00d6\u0089\u00a3J\u00ba\u00d3\u00b9W\u00fe\u00ca\u0096m\u00e3\u00d6\u00daG\u00a4\u0085\u00a2d\u00c89&amp;\u00f2\u00aa\u045b#\u00b3\u00ad1\u19e8\/;\r\nvar a = 1000;\r\nvar checksum = h(str(x));\r\n\r\nconsole.log(c(source.source, checksum));\r\n<\/pre>\n<p>Which outputs:<\/p>\n<pre class=\"brush: jscript; gutter: false; title: ; notranslate\" title=\"\">\r\n\u0445==c('\u00a2\u00d7&amp;\u0081\u00ca\u00b4c\u00ca\u00af\u00ac$\u00b6\u00b3\u00b4}\u00cd\u00c8\u00b4T\u0097\u00a9\u00d08\u00cd\u00b3\u00cd|\u00d4\u009c\u00f7a\u00c8\u00d0\u00dd&amp;\u009b\u00a8\u00feJ',h(\u0445))\/\/\u19e2\r\n<\/pre>\n<p>This actually looks like valid javascript-code!<\/p>\n<h3 id=\"h3_4\">4. Solution<\/h3>\n<p>After tackling all obfuscation and anti-debugging techniques we have successfully decrypted the <code>source<\/code> string.<\/p>\n<p>Notice that the <code>x<\/code> used in the decrypted javascript-code is the cyrillic x, which is the password the user entered:<\/p>\n<pre class=\"brush: jscript; gutter: false; highlight: [11,14]; title: ; notranslate\" title=\"\">\r\nvar decrypted = &quot;\u0445==c('\u00a2\u00d7&amp;\u0081\u00ca\u00b4c\u00ca\u00af\u00ac$\u00b6\u00b3\u00b4}\u00cd\u00c8\u00b4T\u0097\u00a9\u00d08\u00cd\u00b3\u00cd|\u00d4\u009c\u00f7a\u00c8\u00d0\u00dd&amp;\u009b\u00a8\u00feJ',h(\u0445))\/\/\u19e2&quot;;\r\n\r\nfunction hexdump(txt) {\r\n  r = ''\r\n  for (var i = 0; i &lt; txt.length; i++) r += txt.charCodeAt(i).toString(16) + ' ';\r\n  return r;\r\n}\r\n\r\nconsole.log(hexdump(decrypted));\r\n\r\n\/\/ 445 3d 3d 63 28 27 a2 d7 26 81 ca b4 63 ca af ac    &lt;-- 445 = cyrillic x\r\n\/\/  24 b6 b3 b4 7d cd c8 b4 54 97 a9 d0 38 cd b3 cd\r\n\/\/  7c d4 9c f7 61 c8 d0 dd 26 9b a8 fe 4a 27 2c 68\r\n\/\/  28 445 29 29 2f 2f 19e2                            &lt;-- 445 = cyrillic x\r\n<\/pre>\n<p>Remember: our goal is to make the function <code>x<\/code> to return true. The returned value is <code>eval(\"\u0445==c('\u00a2\u00d7&\u0081\u00ca\u00b4c\u00ca\u00af\u00ac$\u00b6\u00b3\u00b4}\u00cd\u00c8\u00b4T\u0097\u00a9\u00d08\u00cd\u00b3\u00cd|\u00d4\u009c\u00f7a\u00c8\u00d0\u00dd&\u009b\u00a8\u00feJ',h(\u0445))\/\/\u19e2\")<\/code>. This means that <code>'\u00a2\u00d7&\u0081\u00ca\u00b4c\u00ca\u00af\u00ac$\u00b6\u00b3\u00b4}\u00cd\u00c8\u00b4T\u0097\u00a9\u00d08\u00cd\u00b3\u00cd|\u00d4\u009c\u00f7a\u00c8\u00d0\u00dd&\u009b\u00a8\u00feJ'<\/code> is the encrypted password we are looking for. It is encrypted using the checksum of the password itself: <code>h(\u0445)<\/code>.<\/p>\n<p>How can we decrypt the password?<br \/>\n&#8211;&gt; We <b>don&#8217;t know<\/b> the checksum being used to encrypt the password as we simply don&#8217;t know the password.<br \/>\n&#8211;&gt; We <b>know<\/b> that the key-length being used is 4.<br \/>\n&#8211;&gt; We <b>know<\/b> that the decrypted password must match the regular expression and can thus only contain the following characters: <code>0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_@!?-<\/code><\/p>\n<p>The 4-byte key is XORed with the ciphertext:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/key.png\" alt=\"\" width=\"666\" class=\"alignnone size-full wp-image-664\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/key.png 866w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/key-300x133.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/key-768x341.png 768w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p>Considering the mentioned assumptions we can look for possible values for each byte of the key, which produces a valid plaintext only containing characters of the allowed charset. The following picture illustrates this method:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/charset.png\" alt=\"\" width=\"1538\" height=\"698\" class=\"alignnone size-full wp-image-665\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/charset.png 1538w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/charset-300x136.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/charset-768x349.png 768w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/charset-1024x465.png 1024w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p>Finally I wrote the following python-script, which determines valid values for each byte of the key and tries to decrypt the encrypted password with all potentially valid key-combinations:<\/p>\n<pre class=\"brush: python; first-line: 0; title: ; notranslate\" title=\"\">\r\nuser@host:~$ cat decrypt.py \r\n#!\/usr\/bin\/env python\r\n\r\nf = open('encrypted.bin')\r\nencr = f.read()\r\nchars = &#x5B;&#x5B;], &#x5B;], &#x5B;], &#x5B;]]\r\ncharset = &quot;0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_@!?-&quot;\r\n\r\n\r\n&quot;&quot;&quot;\r\nDetermines key-bytes, which produce a decrypted text containing only valid characters.\r\n&quot;&quot;&quot;\r\ndef validKeys(arr):\r\n  r = &#x5B;]\r\n  for i in range(256):\r\n    valid = True\r\n    for a in arr:\r\n      if (chr(ord(a)^i) not in charset):\r\n        valid = False\r\n        break\r\n    if (valid): r.append(i)\r\n  return r\r\n\r\n\r\n&quot;&quot;&quot;\r\nDecrypts text by XORing with key.\r\n&quot;&quot;&quot;\r\ndef decrypt(txt, k):\r\n  r = ''\r\n  for i in range(len(txt)):\r\n    r += chr(ord(txt&#x5B;i])^ord(k&#x5B;i%4]))\r\n  return r\r\n\r\n\r\n# each array contains the bytes, which are XORed with the same byte of the key\r\nfor i in range(len(encr)):\r\n  chars&#x5B;i%4].append(encr&#x5B;i])\r\n\r\n\r\n# find best solution for each key-byte\r\nkeys = &#x5B;]\r\nfor c in chars:\r\n  keys.append(validKeys(c))\r\n\r\n# print possible solutions using the calculated keys\r\nfor k0 in keys&#x5B;0]:\r\n  for k1 in keys&#x5B;1]:\r\n    for k2 in keys&#x5B;2]:\r\n      for k3 in keys&#x5B;3]:\r\n        key = chr(k0)+chr(k1)+chr(k2)+chr(k3)\r\n        print(&quot;&#x5B; key = &quot;+key.encode(&quot;hex&quot;)+ &quot; ]:&quot;),\r\n        print(decrypt(encr, key))\r\n\r\n<\/pre>\n<p>Running the script yields two possible passwords:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [3]; title: ; notranslate\" title=\"\">\r\nuser@host:~$ .\/decrypt.py \r\n&#x5B; key = fd9515f9 ]: _B3x7!v3R91ON!h45!AnTE-4NXi-abt1-H3bUk_\r\n&#x5B; key = fd9915f9 ]: _N3x7-v3R51ON-h45-AnTI-4NTi-ant1-D3bUg_\r\n<\/pre>\n<p>Obviously the second one makes sense. Thus the flag is <code><span class=\"spanFlag\">CTF{_N3x7-v3R51ON-h45-AnTI-4NTi-ant1-D3bUg_}<\/span><\/code>.<\/p>\n<p>The following picture illustrates the relation of all involved strings \/ checksums.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/final4.png\" alt=\"\" width=\"770\" height=\"410\" class=\"alignnone size-full wp-image-669\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/final4.png 770w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/final4-300x160.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/06\/final4-768x409.png 768w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p>Done! A really great challenge \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The qualifications for the Google Capture The Flag 2018 (ctftime.org) ran from 23\/06\/2018, 00:00 UTC to 24\/06\/2018 23:59 UTC. The CTF was worked out very well. There have been plenty of interesting and creative challenges. This time I decided to focus on the category web and managed to solve the challenge JS safe 2.0, which &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/devel0pment.de\/?p=587\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Google CTF 2018 (Quals) &#8211; writeup JS safe 2.0&#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":[24],"tags":[20,28],"class_list":["post-587","post","type-post","status-publish","format-standard","hentry","category-ctf","tag-ctf","tag-web"],"_links":{"self":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts\/587"}],"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=587"}],"version-history":[{"count":66,"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts\/587\/revisions"}],"predecessor-version":[{"id":678,"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts\/587\/revisions\/678"}],"wp:attachment":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=587"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=587"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=587"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}