<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://mysterypotatoguy.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://mysterypotatoguy.github.io/" rel="alternate" type="text/html" /><updated>2026-06-03T13:48:45+00:00</updated><id>https://mysterypotatoguy.github.io/feed.xml</id><title type="html">Mysterypotatoguy</title><subtitle>Hi! My name is Alex, I am a hacker, programmer, and former exec member of LUHack.
  This site contains some of my writeups for CTF challenges I&apos;ve completed, as well as a list of the interesting things I&apos;ve read!
</subtitle><author><name>Mysterypotatoguy</name></author><entry><title type="html">Coffee_invocation</title><link href="https://mysterypotatoguy.github.io/writeup/coffee-invocation" rel="alternate" type="text/html" title="Coffee_invocation" /><published>2023-06-10T00:00:00+00:00</published><updated>2023-06-10T00:00:00+00:00</updated><id>https://mysterypotatoguy.github.io/writeup/coffee_invocation</id><content type="html" xml:base="https://mysterypotatoguy.github.io/writeup/coffee-invocation"><![CDATA[<p>coffee_invocation was one of the reversing challenges for the HTB x UNI 2020 CTF, with its twist being that rather than just a standard C or C++ program, it utilises the <a href="https://en.wikipedia.org/wiki/Java_Native_Interface">Java Native Interface</a> to execute most of the program logic
As far as I can tell no team solved this during the event, likely due to perceived time investment for learning about JNI, but it is surprisingly simple once you can wrap your head around some of the obstacles.</p>

<p>There were no debugging symbols present on this binary so any function names, apart from the JNI provided ones, have been provided by myself from deducing what they do.</p>

<hr />
<h2 id="main">main</h2>

<p>Decompiling <code class="language-plaintext highlighter-rouge">main</code> immediately gives away the JNI twist for this challenge, the first function call is to <code class="language-plaintext highlighter-rouge">JNI_CreateJavaVM</code>, with some arguments that consist of some unknown numbers and strings.
I imported <a href="https://gist.github.com/jcalabres/bf8d530b3f18c30ca6f66388357b1d91">this JNI header definition</a> into Ghidra to define the JNI specific types and allow me to view which fields and functions were being accessed, from here we can make a little more sense of things.</p>

<p>After this, the arguments to <code class="language-plaintext highlighter-rouge">JNI_CreateJavaVM</code> make a bit more sense. The function arguments are a pointer to a <code class="language-plaintext highlighter-rouge">JavaVM</code> struct, a pointer to a <code class="language-plaintext highlighter-rouge">JNIEnv</code> struct, and a <code class="language-plaintext highlighter-rouge">JavaVMInitArgs</code> struct -
The <code class="language-plaintext highlighter-rouge">JVMInitArgs</code> don’t tell us much, the struct only takes a <code class="language-plaintext highlighter-rouge">version</code>, <code class="language-plaintext highlighter-rouge">nOptions</code> and <code class="language-plaintext highlighter-rouge">options</code> from which we can determine the Java version is 1.8.
The <code class="language-plaintext highlighter-rouge">jvm</code> and <code class="language-plaintext highlighter-rouge">env</code> pointers are then populated with the respective structs, these are the structs with which the program will interface with the Java process, the <code class="language-plaintext highlighter-rouge">JavaVM</code> struct being a function table and an interface to the running VM, providing the ability to attach threads or destroy it. 
The <code class="language-plaintext highlighter-rouge">JNIEnv</code> struct is far more useful in this challenge, providing a function table giving access to call methods, edit fields, and create objects.</p>

<p><img src="/images/coffee_main.png" alt="main" /></p>

<h3 id="get_option">get_option</h3>

<p>The next call is to a function I have renamed to <code class="language-plaintext highlighter-rouge">get_option</code>, it is a fairly simple function which prints some ASCII art and asks for a selection from a menu, on picking anything but <code class="language-plaintext highlighter-rouge">[REDACTED]</code> the Java VM is destroyed and the program terminates. On picking <code class="language-plaintext highlighter-rouge">[REDACTED]</code> the function returns back to <code class="language-plaintext highlighter-rouge">main</code></p>

<p><img src="/images/coffee_get_option.png" alt="get_option" /></p>

<p>Next, <code class="language-plaintext highlighter-rouge">main</code> checks <code class="language-plaintext highlighter-rouge">argc</code> is greater than 2 (One argument supplied via the command line since <code class="language-plaintext highlighter-rouge">argv[0]</code> is the command with which the program was invoked). If there is no argument present a message is printed via the renamed <code class="language-plaintext highlighter-rouge">print</code> function</p>

<h3 id="print">print</h3>

<p>Printing to standard out is usually pretty simple in C, but the challenge authors decided to rewrite this functionality with JNI. Using the JNI definitions and some basic Java knowledge, it’s pretty clear that this function just finds the <code class="language-plaintext highlighter-rouge">PrintStream</code> of <code class="language-plaintext highlighter-rouge">System.out</code>, then calls <code class="language-plaintext highlighter-rouge">println(String)</code> on it, providing the <code class="language-plaintext highlighter-rouge">char*</code> passed in the original C function.</p>

<p><img src="/images/coffee_print.png" alt="print" /></p>

<p>This <code class="language-plaintext highlighter-rouge">print</code> (and later <code class="language-plaintext highlighter-rouge">print_str</code> which seems to be identical) function is used for all further printing within the program.</p>

<h3 id="get_flag">get_flag</h3>

<p>Focussing back on <code class="language-plaintext highlighter-rouge">main</code>, if the <code class="language-plaintext highlighter-rouge">argc &lt; 2</code> check does not pass, the next call is to a function I renamed to <code class="language-plaintext highlighter-rouge">get_flag</code>, passing the <code class="language-plaintext highlighter-rouge">JNIEnv</code> and <code class="language-plaintext highlighter-rouge">argv[1]</code> as arguments.
This function calls <code class="language-plaintext highlighter-rouge">verify1</code> and <code class="language-plaintext highlighter-rouge">verify2</code>, checks if they both return <code class="language-plaintext highlighter-rouge">0</code> and if so, prints out some ASCII art and gives us the flag.</p>

<p><img src="/images/coffee_get_flag.png" alt="get_flag" /></p>

<h2 id="verify1">verify1</h2>

<p>Here begins the most complex parts of this challenge, <code class="language-plaintext highlighter-rouge">verify1</code> first calls a function I have renamed <code class="language-plaintext highlighter-rouge">hook_shutdown</code>, which essentially overrides Java’s <code class="language-plaintext highlighter-rouge">static native void halt0(int status)</code> function and replaces it with a function <code class="language-plaintext highlighter-rouge">shutdown_hook_param_save</code>, this either saves the status code in a global variable, or if it is already set, compares the status code with the currently stored value and replaces it if it is less than. This will be used later for some program logic.</p>

<p><img src="/images/coffee_verify1.png" alt="verify1" /></p>

<p><img src="/images/coffee_shutdown.png" alt="shutdown" /></p>

<h3 id="get_remappings--remapping-type-caches">get_remappings / Remapping Type caches</h3>

<p><code class="language-plaintext highlighter-rouge">get_remappings</code> is a function which takes an integer and depending on that integer, returns a pointer to a different byte array. These arrays all contain values from hex 0x00 to hex 0xFF, but have some variation on their order. For example <code class="language-plaintext highlighter-rouge">plus_3D</code> begins at 0x3D and increments at each index, wrapping around to 0x00 after 0xFF.</p>

<p><img src="/images/coffee_remappings.png" alt="remappings" /></p>

<p>In a few places this challenge will play around with the caches of some of Java’s boxed types such as <code class="language-plaintext highlighter-rouge">Byte</code>, <code class="language-plaintext highlighter-rouge">Short</code>, <code class="language-plaintext highlighter-rouge">Character</code> and <code class="language-plaintext highlighter-rouge">Boolean</code>. These caches hold all of the 256 possible values for <code class="language-plaintext highlighter-rouge">Byte</code> and a variable number for <code class="language-plaintext highlighter-rouge">Character</code> or <code class="language-plaintext highlighter-rouge">Short</code>. By overwriting these, any operations performed within the upcoming Java code will use these new mappings, so we must be aware of this going forth.</p>

<p><img src="/images/coffee_remap_bytes.png" alt="remap_bytes" />
<img src="/images/coffee_remap_shorts.png" alt="remap_shorts" /></p>

<p>For <code class="language-plaintext highlighter-rouge">verify1</code>, <code class="language-plaintext highlighter-rouge">Byte</code> and <code class="language-plaintext highlighter-rouge">Short</code> are remapped to new byte orders, <code class="language-plaintext highlighter-rouge">plus_3D</code> (Hex 00 to FF but offset by +3D)  and <code class="language-plaintext highlighter-rouge">00_CD_9A_67_34</code> (this is the pattern of 5 bytes which are all incremented to form the pattern) respectively.</p>

<hr />

<p>Two compiled Java class files are contained within this binary, <code class="language-plaintext highlighter-rouge">get_verify_source</code> selects which one to access and then provides a pointer to it as well as its length in bytes. 
<code class="language-plaintext highlighter-rouge">verify1</code> accesses the first and makes a JNI call to <code class="language-plaintext highlighter-rouge">DefineClass</code> to load the class into the JVM. Then, still using JNI, creates an empty <code class="language-plaintext highlighter-rouge">String</code>, a length 2 <code class="language-plaintext highlighter-rouge">String[]</code> array of these empty <code class="language-plaintext highlighter-rouge">String</code>s. Our input string which is taken from <code class="language-plaintext highlighter-rouge">argv[1]</code> is substringed to length 30, placed in index 0 of the 2-element <code class="language-plaintext highlighter-rouge">String[]</code> array, and is then accompanied by a seemingly random <code class="language-plaintext highlighter-rouge">String</code> of characters placed in slot 1.
The <code class="language-plaintext highlighter-rouge">verify1</code> class now has its main method called via <code class="language-plaintext highlighter-rouge">CallStaticVoidMethod</code> with the 2-element <code class="language-plaintext highlighter-rouge">String[]</code> as its <code class="language-plaintext highlighter-rouge">String[] args</code> argument.</p>

<p>Extracting the <code class="language-plaintext highlighter-rouge">verify1</code> source and decompiling it (with some re-arranging of code for readability) we find a fairly simple functionality. Both <code class="language-plaintext highlighter-rouge">String</code>s from the 2-element array are checked to be present, non-null and of the same length. Providing this is true, each character in the <code class="language-plaintext highlighter-rouge">String</code> is compared to its corresponding character in the other <code class="language-plaintext highlighter-rouge">String</code> and if all match, the <code class="language-plaintext highlighter-rouge">main</code> method can exit with status 0, else it will return with a non-zero value depending on which condition was not met.</p>

<p><img src="/images/coffee_verify1_java.png" alt="verify1_java" /></p>

<p>However, remembering that both the <code class="language-plaintext highlighter-rouge">Byte</code> and <code class="language-plaintext highlighter-rouge">Short</code> caches have been tampered with, we must do some scripting to match values in both arrays to their remappings, and reverse this to find how we can match our input to the remapped second <code class="language-plaintext highlighter-rouge">String</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>remap1 = "3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c"
remap2 = "00 cd 9a 67 34 01 ce 9b 68 35 02 cf 9c 69 36 03 d0 9d 6a 37 04 d1 9e 6b 38 05 d2 9f 6c 39 06 d3 a0 6d 3a 07 d4 a1 6e 3b 08 d5 a2 6f 3c 09 d6 a3 70 3d 0a d7 a4 71 3e 0b d8 a5 72 3f 0c d9 a6 73 40 0d da a7 74 41 0e db a8 75 42 0f dc a9 76 43 10 dd aa 77 44 11 de ab 78 45 12 df ac 79 46 13 e0 ad 7a 47 14 e1 ae 7b 48 15 e2 af 7c 49 16 e3 b0 7d 4a 17 e4 b1 7e 4b 18 e5 b2 7f 4c 19 e6 b3 80 4d 1a e7 b4 81 4e 1b e8 b5 82 4f 1c e9 b6 83 50 1d ea b7 84 51 1e eb b8 85 52 1f ec b9 86 53 20 ed ba 87 54 21 ee bb 88 55 22 ef bc 89 56 23 f0 bd 8a 57 24 f1 be 8b 58 25 f2 bf 8c 59 26 f3 c0 8d 5a 27 f4 c1 8e 5b 28 f5 c2 8f 5c 29 f6 c3 90 5d 2a f7 c4 91 5e 2b f8 c5 92 5f 2c f9 c6 93 60 2d fa c7 94 61 2e fb c8 95 62 2f fc c9 96 63 30 fd ca 97 64 31 fe cb 98 65 32 ff cc 99 66 33"

remap_bytes = [int(i, 16) for i in remap1.split(' ')]
remap_shorts = [int(i, 16) for i in remap2.split(' ')]

known_string = "u90\fp0 k0u0\fk0 &amp;a0\f&amp;p\f+0\f9!zk:"
input_str = ""

for char in known_string:
    input_str = input_str + chr(remap_bytes.index(remap_shorts[ord(char)]))

print(input_str)
</code></pre></div></div>

<p>And this gives us:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>th3_s3cr3t3_r3c1p3_1s_23_h0ur5
</code></pre></div></div>

<p>Running this through <code class="language-plaintext highlighter-rouge">verify1</code> as a standalone Java program exits successfully with a zero exit code, verifying that this is the correct string!</p>

<h2 id="verify2">verify2</h2>

<p><code class="language-plaintext highlighter-rouge">verify2</code> follows much of the same story as <code class="language-plaintext highlighter-rouge">verify1</code>, another Java class file is embedded in the binary, and caches are remapped. However, this one will be slightly more tricky.</p>

<p><img src="/images/coffee_verify2.png" alt="verify2" /></p>

<p>The first difference we see is that the <code class="language-plaintext highlighter-rouge">hook_shutdown</code> function is now called with a different replacement function. I have named this <code class="language-plaintext highlighter-rouge">remap_character_set</code> since it appears to remap the <code class="language-plaintext highlighter-rouge">char</code> array to one of 15 different remappings, depending on the exit code received. There also appears to be a global variable modified each time which eventually is returned as the result of <code class="language-plaintext highlighter-rouge">verify2</code>.</p>

<p><img src="/images/coffee_remap_chars.png" alt="remap_chars" /></p>

<p>There is another new function which I have named <code class="language-plaintext highlighter-rouge">invert_booleans</code>, the purpose of which is to swap the <code class="language-plaintext highlighter-rouge">true</code> and <code class="language-plaintext highlighter-rouge">false</code> definitions within the <code class="language-plaintext highlighter-rouge">Boolean</code> class’s fields. This means we will need to take care when reading the Java source for the <code class="language-plaintext highlighter-rouge">verify2</code> class, as any booleans boxed into a <code class="language-plaintext highlighter-rouge">Boolean</code> will be inverted.
This time the second 30-char half of our input string from <code class="language-plaintext highlighter-rouge">argv</code> is passed to the Java <code class="language-plaintext highlighter-rouge">main</code> method.</p>

<p><img src="/images/coffee_invert_bools.png" alt="invert_bools" /></p>

<p>The first part of the <code class="language-plaintext highlighter-rouge">main</code> method is much of the same checks, the <code class="language-plaintext highlighter-rouge">args</code> array must be non-null and of length 1, and the length of our input string must be an even number.
From there it iterates over the input string, splitting it into 2 character chunks, then calling <code class="language-plaintext highlighter-rouge">complexSort(chars, true)</code>. <code class="language-plaintext highlighter-rouge">complexSort</code> boxes the input <code class="language-plaintext highlighter-rouge">String</code> into an array of <code class="language-plaintext highlighter-rouge">Char</code>s, which remaps them onto the mappings set earlier, then if the second boolean argument is <code class="language-plaintext highlighter-rouge">true</code> (or in our inverted case, <code class="language-plaintext highlighter-rouge">false</code>) then the <code class="language-plaintext highlighter-rouge">Char</code>s are sorted by the standard library <code class="language-plaintext highlighter-rouge">Arrays.sort</code> function, combined back into a <code class="language-plaintext highlighter-rouge">String</code> and returned.
<code class="language-plaintext highlighter-rouge">complexSort</code> is called again, this time with a hard-coded string <code class="language-plaintext highlighter-rouge">Cr1KD5mk0_uUzQYifaGVqlN2B3wvpgPtSx6Odo{8hjJLHy9IXb4RnWZ}TAFEsMce7</code> and <code class="language-plaintext highlighter-rouge">false</code>. This means the string will be remapped and <em>will</em> be sorted into its natural ordering.
Both 2-character chunks are then compared to each other. If they match, <code class="language-plaintext highlighter-rouge">System.exit(i+3)</code> is called, this is intercepted by the shutdown hook set earlier and switches the char remapping to the next mapping set.</p>

<p><img src="/images/coffee_verify2_java.png" alt="verify2_java" /></p>

<p>This requires another script to try to reverse -</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mappings = [
		"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 55 43 78 7b 4b 47 69 56 67 41 3a 3b 3c 3d 3e 3f 40 76 52 34 38 79 61 35 54 6f 53 6d 63 4f 49 4e 5f 32 7d 7a 71 50 75 33 42 45 66 5b 5c 5d 5e 30 60 57 48 58 6c 51 65 39 4d 5a 4a 62 64 6e 73 72 74 6b 77 31 44 37 68 36 59 46 70 4c 7c 6a 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
		"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 6b 41 63 31 51 43 72 76 4d 48 3a 3b 3c 3d 3e 3f 40 68 45 56 73 4f 57 70 37 46 55 44 74 42 30 6e 61 5f 62 36 58 6c 65 52 53 4c 34 5b 5c 5d 5e 71 60 4b 54 77 47 49 59 6f 7b 38 4a 67 79 78 6a 7d 7a 35 33 6d 32 64 69 39 75 4e 5a 66 7c 50 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
		"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 6d 35 56 38 34 59 49 71 54 77 3a 3b 3c 3d 3e 3f 40 41 74 58 33 63 57 47 61 4e 6b 76 67 4c 39 44 4a 7b 5f 70 64 37 65 32 30 52 62 5b 5c 5d 5e 6a 60 36 68 69 53 51 73 45 6f 4f 6c 7d 31 48 43 72 66 42 75 50 46 4b 7a 5a 79 55 6e 78 7c 4d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
		"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 68 64 59 52 49 45 51 31 74 34 3a 3b 3c 3d 3e 3f 40 71 47 55 4d 66 35 61 65 6d 43 50 7d 63 67 41 6e 6f 78 58 6a 46 4c 54 77 30 39 5b 5c 5d 5e 62 60 7b 32 57 69 6b 72 36 37 38 70 4e 76 48 4a 5a 56 75 42 44 4f 79 4b 73 53 33 5f 7a 7c 6c 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
		"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 71 33 7b 42 31 61 55 7a 52 6a 3a 3b 3c 3d 3e 3f 40 64 5a 53 6b 58 34 44 79 78 69 4d 6f 76 4f 6c 77 74 54 63 75 68 70 30 41 7d 6d 5b 5c 5d 5e 39 60 48 36 56 32 67 37 45 62 50 51 43 4e 59 72 4a 49 66 4b 35 38 5f 57 47 46 73 6e 4c 7c 65 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
		"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 41 4f 7a 30 6a 67 5a 7b 5f 54 3a 3b 3c 3d 3e 3f 40 47 33 72 69 6b 64 32 6c 62 77 49 57 53 38 66 7d 46 4d 70 4b 4e 76 36 55 65 74 5b 5c 5d 5e 4a 60 45 59 78 31 58 42 43 51 61 39 73 79 6e 52 44 63 4c 37 34 6d 48 50 71 35 6f 68 75 7c 56 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
		"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 55 75 30 32 6e 7d 41 56 34 4c 3a 3b 3c 3d 3e 3f 40 59 68 58 37 36 71 53 39 50 48 6d 7a 5f 6c 4f 51 45 6a 77 31 65 46 38 64 70 74 5b 5c 5d 5e 43 60 4a 76 5a 4d 73 4b 79 6f 57 52 62 33 67 69 35 72 78 44 54 49 4e 61 6b 7b 66 63 47 7c 42 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
		"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 58 6d 45 46 6e 38 4a 4d 36 3a 3b 3c 3d 3e 3f 40 61 63 34 62 59 31 53 6c 55 54 4b 78 7b 5a 73 37 50 70 41 69 39 52 4c 5f 48 67 5b 5c 5d 5e 65 60 56 47 71 6a 32 6b 4e 33 72 42 49 74 44 6f 7d 75 77 57 35 64 7a 79 51 4f 43 68 76 7c 66 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
		"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 31 48 7b 76 70 7d 71 73 6d 6e 3a 3b 3c 3d 3e 3f 40 33 50 45 75 6b 57 56 5a 79 62 7a 4d 30 39 69 52 6f 49 67 72 6c 63 44 58 4a 53 5b 5c 5d 5e 74 60 61 65 37 47 66 51 55 6a 5f 64 34 4c 38 35 68 4e 4f 43 36 42 4b 54 59 46 78 77 41 7c 32 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
		"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 45 4c 6c 70 75 6a 52 76 6d 73 3a 3b 3c 3d 3e 3f 40 48 32 47 54 66 56 7d 50 68 5f 46 39 55 51 78 74 71 42 7a 63 35 4f 61 33 62 34 5b 5c 5d 5e 6e 60 44 57 58 64 43 37 4a 4b 67 31 53 36 30 49 77 6f 72 4d 59 7b 65 38 79 5a 41 6b 4e 7c 69 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
		"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 6c 72 39 4d 74 4e 4f 75 49 68 3a 3b 3c 3d 3e 3f 40 37 35 32 64 7b 59 61 62 48 4c 63 77 36 69 30 44 6a 54 7d 6e 73 79 70 41 71 6f 5b 5c 5d 5e 4b 60 5a 46 33 34 55 42 6b 4a 47 65 5f 67 51 6d 57 53 66 78 52 76 38 56 45 43 50 7a 31 7c 58 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
		"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 66 38 58 61 4d 59 6c 36 45 53 3a 3b 3c 3d 3e 3f 40 39 52 77 33 63 30 32 57 31 41 78 46 43 6d 56 67 47 37 6f 7d 4f 65 75 34 76 69 5b 5c 5d 5e 74 60 5f 6a 42 4c 7b 64 79 68 70 7a 50 49 6e 35 48 5a 4b 6b 44 55 54 4e 73 51 71 72 4a 7c 62 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
		"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 4d 4b 42 79 4f 6c 68 69 63 75 3a 3b 3c 3d 3e 3f 40 56 7a 6d 64 70 6a 62 5f 38 30 4e 55 6f 4c 7b 31 36 53 7d 77 51 59 6b 46 32 43 5b 5c 5d 5e 50 60 61 67 6e 49 33 5a 41 58 4a 54 39 45 78 35 52 44 65 48 76 66 57 47 74 72 73 37 71 7c 34 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
		"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 52 48 67 4b 6a 55 71 54 79 57 3a 3b 3c 3d 3e 3f 40 59 36 6e 4c 53 7b 44 30 63 49 70 46 35 37 6d 7a 75 69 4f 61 42 74 6c 77 6f 7d 5b 5c 5d 5e 31 60 56 72 66 51 65 41 6b 43 47 39 68 33 45 76 4a 58 34 50 5a 64 4d 62 78 73 38 32 4e 7c 5f 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
		"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 79 7d 31 68 36 4d 62 67 32 4b 3a 3b 3c 3d 3e 3f 40 6d 44 47 42 78 51 35 74 72 56 57 4f 65 6b 59 6c 37 45 69 38 6f 4e 7b 4a 48 33 5b 5c 5d 5e 52 60 64 58 53 71 63 49 73 76 43 6a 30 66 5a 70 5f 46 55 6e 54 4c 50 77 34 41 75 61 39 7c 7a 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
]

for i in range(len(mappings)):
    mappings[i] = [chr(int(j, 16)) for j in mappings[i].split(' ')]

current_mapping = 0

ascii_range = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz{}"
input_str = ""
    
for i in range(0, 30, 2):
    chars = ascii_range[i:i+2]
    
    for char in chars:
        input_str += chr(mappings[current_mapping].index(char))
    current_mapping += 1
    
print(input_str)
</code></pre></div></div>

<p>Since we know <code class="language-plaintext highlighter-rouge">complexSort</code> will always sort the compared string into its natural ascii ordering (same string, true passed which is mapped to false so no <code class="language-plaintext highlighter-rouge">sort</code> call) we can sort it ourselves and skip a step, from there we just chunk the string into 2-character pairs and reverse the mapping, resulting with the output of the 2nd half of our flag:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>_str41ght_0f_r34d1ng_J4v4_d0cs
</code></pre></div></div>

<h2 id="success">Success</h2>

<p>From here we can combine the two halves to create the string <code class="language-plaintext highlighter-rouge">th3_s3cr3t3_r3c1p3_1s_23_h0ur5_str41ght_0f_r34d1ng_J4v4_d0cs</code>, which we can feed to the <code class="language-plaintext highlighter-rouge">[REDACTED]</code> option and…</p>

<p><img src="/images/coffee_flag.png" alt="flag" /></p>

<p>Our final flag is output - <code class="language-plaintext highlighter-rouge">HTB{th3_s3cr3t3_r3c1p3_1s_23_h0ur5_str41ght_0f_r34d1ng_J4v4_d0cs}</code> !</p>

<h2 id="conclusions">Conclusions</h2>

<p>This was a super fun challenge to solve after the actual competition and time pressures that come along with it, I got to combine my developing reverse engineering skills with my existing Java knowledge, along with some learning about how JNI works.
It can bend your brain a little thinking about all of the remappings, especially when true becomes false and vice-versa, but some simple scripting can help immensely.</p>]]></content><author><name>Alex Butler</name></author><category term="writeup" /><category term="reverse-engineering" /><category term="pwn" /><summary type="html"><![CDATA[coffee_invocation was one of the reversing challenges for the HTB x UNI 2020 CTF, with its twist being that rather than just a standard C or C++ program, it utilises the Java Native Interface to execute most of the program logic As far as I can tell no team solved this during the event, likely due to perceived time investment for learning about JNI, but it is surprisingly simple once you can wrap your head around some of the obstacles. There were no debugging symbols present on this binary so any function names, apart from the JNI provided ones, have been provided by myself from deducing what they do. main Decompiling main immediately gives away the JNI twist for this challenge, the first function call is to JNI_CreateJavaVM, with some arguments that consist of some unknown numbers and strings. I imported this JNI header definition into Ghidra to define the JNI specific types and allow me to view which fields and functions were being accessed, from here we can make a little more sense of things. After this, the arguments to JNI_CreateJavaVM make a bit more sense. The function arguments are a pointer to a JavaVM struct, a pointer to a JNIEnv struct, and a JavaVMInitArgs struct - The JVMInitArgs don’t tell us much, the struct only takes a version, nOptions and options from which we can determine the Java version is 1.8. The jvm and env pointers are then populated with the respective structs, these are the structs with which the program will interface with the Java process, the JavaVM struct being a function table and an interface to the running VM, providing the ability to attach threads or destroy it. The JNIEnv struct is far more useful in this challenge, providing a function table giving access to call methods, edit fields, and create objects. get_option The next call is to a function I have renamed to get_option, it is a fairly simple function which prints some ASCII art and asks for a selection from a menu, on picking anything but [REDACTED] the Java VM is destroyed and the program terminates. On picking [REDACTED] the function returns back to main Next, main checks argc is greater than 2 (One argument supplied via the command line since argv[0] is the command with which the program was invoked). If there is no argument present a message is printed via the renamed print function print Printing to standard out is usually pretty simple in C, but the challenge authors decided to rewrite this functionality with JNI. Using the JNI definitions and some basic Java knowledge, it’s pretty clear that this function just finds the PrintStream of System.out, then calls println(String) on it, providing the char* passed in the original C function. This print (and later print_str which seems to be identical) function is used for all further printing within the program. get_flag Focussing back on main, if the argc &lt; 2 check does not pass, the next call is to a function I renamed to get_flag, passing the JNIEnv and argv[1] as arguments. This function calls verify1 and verify2, checks if they both return 0 and if so, prints out some ASCII art and gives us the flag. verify1 Here begins the most complex parts of this challenge, verify1 first calls a function I have renamed hook_shutdown, which essentially overrides Java’s static native void halt0(int status) function and replaces it with a function shutdown_hook_param_save, this either saves the status code in a global variable, or if it is already set, compares the status code with the currently stored value and replaces it if it is less than. This will be used later for some program logic. get_remappings / Remapping Type caches get_remappings is a function which takes an integer and depending on that integer, returns a pointer to a different byte array. These arrays all contain values from hex 0x00 to hex 0xFF, but have some variation on their order. For example plus_3D begins at 0x3D and increments at each index, wrapping around to 0x00 after 0xFF. In a few places this challenge will play around with the caches of some of Java’s boxed types such as Byte, Short, Character and Boolean. These caches hold all of the 256 possible values for Byte and a variable number for Character or Short. By overwriting these, any operations performed within the upcoming Java code will use these new mappings, so we must be aware of this going forth. For verify1, Byte and Short are remapped to new byte orders, plus_3D (Hex 00 to FF but offset by +3D) and 00_CD_9A_67_34 (this is the pattern of 5 bytes which are all incremented to form the pattern) respectively. Two compiled Java class files are contained within this binary, get_verify_source selects which one to access and then provides a pointer to it as well as its length in bytes. verify1 accesses the first and makes a JNI call to DefineClass to load the class into the JVM. Then, still using JNI, creates an empty String, a length 2 String[] array of these empty Strings. Our input string which is taken from argv[1] is substringed to length 30, placed in index 0 of the 2-element String[] array, and is then accompanied by a seemingly random String of characters placed in slot 1. The verify1 class now has its main method called via CallStaticVoidMethod with the 2-element String[] as its String[] args argument. Extracting the verify1 source and decompiling it (with some re-arranging of code for readability) we find a fairly simple functionality. Both Strings from the 2-element array are checked to be present, non-null and of the same length. Providing this is true, each character in the String is compared to its corresponding character in the other String and if all match, the main method can exit with status 0, else it will return with a non-zero value depending on which condition was not met. However, remembering that both the Byte and Short caches have been tampered with, we must do some scripting to match values in both arrays to their remappings, and reverse this to find how we can match our input to the remapped second String. remap1 = "3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c" remap2 = "00 cd 9a 67 34 01 ce 9b 68 35 02 cf 9c 69 36 03 d0 9d 6a 37 04 d1 9e 6b 38 05 d2 9f 6c 39 06 d3 a0 6d 3a 07 d4 a1 6e 3b 08 d5 a2 6f 3c 09 d6 a3 70 3d 0a d7 a4 71 3e 0b d8 a5 72 3f 0c d9 a6 73 40 0d da a7 74 41 0e db a8 75 42 0f dc a9 76 43 10 dd aa 77 44 11 de ab 78 45 12 df ac 79 46 13 e0 ad 7a 47 14 e1 ae 7b 48 15 e2 af 7c 49 16 e3 b0 7d 4a 17 e4 b1 7e 4b 18 e5 b2 7f 4c 19 e6 b3 80 4d 1a e7 b4 81 4e 1b e8 b5 82 4f 1c e9 b6 83 50 1d ea b7 84 51 1e eb b8 85 52 1f ec b9 86 53 20 ed ba 87 54 21 ee bb 88 55 22 ef bc 89 56 23 f0 bd 8a 57 24 f1 be 8b 58 25 f2 bf 8c 59 26 f3 c0 8d 5a 27 f4 c1 8e 5b 28 f5 c2 8f 5c 29 f6 c3 90 5d 2a f7 c4 91 5e 2b f8 c5 92 5f 2c f9 c6 93 60 2d fa c7 94 61 2e fb c8 95 62 2f fc c9 96 63 30 fd ca 97 64 31 fe cb 98 65 32 ff cc 99 66 33" remap_bytes = [int(i, 16) for i in remap1.split(' ')] remap_shorts = [int(i, 16) for i in remap2.split(' ')] known_string = "u90\fp0 k0u0\fk0 &amp;a0\f&amp;p\f+0\f9!zk:" input_str = "" for char in known_string: input_str = input_str + chr(remap_bytes.index(remap_shorts[ord(char)])) print(input_str) And this gives us: th3_s3cr3t3_r3c1p3_1s_23_h0ur5 Running this through verify1 as a standalone Java program exits successfully with a zero exit code, verifying that this is the correct string! verify2 verify2 follows much of the same story as verify1, another Java class file is embedded in the binary, and caches are remapped. However, this one will be slightly more tricky. The first difference we see is that the hook_shutdown function is now called with a different replacement function. I have named this remap_character_set since it appears to remap the char array to one of 15 different remappings, depending on the exit code received. There also appears to be a global variable modified each time which eventually is returned as the result of verify2. There is another new function which I have named invert_booleans, the purpose of which is to swap the true and false definitions within the Boolean class’s fields. This means we will need to take care when reading the Java source for the verify2 class, as any booleans boxed into a Boolean will be inverted. This time the second 30-char half of our input string from argv is passed to the Java main method. The first part of the main method is much of the same checks, the args array must be non-null and of length 1, and the length of our input string must be an even number. From there it iterates over the input string, splitting it into 2 character chunks, then calling complexSort(chars, true). complexSort boxes the input String into an array of Chars, which remaps them onto the mappings set earlier, then if the second boolean argument is true (or in our inverted case, false) then the Chars are sorted by the standard library Arrays.sort function, combined back into a String and returned. complexSort is called again, this time with a hard-coded string Cr1KD5mk0_uUzQYifaGVqlN2B3wvpgPtSx6Odo{8hjJLHy9IXb4RnWZ}TAFEsMce7 and false. This means the string will be remapped and will be sorted into its natural ordering. Both 2-character chunks are then compared to each other. If they match, System.exit(i+3) is called, this is intercepted by the shutdown hook set earlier and switches the char remapping to the next mapping set. This requires another script to try to reverse - mappings = [ "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 55 43 78 7b 4b 47 69 56 67 41 3a 3b 3c 3d 3e 3f 40 76 52 34 38 79 61 35 54 6f 53 6d 63 4f 49 4e 5f 32 7d 7a 71 50 75 33 42 45 66 5b 5c 5d 5e 30 60 57 48 58 6c 51 65 39 4d 5a 4a 62 64 6e 73 72 74 6b 77 31 44 37 68 36 59 46 70 4c 7c 6a 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 6b 41 63 31 51 43 72 76 4d 48 3a 3b 3c 3d 3e 3f 40 68 45 56 73 4f 57 70 37 46 55 44 74 42 30 6e 61 5f 62 36 58 6c 65 52 53 4c 34 5b 5c 5d 5e 71 60 4b 54 77 47 49 59 6f 7b 38 4a 67 79 78 6a 7d 7a 35 33 6d 32 64 69 39 75 4e 5a 66 7c 50 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 6d 35 56 38 34 59 49 71 54 77 3a 3b 3c 3d 3e 3f 40 41 74 58 33 63 57 47 61 4e 6b 76 67 4c 39 44 4a 7b 5f 70 64 37 65 32 30 52 62 5b 5c 5d 5e 6a 60 36 68 69 53 51 73 45 6f 4f 6c 7d 31 48 43 72 66 42 75 50 46 4b 7a 5a 79 55 6e 78 7c 4d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 68 64 59 52 49 45 51 31 74 34 3a 3b 3c 3d 3e 3f 40 71 47 55 4d 66 35 61 65 6d 43 50 7d 63 67 41 6e 6f 78 58 6a 46 4c 54 77 30 39 5b 5c 5d 5e 62 60 7b 32 57 69 6b 72 36 37 38 70 4e 76 48 4a 5a 56 75 42 44 4f 79 4b 73 53 33 5f 7a 7c 6c 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 71 33 7b 42 31 61 55 7a 52 6a 3a 3b 3c 3d 3e 3f 40 64 5a 53 6b 58 34 44 79 78 69 4d 6f 76 4f 6c 77 74 54 63 75 68 70 30 41 7d 6d 5b 5c 5d 5e 39 60 48 36 56 32 67 37 45 62 50 51 43 4e 59 72 4a 49 66 4b 35 38 5f 57 47 46 73 6e 4c 7c 65 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 41 4f 7a 30 6a 67 5a 7b 5f 54 3a 3b 3c 3d 3e 3f 40 47 33 72 69 6b 64 32 6c 62 77 49 57 53 38 66 7d 46 4d 70 4b 4e 76 36 55 65 74 5b 5c 5d 5e 4a 60 45 59 78 31 58 42 43 51 61 39 73 79 6e 52 44 63 4c 37 34 6d 48 50 71 35 6f 68 75 7c 56 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 55 75 30 32 6e 7d 41 56 34 4c 3a 3b 3c 3d 3e 3f 40 59 68 58 37 36 71 53 39 50 48 6d 7a 5f 6c 4f 51 45 6a 77 31 65 46 38 64 70 74 5b 5c 5d 5e 43 60 4a 76 5a 4d 73 4b 79 6f 57 52 62 33 67 69 35 72 78 44 54 49 4e 61 6b 7b 66 63 47 7c 42 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 58 6d 45 46 6e 38 4a 4d 36 3a 3b 3c 3d 3e 3f 40 61 63 34 62 59 31 53 6c 55 54 4b 78 7b 5a 73 37 50 70 41 69 39 52 4c 5f 48 67 5b 5c 5d 5e 65 60 56 47 71 6a 32 6b 4e 33 72 42 49 74 44 6f 7d 75 77 57 35 64 7a 79 51 4f 43 68 76 7c 66 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 31 48 7b 76 70 7d 71 73 6d 6e 3a 3b 3c 3d 3e 3f 40 33 50 45 75 6b 57 56 5a 79 62 7a 4d 30 39 69 52 6f 49 67 72 6c 63 44 58 4a 53 5b 5c 5d 5e 74 60 61 65 37 47 66 51 55 6a 5f 64 34 4c 38 35 68 4e 4f 43 36 42 4b 54 59 46 78 77 41 7c 32 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 45 4c 6c 70 75 6a 52 76 6d 73 3a 3b 3c 3d 3e 3f 40 48 32 47 54 66 56 7d 50 68 5f 46 39 55 51 78 74 71 42 7a 63 35 4f 61 33 62 34 5b 5c 5d 5e 6e 60 44 57 58 64 43 37 4a 4b 67 31 53 36 30 49 77 6f 72 4d 59 7b 65 38 79 5a 41 6b 4e 7c 69 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 6c 72 39 4d 74 4e 4f 75 49 68 3a 3b 3c 3d 3e 3f 40 37 35 32 64 7b 59 61 62 48 4c 63 77 36 69 30 44 6a 54 7d 6e 73 79 70 41 71 6f 5b 5c 5d 5e 4b 60 5a 46 33 34 55 42 6b 4a 47 65 5f 67 51 6d 57 53 66 78 52 76 38 56 45 43 50 7a 31 7c 58 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 66 38 58 61 4d 59 6c 36 45 53 3a 3b 3c 3d 3e 3f 40 39 52 77 33 63 30 32 57 31 41 78 46 43 6d 56 67 47 37 6f 7d 4f 65 75 34 76 69 5b 5c 5d 5e 74 60 5f 6a 42 4c 7b 64 79 68 70 7a 50 49 6e 35 48 5a 4b 6b 44 55 54 4e 73 51 71 72 4a 7c 62 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 4d 4b 42 79 4f 6c 68 69 63 75 3a 3b 3c 3d 3e 3f 40 56 7a 6d 64 70 6a 62 5f 38 30 4e 55 6f 4c 7b 31 36 53 7d 77 51 59 6b 46 32 43 5b 5c 5d 5e 50 60 61 67 6e 49 33 5a 41 58 4a 54 39 45 78 35 52 44 65 48 76 66 57 47 74 72 73 37 71 7c 34 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 52 48 67 4b 6a 55 71 54 79 57 3a 3b 3c 3d 3e 3f 40 59 36 6e 4c 53 7b 44 30 63 49 70 46 35 37 6d 7a 75 69 4f 61 42 74 6c 77 6f 7d 5b 5c 5d 5e 31 60 56 72 66 51 65 41 6b 43 47 39 68 33 45 76 4a 58 34 50 5a 64 4d 62 78 73 38 32 4e 7c 5f 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 79 7d 31 68 36 4d 62 67 32 4b 3a 3b 3c 3d 3e 3f 40 6d 44 47 42 78 51 35 74 72 56 57 4f 65 6b 59 6c 37 45 69 38 6f 4e 7b 4a 48 33 5b 5c 5d 5e 52 60 64 58 53 71 63 49 73 76 43 6a 30 66 5a 70 5f 46 55 6e 54 4c 50 77 34 41 75 61 39 7c 7a 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" ] for i in range(len(mappings)): mappings[i] = [chr(int(j, 16)) for j in mappings[i].split(' ')] current_mapping = 0 ascii_range = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz{}" input_str = "" for i in range(0, 30, 2): chars = ascii_range[i:i+2] for char in chars: input_str += chr(mappings[current_mapping].index(char)) current_mapping += 1 print(input_str) Since we know complexSort will always sort the compared string into its natural ascii ordering (same string, true passed which is mapped to false so no sort call) we can sort it ourselves and skip a step, from there we just chunk the string into 2-character pairs and reverse the mapping, resulting with the output of the 2nd half of our flag: _str41ght_0f_r34d1ng_J4v4_d0cs Success From here we can combine the two halves to create the string th3_s3cr3t3_r3c1p3_1s_23_h0ur5_str41ght_0f_r34d1ng_J4v4_d0cs, which we can feed to the [REDACTED] option and… Our final flag is output - HTB{th3_s3cr3t3_r3c1p3_1s_23_h0ur5_str41ght_0f_r34d1ng_J4v4_d0cs} ! Conclusions This was a super fun challenge to solve after the actual competition and time pressures that come along with it, I got to combine my developing reverse engineering skills with my existing Java knowledge, along with some learning about how JNI works. It can bend your brain a little thinking about all of the remappings, especially when true becomes false and vice-versa, but some simple scripting can help immensely.]]></summary></entry><entry><title type="html">Crackthepassword</title><link href="https://mysterypotatoguy.github.io/writeup/crackthepassword" rel="alternate" type="text/html" title="Crackthepassword" /><published>2022-07-15T00:00:00+00:00</published><updated>2022-07-15T00:00:00+00:00</updated><id>https://mysterypotatoguy.github.io/writeup/crackthepassword</id><content type="html" xml:base="https://mysterypotatoguy.github.io/writeup/crackthepassword"><![CDATA[<p>Crack The Password was one of the reverse engineering challenges for Deloitte’s 2022 Hacky Holidays CTF. This was a fairly simple reversing challenge with just some byte manipulation standing between myself and the flag, however, I chose to take a slightly different approach.</p>

<blockquote>
  <p>The AI has taken control of the authentication system and we no longer have access to our important files! Can you help us find a way in by reversing the binary and cracking the password?</p>
</blockquote>

<p>We are given a binary with debugging symbols and upon initial analysis we can see just how simple this challenge should be, in <code class="language-plaintext highlighter-rouge">main</code>, a password is read in from stdin and then passed to the <code class="language-plaintext highlighter-rouge">validatePassword</code> function. From here the return value determines whether “Access granted!” or “Access denied!” is printed.</p>

<p><img src="/images/crackthepassword-main.png" alt="The main function" /></p>

<p>In <code class="language-plaintext highlighter-rouge">validatePassword</code>, we see the password is being checked for a variety of conditions, and we can assume that the flag satisfies all of these checks.</p>

<p><img src="/images/crackthepassword-validatepassword.png" alt="The validatePassword function" /></p>

<p>Instead of reversing each of these manually, or creating a script to invert the checks, I decided to get some practice with a tool that had been discussed within LUHack sessions, angr.</p>

<p>Angr is a tool developed by Shellphish, a team well known for competing in the annual DEFCON CTF. It is at it’s core a program analysis tool, containing modules for disassembly &amp; decompilation, automatic exploit building, ROP chain building, just to name a few. With this challenge we will be leveraging its symbolic execution engine and constraint solving.</p>

<p>With a simple script this challenge can be solved automagically. All we need to do is provide angr an address to try and find a path to, and one to avoid. I chose two instructions that were part of printing the <code class="language-plaintext highlighter-rouge">Access granted/denied!</code> strings.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">angr</span>

<span class="n">FIND_ADDR</span> <span class="o">=</span> <span class="mh">0x401659</span> <span class="c1"># mov dword [esp], str.Congrats_ ; [0x8048654:4]=0x676e6f43 LEA str.Congrats_ ; "Congrats!" @ 0x8048654
</span><span class="n">AVOID_ADDR</span> <span class="o">=</span> <span class="mh">0x40166a</span> <span class="c1"># mov dword [esp], str.Wrong_ ; [0x804865e:4]=0x6e6f7257 LEA str.Wrong_ ; "Wrong!" @ 0x804865e
</span>

<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
	<span class="n">proj</span> <span class="o">=</span> <span class="n">angr</span><span class="p">.</span><span class="n">Project</span><span class="p">(</span><span class="s">'CrackThePassword'</span><span class="p">,</span> <span class="n">load_options</span><span class="o">=</span><span class="p">{</span><span class="s">"auto_load_libs"</span><span class="p">:</span> <span class="bp">False</span><span class="p">})</span>
	<span class="n">sm</span> <span class="o">=</span> <span class="n">proj</span><span class="p">.</span><span class="n">factory</span><span class="p">.</span><span class="n">simulation_manager</span><span class="p">()</span>
	<span class="n">sm</span><span class="p">.</span><span class="n">explore</span><span class="p">(</span><span class="n">find</span><span class="o">=</span><span class="n">FIND_ADDR</span><span class="p">,</span> <span class="n">avoid</span><span class="o">=</span><span class="n">AVOID_ADDR</span><span class="p">)</span>
	<span class="k">return</span> <span class="n">sm</span><span class="p">.</span><span class="n">found</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">posix</span><span class="p">.</span><span class="n">dumps</span><span class="p">(</span><span class="mi">0</span><span class="p">).</span><span class="n">split</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\0</span><span class="s">'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="c1"># stdin
</span>
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span>
	<span class="k">print</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
</code></pre></div></div>

<p>And the flag is given to us!</p>

<p><code class="language-plaintext highlighter-rouge">CTF{7a0QfB8dr1cF293Oy5a9fk9dA01c}</code></p>]]></content><author><name>Mysterypotatoguy</name></author><category term="writeup" /><category term="reverse-engineering" /><category term="angr" /><summary type="html"><![CDATA[Crack The Password was one of the reverse engineering challenges for Deloitte’s 2022 Hacky Holidays CTF. This was a fairly simple reversing challenge with just some byte manipulation standing between myself and the flag, however, I chose to take a slightly different approach. The AI has taken control of the authentication system and we no longer have access to our important files! Can you help us find a way in by reversing the binary and cracking the password? We are given a binary with debugging symbols and upon initial analysis we can see just how simple this challenge should be, in main, a password is read in from stdin and then passed to the validatePassword function. From here the return value determines whether “Access granted!” or “Access denied!” is printed. In validatePassword, we see the password is being checked for a variety of conditions, and we can assume that the flag satisfies all of these checks. Instead of reversing each of these manually, or creating a script to invert the checks, I decided to get some practice with a tool that had been discussed within LUHack sessions, angr. Angr is a tool developed by Shellphish, a team well known for competing in the annual DEFCON CTF. It is at it’s core a program analysis tool, containing modules for disassembly &amp; decompilation, automatic exploit building, ROP chain building, just to name a few. With this challenge we will be leveraging its symbolic execution engine and constraint solving. With a simple script this challenge can be solved automagically. All we need to do is provide angr an address to try and find a path to, and one to avoid. I chose two instructions that were part of printing the Access granted/denied! strings. import angr FIND_ADDR = 0x401659 # mov dword [esp], str.Congrats_ ; [0x8048654:4]=0x676e6f43 LEA str.Congrats_ ; "Congrats!" @ 0x8048654 AVOID_ADDR = 0x40166a # mov dword [esp], str.Wrong_ ; [0x804865e:4]=0x6e6f7257 LEA str.Wrong_ ; "Wrong!" @ 0x804865e def main(): proj = angr.Project('CrackThePassword', load_options={"auto_load_libs": False}) sm = proj.factory.simulation_manager() sm.explore(find=FIND_ADDR, avoid=AVOID_ADDR) return sm.found[0].posix.dumps(0).split(b'\0')[0] # stdin if __name__ == '__main__': print(main()) And the flag is given to us! CTF{7a0QfB8dr1cF293Oy5a9fk9dA01c}]]></summary></entry><entry><title type="html">Kindergarten</title><link href="https://mysterypotatoguy.github.io/writeup/kindergarten" rel="alternate" type="text/html" title="Kindergarten" /><published>2020-12-01T00:00:00+00:00</published><updated>2020-12-01T00:00:00+00:00</updated><id>https://mysterypotatoguy.github.io/writeup/kindergarten</id><content type="html" xml:base="https://mysterypotatoguy.github.io/writeup/kindergarten"><![CDATA[<p>Kindergarten was the first pwn challenge of the HTB x UNI 2020 CTF, and my first real attempt at a pwn challenge.</p>

<p>The challenge is a 64 bit ELF binary which we must exploit to read a flag stored on the server.</p>

<p>Using Ghidra we can decompile the binary and get a rough representation of the original code. The binary is exported with debugging symbols so the original function names are still available.</p>

<hr />
<h2 id="main">main</h2>

<p>Decompiling the <code class="language-plaintext highlighter-rouge">main</code> method, we find a calls to:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">setup</code> - which sets up some time limits on how long the binary can run (in the interest of saving infrastructure resources)</li>
  <li><code class="language-plaintext highlighter-rouge">sec</code> - which will be talked about in a later section</li>
  <li><code class="language-plaintext highlighter-rouge">write</code> which prints out the initial prompt</li>
  <li><code class="language-plaintext highlighter-rouge">read</code> which takes <code class="language-plaintext highlighter-rouge">0x60</code> bytes of input and writes into a buffer labelled <code class="language-plaintext highlighter-rouge">ans</code></li>
  <li><code class="language-plaintext highlighter-rouge">kinder</code>, the next function we will talk about</li>
  <li>a final <code class="language-plaintext highlighter-rouge">write</code> which gives us a nice farewell</li>
</ul>

<p><img src="/images/kindergarten-main.png" alt="main function" /></p>

<p>There is not too much of note here, some initial setup and calls to other functions. However, it should be noted for later that our response to a y/n question is 0x60 or 96 bytes long and is written into the global <code class="language-plaintext highlighter-rouge">ans</code> buffer which is not used again in this function.</p>

<hr />

<h2 id="kinder">kinder</h2>

<p>The <code class="language-plaintext highlighter-rouge">kinder</code> function gives us a bit more to read into, but in reality the structure is fairly simple. We get five questions which allow us to enter 31 characters of text into an appropriately sized buffer, and then a final question which allows us to enter 0x14c or <em>332 characters</em> (!) into a buffer only 24 bytes long.
This is a fairly obvious stack-based overflow in which we should be able to rewrite the RIP (Instruction Pointer register) and redirect the program flow to our own code.</p>

<p><img src="/images/kindergarten-kinder.png" alt="kinder function" /></p>

<hr />

<h2 id="rip-overwrite">RIP overwrite</h2>

<p>I used GDB with the PEDA extension to debug this binary and find ways to exploit it, it’s a fairly useful tool that provides shortcuts for a lot of common binary exploitation methods. 
First off we use PEDA’s <code class="language-plaintext highlighter-rouge">pattern_create</code> to generate a non-repeating pattern of characters we can feed into the buffer overflow and check if and where the return pointer is overwritten. I initially used a pattern length of 150 and then wrote a series of bash commands which would automatically step through each question and eventually input our exploit string to the final question.</p>

<p><img src="/images/kindergarten-pattern.png" alt="Creating a pattern with PEDA" /></p>

<p>The program then crashed with a segfault. PEDA shows us the program state at crash-time, with register values, the offending instruction, stack content and using <code class="language-plaintext highlighter-rouge">backtrace</code>, the function stack trace.
From the register values we can see that the RBP (Base Pointer register) has been overwritten with a string of ASCII, meaning our overflow has been successful. Using PEDA’s <code class="language-plaintext highlighter-rouge">pattern_offset</code> on the ASCII string it will tell us its offset within the previously generated pattern, in this case the RBP is overwritten after 128 bytes.
Using the function stack trace, we see that the function that kinder <em>would</em> have returned to if it had not crashed would have been 0x41416d4141514141 which is definitely not within the bounds of the program. Again using <code class="language-plaintext highlighter-rouge">pattern_offset</code> we find that RIP is overwritten after 136 bytes.
The base pointer is not actually needed to exploit this program but it could have been useful if the challenge was set up differently.</p>

<p><img src="/images/kindergarten-overflow.png" alt="The program segfaults" /></p>

<p>Next, deciding where to redirect program flow to. We have the user-controlled buffer <code class="language-plaintext highlighter-rouge">ans</code> from earlier which is perfect for our needs
Sidenote: There is a function in the binary named <code class="language-plaintext highlighter-rouge">kids_are_not_allowed_here</code> which contained a <code class="language-plaintext highlighter-rouge">CALL</code> instruction on the <code class="language-plaintext highlighter-rouge">ans</code> memory location but this was not needed as we can jump straight to <code class="language-plaintext highlighter-rouge">ans</code> with our buffer overflow.</p>

<p>I wrote a small python script which would generate the required amount of padding and then appended the address of the <code class="language-plaintext highlighter-rouge">ans</code> buffer, 0x602040, accounting for little-endianness</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">sys</span>
<span class="n">IP_OFFSET</span> <span class="o">=</span> <span class="mi">136</span>
<span class="n">buf</span> <span class="o">=</span> <span class="s">"a"</span> <span class="o">*</span> <span class="n">IP_OFFSET</span>
<span class="n">ip</span> <span class="o">=</span> <span class="s">"</span><span class="se">\x40\x20\x60\x00\x00\x00\x00</span><span class="s">"</span>
<span class="n">sys</span><span class="p">.</span><span class="n">stdout</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">buf</span> <span class="o">+</span> <span class="n">ip</span><span class="p">)</span>
<span class="n">sys</span><span class="p">.</span><span class="n">stdout</span><span class="p">.</span><span class="n">flush</span>
</code></pre></div></div>

<p>Testing this leads to another segfault, but this time we segfault on the memory address 0x60204c, which is inside the <code class="language-plaintext highlighter-rouge">ans</code> buffer and demonstrates successful program execution redirection! Onto writing our shellcode…</p>

<p><img src="/images/kindergarten-redirection.png" alt="Successful redirection" /></p>

<hr />

<h2 id="seccomp">seccomp</h2>

<p>But first, back to the <code class="language-plaintext highlighter-rouge">sec</code> function we noticed called in <code class="language-plaintext highlighter-rouge">main</code>.</p>

<p><img src="/images/kindergarten-seccomp.png" alt="sec function" /></p>

<p>To add a little difficulty to this challenge, the authors have added in some <a href="https://en.wikipedia.org/wiki/Seccomp">seccomp</a> rules. seccomp allows the program authors to filter out specific system calls, killing the program if they are detected.</p>

<p>Using seccomp-tools, I dumped the ruleset and it was displayed as a nice bit of pseudocode showing which syscalls were allowed, and which were banned. In our case only the <code class="language-plaintext highlighter-rouge">read</code>, <code class="language-plaintext highlighter-rouge">write</code>, and <code class="language-plaintext highlighter-rouge">open</code> syscalls are allowed, preventing us from popping a shell with <code class="language-plaintext highlighter-rouge">execve</code>. This is not a huge setback though, as will be discussed next.</p>

<p><img src="/images/kindergarten-seccomptools.png" alt="sec function" /></p>

<hr />

<h2 id="writing-shellcode">Writing shellcode</h2>

<p>For our shellcode, we need to write as small of a program as possible (we have 95 bytes to play with) to:</p>
<ul>
  <li>open flag.txt</li>
  <li>read the contents</li>
  <li>write the contents to stdout</li>
</ul>

<p>I used <a href="https://filippo.io/linux-syscall-table/">this linux syscall table</a> to find the correct register values for each syscall.</p>

<p>The RAX register contains a unique number for the syscall we want to perform, it will also contain the result of the syscall after it completes. The next registers used for arguments are, in order: RDI, RSI, RDX, RCX, R8 and R9. We will only need to use up to RDX for this shellcode.</p>

<h3 id="opening-the-file">Opening the file</h3>

<p>Opening the file (<a href="https://linux.die.net/man/3/open">open(3)</a> ) requires a RAX value of 2, then a pointer to the file name in the RDI register, and finally the file mode. To get a pointer to the file name I combine the two 4 byte halves of the flag together, push it to the empty stack and then use the stack pointer (RSP) to point directly to it.</p>

<p>The return value within RAX is the file descriptor number we can use to read the file later.</p>

<h3 id="reading-the-contents">Reading the contents</h3>

<p>Reading the file (<a href="https://linux.die.net/man/2/read">read(2)</a> ) requires a RAX value of 0, the file descriptor number in the RDI register, a pointer to a buffer in which to write the contents in the RSI register, and the length of the content to read in the RDX register. I chose to write the contents to <code class="language-plaintext highlighter-rouge">0x60209f</code> which is the end of the <code class="language-plaintext highlighter-rouge">ans</code> buffer, but since we will have the flag after this shellcode completes, overwriting anything after does not worry me.</p>

<h3 id="writing-the-contents-to-stdout">Writing the contents to stdout</h3>

<p>Our final syscall, writing the contents  (<a href="https://linux.die.net/man/2/write">write(2)</a> ) requires a RAX value of 1, the file descriptor number in the RDI register (stdout is at fd 1), and a pointer to the buffer to write into stdout.</p>

<p>I came up with the following assembly:</p>

<pre><code class="language-x86">mov rax, 0x7478742e;
shl rax, 32;
or rax, 0x67616c66;
push 0;
push rax;
mov rdi, rsp;
mov rax, 2;
xor rsi, rsi;
mov rdx, 600;
syscall;
mov rdi, rax;
xor rax, rax;
mov rsi, 0x60209f;
mov rdx, 22;
syscall;
mov rax, 1;
mov rdi, 1;
mov rsi, 0x60209f;
syscall;
</code></pre>

<p>To convert the assembly to shellcode, I used <a href="https://book.rada.re/tools/rasm2/intro.html">rasm2</a> from radare, along with a python script to convert the produced ascii hex string into a file containing the raw bytes.
This assembly comes out at 87 bytes long which fits perfectly fine within our <code class="language-plaintext highlighter-rouge">ans</code> buffer.</p>

<p><img src="/images/kindergarten-rasm2.png" alt="rasm2" /></p>

<hr />

<h2 id="executing">Executing</h2>

<p>I created a test file containing the phrase <code class="language-plaintext highlighter-rouge">testvalue</code> and ran the full exploit locally…</p>

<p><img src="/images/kindergarten-localoutput.png" alt="Testing locally" /></p>

<p>It worked!</p>

<p>Next to exploit the remote docker instance, incrementing the <code class="language-plaintext highlighter-rouge">count</code> value passed to <code class="language-plaintext highlighter-rouge">read</code> and <code class="language-plaintext highlighter-rouge">write</code> until the full flag was returned</p>

<p><img src="/images/kindergarten-pwn.png" alt="Exploit success!" /></p>

<p>And we are presented with our flag: <code class="language-plaintext highlighter-rouge">HTB{2_c00l_4_$ch0OL!!}</code></p>

<hr />

<h2 id="reflections">Reflections</h2>
<p>Some lessons I took from completing this challenge:</p>

<h1 id="pwnlib">pwnlib</h1>
<p>As this was one of the first pwn challenges I attempted, I was running a lot of the steps manually through slightly complex bash commands. Instead I could have used a library such as pwnlib to automate stepping through the questions and deliver the payload</p>

<h1 id="32-bit-assembly-code">32 bit assembly code</h1>
<p>Even though the binary is 64 bit, I was still writing 32 bit assembly code. Things like pushing <code class="language-plaintext highlighter-rouge">/bin/bash</code> onto the stack could have been shortened significantly</p>

<h1 id="inefficient-assembly">Inefficient assembly</h1>
<p>On the same vein as the last point, there are a few unneccesary instructions, such as the duplicate <code class="language-plaintext highlighter-rouge">mov rsi, 0x60209f</code> before both syscalls.</p>]]></content><author><name>Mysterypotatoguy</name></author><category term="writeup" /><category term="reverse-engineering" /><category term="pwn" /><summary type="html"><![CDATA[Kindergarten was the first pwn challenge of the HTB x UNI 2020 CTF, and my first real attempt at a pwn challenge.]]></summary></entry></feed>